From 2d08140fdbb3aaab9457287b49e877ecf3b8b790 Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Mon, 28 Feb 2000 11:33:39 +0000 Subject: [PATCH] Moved OGL to new locations. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@6327 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- distrib/msw/ogl.rsp | 120 +- docs/latex/ogl/back.gif | Bin 0 -> 225 bytes docs/latex/ogl/books.bmp | Bin 0 -> 1222 bytes docs/latex/ogl/bugs.tex | 11 + docs/latex/ogl/bullet.bmp | Bin 0 -> 138 bytes docs/latex/ogl/changes.tex | 19 + docs/latex/ogl/classes.tex | 2861 ++++++++++++++++++++ docs/latex/ogl/contents.gif | Bin 0 -> 231 bytes docs/latex/ogl/forward.gif | Bin 0 -> 164 bytes docs/latex/ogl/intro.tex | 47 + docs/latex/ogl/ogl.hpj | 17 + docs/latex/ogl/ogl.tex | 46 + docs/latex/ogl/ogledit.bmp | Bin 0 -> 87670 bytes docs/latex/ogl/ogledit.gif | Bin 0 -> 7163 bytes docs/latex/ogl/sample.tex | 87 + docs/latex/ogl/tex2rtf.ini | 35 + docs/latex/ogl/texhelp.sty | 298 +++ docs/latex/ogl/topics.tex | 161 ++ docs/latex/ogl/up.gif | Bin 0 -> 137 bytes include/wx/ogl/basic.h | 744 +++++ include/wx/ogl/basicp.h | 223 ++ include/wx/ogl/bmpshape.h | 53 + include/wx/ogl/canvas.h | 83 + include/wx/ogl/composit.h | 238 ++ include/wx/ogl/constrnt.h | 87 + include/wx/ogl/divided.h | 75 + include/wx/ogl/drawn.h | 227 ++ include/wx/ogl/drawnp.h | 205 ++ include/wx/ogl/lines.h | 296 ++ include/wx/ogl/linesp.h | 89 + include/wx/ogl/mfutils.h | 211 ++ include/wx/ogl/misc.h | 113 + include/wx/ogl/ogl.h | 27 + include/wx/ogl/ogldiag.h | 124 + samples/ogl/ogledit/Makefile | 39 + samples/ogl/ogledit/bitmaps/arrow.bmp | Bin 0 -> 382 bytes samples/ogl/ogledit/bitmaps/arrow.xpm | 44 + samples/ogl/ogledit/bitmaps/tool1.bmp | Bin 0 -> 382 bytes samples/ogl/ogledit/bitmaps/tool1.xpm | 44 + samples/ogl/ogledit/bitmaps/tool2.bmp | Bin 0 -> 382 bytes samples/ogl/ogledit/bitmaps/tool2.xpm | 44 + samples/ogl/ogledit/bitmaps/tool3.bmp | Bin 0 -> 382 bytes samples/ogl/ogledit/bitmaps/tool3.xpm | 44 + samples/ogl/ogledit/bitmaps/tool4.bmp | Bin 0 -> 382 bytes samples/ogl/ogledit/bitmaps/tool4.xpm | 44 + samples/ogl/ogledit/doc.cpp | 611 +++++ samples/ogl/ogledit/doc.h | 182 ++ samples/ogl/ogledit/makefile.b32 | 18 + samples/ogl/ogledit/makefile.bcc | 21 + samples/ogl/ogledit/makefile.dos | 103 + samples/ogl/ogledit/makefile.g95 | 18 + samples/ogl/ogledit/makefile.sc | 33 + samples/ogl/ogledit/makefile.unx | 20 + samples/ogl/ogledit/makefile.vc | 95 + samples/ogl/ogledit/makefile.vms | 44 + samples/ogl/ogledit/makefile.wat | 43 + samples/ogl/ogledit/ogl.ico | Bin 0 -> 766 bytes samples/ogl/ogledit/ogl.xpm | 45 + samples/ogl/ogledit/ogledit.cpp | 213 ++ samples/ogl/ogledit/ogledit.def | 8 + samples/ogl/ogledit/ogledit.h | 77 + samples/ogl/ogledit/ogledit.rc | 10 + samples/ogl/ogledit/palette.cpp | 121 + samples/ogl/ogledit/palette.h | 66 + samples/ogl/ogledit/view.cpp | 337 +++ samples/ogl/ogledit/view.h | 79 + samples/ogl/studio/Makefile | 57 + samples/ogl/studio/cspalette.cpp | 153 ++ samples/ogl/studio/cspalette.h | 57 + samples/ogl/studio/csprint.cpp | 320 +++ samples/ogl/studio/dialogs.cpp | 525 ++++ samples/ogl/studio/dialogs.h | 248 ++ samples/ogl/studio/doc.cpp | 598 +++++ samples/ogl/studio/doc.h | 134 + samples/ogl/studio/mainfrm.cpp | 276 ++ samples/ogl/studio/mainfrm.h | 55 + samples/ogl/studio/makefile.b32 | 19 + samples/ogl/studio/makefile.bcc | 22 + samples/ogl/studio/makefile.g95 | 19 + samples/ogl/studio/makefile.unx | 39 + samples/ogl/studio/makefile.vc | 143 + samples/ogl/studio/manual/alignb.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/alignl.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/alignr.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/alignt.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/arrow.bmp | Bin 0 -> 382 bytes samples/ogl/studio/manual/back.gif | Bin 0 -> 225 bytes samples/ogl/studio/manual/bitmap1.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/bitmap2.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/bullet.bmp | Bin 0 -> 138 bytes samples/ogl/studio/manual/contents.gif | Bin 0 -> 231 bytes samples/ogl/studio/manual/copy.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/copysize.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/cut.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/cutpoint.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/forward.gif | Bin 0 -> 164 bytes samples/ogl/studio/manual/help.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/helpcs.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/horiz.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/linearrow.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/new.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/newpoint.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/open.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/paste.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/pointsize.bmp | Bin 0 -> 538 bytes samples/ogl/studio/manual/preview.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/print.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/redo.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/save.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/straight.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/studio.hpj | 23 + samples/ogl/studio/manual/studio.tex | 381 +++ samples/ogl/studio/manual/tex2rtf.ini | 20 + samples/ogl/studio/manual/texttool.bmp | Bin 0 -> 382 bytes samples/ogl/studio/manual/tick.bmp | Bin 0 -> 220 bytes samples/ogl/studio/manual/toback.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/tofront.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/tool1.bmp | Bin 0 -> 382 bytes samples/ogl/studio/manual/tool2.bmp | Bin 0 -> 382 bytes samples/ogl/studio/manual/tool3.bmp | Bin 0 -> 382 bytes samples/ogl/studio/manual/tool4.bmp | Bin 0 -> 382 bytes samples/ogl/studio/manual/undo.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/up.gif | Bin 0 -> 137 bytes samples/ogl/studio/manual/vert.bmp | Bin 0 -> 238 bytes samples/ogl/studio/manual/zoom.bmp | Bin 0 -> 790 bytes samples/ogl/studio/project.cpp | 89 + samples/ogl/studio/project.h | 42 + samples/ogl/studio/shapes.cpp | 1194 +++++++++ samples/ogl/studio/shapes.h | 268 ++ samples/ogl/studio/studio.cpp | 506 ++++ samples/ogl/studio/studio.h | 171 ++ samples/ogl/studio/studio.ico | Bin 0 -> 766 bytes samples/ogl/studio/studio.rc | 41 + samples/ogl/studio/studio.xpm | 44 + samples/ogl/studio/studio_resources.h | 44 + samples/ogl/studio/studio_resources.wxr | 191 ++ samples/ogl/studio/symbols.cpp | 203 ++ samples/ogl/studio/symbols.h | 76 + samples/ogl/studio/view.cpp | 1039 +++++++ samples/ogl/studio/view.h | 141 + src/ogl/Makefile.in | 13 + src/ogl/basic.cpp | 3274 +++++++++++++++++++++++ src/ogl/basic2.cpp | 1902 +++++++++++++ src/ogl/bmpshape.cpp | 115 + src/ogl/canvas.cpp | 516 ++++ src/ogl/composit.cpp | 1784 ++++++++++++ src/ogl/constrnt.cpp | 619 +++++ src/ogl/divided.cpp | 720 +++++ src/ogl/drawn.cpp | 2489 +++++++++++++++++ src/ogl/lines.cpp | 2515 +++++++++++++++++ src/ogl/makefile.b32 | 18 + src/ogl/makefile.bcc | 21 + src/ogl/makefile.dos | 159 ++ src/ogl/makefile.g95 | 17 + src/ogl/makefile.unx | 42 + src/ogl/makefile.vc | 195 ++ src/ogl/makefile.wat | 26 + src/ogl/mfutils.cpp | 1085 ++++++++ src/ogl/misc.cpp | 894 +++++++ src/ogl/ogldiag.cpp | 756 ++++++ utils/projgen/makeproj.cpp | 27 +- 161 files changed, 33152 insertions(+), 73 deletions(-) create mode 100644 docs/latex/ogl/back.gif create mode 100644 docs/latex/ogl/books.bmp create mode 100644 docs/latex/ogl/bugs.tex create mode 100644 docs/latex/ogl/bullet.bmp create mode 100644 docs/latex/ogl/changes.tex create mode 100644 docs/latex/ogl/classes.tex create mode 100644 docs/latex/ogl/contents.gif create mode 100644 docs/latex/ogl/forward.gif create mode 100644 docs/latex/ogl/intro.tex create mode 100644 docs/latex/ogl/ogl.hpj create mode 100644 docs/latex/ogl/ogl.tex create mode 100644 docs/latex/ogl/ogledit.bmp create mode 100644 docs/latex/ogl/ogledit.gif create mode 100644 docs/latex/ogl/sample.tex create mode 100644 docs/latex/ogl/tex2rtf.ini create mode 100644 docs/latex/ogl/texhelp.sty create mode 100644 docs/latex/ogl/topics.tex create mode 100644 docs/latex/ogl/up.gif create mode 100644 include/wx/ogl/basic.h create mode 100644 include/wx/ogl/basicp.h create mode 100644 include/wx/ogl/bmpshape.h create mode 100644 include/wx/ogl/canvas.h create mode 100644 include/wx/ogl/composit.h create mode 100644 include/wx/ogl/constrnt.h create mode 100644 include/wx/ogl/divided.h create mode 100644 include/wx/ogl/drawn.h create mode 100644 include/wx/ogl/drawnp.h create mode 100644 include/wx/ogl/lines.h create mode 100644 include/wx/ogl/linesp.h create mode 100644 include/wx/ogl/mfutils.h create mode 100644 include/wx/ogl/misc.h create mode 100644 include/wx/ogl/ogl.h create mode 100644 include/wx/ogl/ogldiag.h create mode 100644 samples/ogl/ogledit/Makefile create mode 100644 samples/ogl/ogledit/bitmaps/arrow.bmp create mode 100644 samples/ogl/ogledit/bitmaps/arrow.xpm create mode 100644 samples/ogl/ogledit/bitmaps/tool1.bmp create mode 100644 samples/ogl/ogledit/bitmaps/tool1.xpm create mode 100644 samples/ogl/ogledit/bitmaps/tool2.bmp create mode 100644 samples/ogl/ogledit/bitmaps/tool2.xpm create mode 100644 samples/ogl/ogledit/bitmaps/tool3.bmp create mode 100644 samples/ogl/ogledit/bitmaps/tool3.xpm create mode 100644 samples/ogl/ogledit/bitmaps/tool4.bmp create mode 100644 samples/ogl/ogledit/bitmaps/tool4.xpm create mode 100644 samples/ogl/ogledit/doc.cpp create mode 100644 samples/ogl/ogledit/doc.h create mode 100644 samples/ogl/ogledit/makefile.b32 create mode 100644 samples/ogl/ogledit/makefile.bcc create mode 100644 samples/ogl/ogledit/makefile.dos create mode 100644 samples/ogl/ogledit/makefile.g95 create mode 100644 samples/ogl/ogledit/makefile.sc create mode 100644 samples/ogl/ogledit/makefile.unx create mode 100644 samples/ogl/ogledit/makefile.vc create mode 100644 samples/ogl/ogledit/makefile.vms create mode 100644 samples/ogl/ogledit/makefile.wat create mode 100644 samples/ogl/ogledit/ogl.ico create mode 100644 samples/ogl/ogledit/ogl.xpm create mode 100644 samples/ogl/ogledit/ogledit.cpp create mode 100644 samples/ogl/ogledit/ogledit.def create mode 100644 samples/ogl/ogledit/ogledit.h create mode 100644 samples/ogl/ogledit/ogledit.rc create mode 100644 samples/ogl/ogledit/palette.cpp create mode 100644 samples/ogl/ogledit/palette.h create mode 100644 samples/ogl/ogledit/view.cpp create mode 100644 samples/ogl/ogledit/view.h create mode 100644 samples/ogl/studio/Makefile create mode 100644 samples/ogl/studio/cspalette.cpp create mode 100644 samples/ogl/studio/cspalette.h create mode 100644 samples/ogl/studio/csprint.cpp create mode 100644 samples/ogl/studio/dialogs.cpp create mode 100644 samples/ogl/studio/dialogs.h create mode 100644 samples/ogl/studio/doc.cpp create mode 100644 samples/ogl/studio/doc.h create mode 100644 samples/ogl/studio/mainfrm.cpp create mode 100644 samples/ogl/studio/mainfrm.h create mode 100644 samples/ogl/studio/makefile.b32 create mode 100644 samples/ogl/studio/makefile.bcc create mode 100644 samples/ogl/studio/makefile.g95 create mode 100644 samples/ogl/studio/makefile.unx create mode 100644 samples/ogl/studio/makefile.vc create mode 100644 samples/ogl/studio/manual/alignb.bmp create mode 100644 samples/ogl/studio/manual/alignl.bmp create mode 100644 samples/ogl/studio/manual/alignr.bmp create mode 100644 samples/ogl/studio/manual/alignt.bmp create mode 100644 samples/ogl/studio/manual/arrow.bmp create mode 100644 samples/ogl/studio/manual/back.gif create mode 100644 samples/ogl/studio/manual/bitmap1.bmp create mode 100644 samples/ogl/studio/manual/bitmap2.bmp create mode 100644 samples/ogl/studio/manual/bullet.bmp create mode 100644 samples/ogl/studio/manual/contents.gif create mode 100644 samples/ogl/studio/manual/copy.bmp create mode 100644 samples/ogl/studio/manual/copysize.bmp create mode 100644 samples/ogl/studio/manual/cut.bmp create mode 100644 samples/ogl/studio/manual/cutpoint.bmp create mode 100644 samples/ogl/studio/manual/forward.gif create mode 100644 samples/ogl/studio/manual/help.bmp create mode 100644 samples/ogl/studio/manual/helpcs.bmp create mode 100644 samples/ogl/studio/manual/horiz.bmp create mode 100644 samples/ogl/studio/manual/linearrow.bmp create mode 100644 samples/ogl/studio/manual/new.bmp create mode 100644 samples/ogl/studio/manual/newpoint.bmp create mode 100644 samples/ogl/studio/manual/open.bmp create mode 100644 samples/ogl/studio/manual/paste.bmp create mode 100644 samples/ogl/studio/manual/pointsize.bmp create mode 100644 samples/ogl/studio/manual/preview.bmp create mode 100644 samples/ogl/studio/manual/print.bmp create mode 100644 samples/ogl/studio/manual/redo.bmp create mode 100644 samples/ogl/studio/manual/save.bmp create mode 100644 samples/ogl/studio/manual/straight.bmp create mode 100644 samples/ogl/studio/manual/studio.hpj create mode 100644 samples/ogl/studio/manual/studio.tex create mode 100644 samples/ogl/studio/manual/tex2rtf.ini create mode 100644 samples/ogl/studio/manual/texttool.bmp create mode 100644 samples/ogl/studio/manual/tick.bmp create mode 100644 samples/ogl/studio/manual/toback.bmp create mode 100644 samples/ogl/studio/manual/tofront.bmp create mode 100644 samples/ogl/studio/manual/tool1.bmp create mode 100644 samples/ogl/studio/manual/tool2.bmp create mode 100644 samples/ogl/studio/manual/tool3.bmp create mode 100644 samples/ogl/studio/manual/tool4.bmp create mode 100644 samples/ogl/studio/manual/undo.bmp create mode 100644 samples/ogl/studio/manual/up.gif create mode 100644 samples/ogl/studio/manual/vert.bmp create mode 100644 samples/ogl/studio/manual/zoom.bmp create mode 100644 samples/ogl/studio/project.cpp create mode 100644 samples/ogl/studio/project.h create mode 100644 samples/ogl/studio/shapes.cpp create mode 100644 samples/ogl/studio/shapes.h create mode 100644 samples/ogl/studio/studio.cpp create mode 100644 samples/ogl/studio/studio.h create mode 100644 samples/ogl/studio/studio.ico create mode 100644 samples/ogl/studio/studio.rc create mode 100644 samples/ogl/studio/studio.xpm create mode 100644 samples/ogl/studio/studio_resources.h create mode 100644 samples/ogl/studio/studio_resources.wxr create mode 100644 samples/ogl/studio/symbols.cpp create mode 100644 samples/ogl/studio/symbols.h create mode 100644 samples/ogl/studio/view.cpp create mode 100644 samples/ogl/studio/view.h create mode 100644 src/ogl/Makefile.in create mode 100644 src/ogl/basic.cpp create mode 100644 src/ogl/basic2.cpp create mode 100644 src/ogl/bmpshape.cpp create mode 100644 src/ogl/canvas.cpp create mode 100644 src/ogl/composit.cpp create mode 100644 src/ogl/constrnt.cpp create mode 100644 src/ogl/divided.cpp create mode 100644 src/ogl/drawn.cpp create mode 100644 src/ogl/lines.cpp create mode 100644 src/ogl/makefile.b32 create mode 100644 src/ogl/makefile.bcc create mode 100644 src/ogl/makefile.dos create mode 100644 src/ogl/makefile.g95 create mode 100644 src/ogl/makefile.unx create mode 100644 src/ogl/makefile.vc create mode 100644 src/ogl/makefile.wat create mode 100644 src/ogl/mfutils.cpp create mode 100644 src/ogl/misc.cpp create mode 100644 src/ogl/ogldiag.cpp diff --git a/distrib/msw/ogl.rsp b/distrib/msw/ogl.rsp index de8ca90dfd..b6ef4608c9 100644 --- a/distrib/msw/ogl.rsp +++ b/distrib/msw/ogl.rsp @@ -1,68 +1,68 @@ -utils/ogl/Makefile.in +src/ogl/*.cpp +src/ogl/*.h +src/ogl/*.rc +src/ogl/*.def +src/ogl/*.xbm +src/ogl/*.xpm +src/ogl/make*.* +src/ogl/*.txt +src/ogl/*.ico +src/ogl/*.bmp -utils/ogl/src/*.cpp -utils/ogl/src/*.h -utils/ogl/src/*.rc -utils/ogl/src/*.def -utils/ogl/src/*.xbm -utils/ogl/src/*.xpm -utils/ogl/src/make*.* -utils/ogl/src/*.txt -utils/ogl/src/*.ico -utils/ogl/src/*.bmp +include/wx/ogl/*.h -utils/ogl/samples/ogledit/*.cpp -utils/ogl/samples/ogledit/*.h -utils/ogl/samples/ogledit/*.rc -utils/ogl/samples/ogledit/*.def -utils/ogl/samples/ogledit/*.xbm -utils/ogl/samples/ogledit/make*.* -utils/ogl/samples/ogledit/Makefile -utils/ogl/samples/ogledit/*.txt -utils/ogl/samples/ogledit/*.ico -utils/ogl/samples/ogledit/*.bmp -utils/ogl/samples/ogledit/*.xpm -utils/ogl/samples/ogledit/bitmaps/*.bmp -utils/ogl/samples/ogledit/bitmaps/*.gif -utils/ogl/samples/ogledit/bitmaps/*.xbm -utils/ogl/samples/ogledit/bitmaps/*.xpm +samples/ogl/ogledit/*.cpp +samples/ogl/ogledit/*.h +samples/ogl/ogledit/*.rc +samples/ogl/ogledit/*.def +samples/ogl/ogledit/*.xbm +samples/ogl/ogledit/make*.* +samples/ogl/ogledit/Makefile +samples/ogl/ogledit/*.txt +samples/ogl/ogledit/*.ico +samples/ogl/ogledit/*.bmp +samples/ogl/ogledit/*.xpm +samples/ogl/ogledit/bitmaps/*.bmp +samples/ogl/ogledit/bitmaps/*.gif +samples/ogl/ogledit/bitmaps/*.xbm +samples/ogl/ogledit/bitmaps/*.xpm -utils/ogl/samples/studio/*.cpp -utils/ogl/samples/studio/*.h -utils/ogl/samples/studio/*.rc -utils/ogl/samples/studio/*.def -utils/ogl/samples/studio/*.xbm -utils/ogl/samples/studio/make*.* -utils/ogl/samples/studio/Makefile -utils/ogl/samples/studio/*.txt -utils/ogl/samples/studio/*.ico -utils/ogl/samples/studio/*.bmp -utils/ogl/samples/studio/*.xpm -utils/ogl/samples/studio/*.wxr -utils/ogl/samples/studio/bitmaps/*.bmp -utils/ogl/samples/studio/bitmaps/*.gif -utils/ogl/samples/studio/bitmaps/*.xbm -utils/ogl/samples/studio/bitmaps/*.xpm -utils/ogl/samples/studio/manual/*.tex -utils/ogl/samples/studio/manual/*.ini -utils/ogl/samples/studio/manual/*.gif -utils/ogl/samples/studio/manual/*.bmp -utils/ogl/samples/studio/manual/*.htm -utils/ogl/samples/studio/manual/*.hlp -utils/ogl/samples/studio/manual/*.cnt -utils/ogl/samples/studio/manual/Makefile +samples/ogl/studio/*.cpp +samples/ogl/studio/*.h +samples/ogl/studio/*.rc +samples/ogl/studio/*.def +samples/ogl/studio/*.xbm +samples/ogl/studio/make*.* +samples/ogl/studio/Makefile +samples/ogl/studio/*.txt +samples/ogl/studio/*.ico +samples/ogl/studio/*.bmp +samples/ogl/studio/*.xpm +samples/ogl/studio/*.wxr +samples/ogl/studio/bitmaps/*.bmp +samples/ogl/studio/bitmaps/*.gif +samples/ogl/studio/bitmaps/*.xbm +samples/ogl/studio/bitmaps/*.xpm +samples/ogl/studio/manual/*.tex +samples/ogl/studio/manual/*.ini +samples/ogl/studio/manual/*.gif +samples/ogl/studio/manual/*.bmp +samples/ogl/studio/manual/*.htm +samples/ogl/studio/manual/*.hlp +samples/ogl/studio/manual/*.cnt +samples/ogl/studio/manual/Makefile -utils/ogl/distrib/*.rsp -utils/ogl/distrib/*.bat +distrib/msw/ogl.rsp +distrib/msw/zipogl.bat -utils/ogl/docs/*.txt -utils/ogl/docs/*.tex -utils/ogl/docs/*.ini -utils/ogl/docs/*.hpj -utils/ogl/docs/*.ps -utils/ogl/docs/*.eps -utils/ogl/docs/*.bmp -utils/ogl/docs/*.gif +docs/latex/ogl/*.txt +docs/latex/ogl/*.tex +docs/latex/ogl/*.ini +docs/latex/ogl/*.hpj +docs/latex/ogl/*.ps +docs/latex/ogl/*.eps +docs/latex/ogl/*.bmp +docs/latex/ogl/*.gif docs/html/ogl/*.* docs/winhelp/ogl.hlp diff --git a/docs/latex/ogl/back.gif b/docs/latex/ogl/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>t<(Iwfoo literal 0 HcmV?d00001 diff --git a/docs/latex/ogl/books.bmp b/docs/latex/ogl/books.bmp new file mode 100644 index 0000000000000000000000000000000000000000..cf1e148734c807052ec6359ad2eb1a3e8d43d43d GIT binary patch literal 1222 zcmb7?v2KGf5Qg0-f^PH?BCA8E<{c_a$x@Y}nZr;qXR5NnfE2boQZn^-S4x_%j?%%`Rfz!C$uHnGuoYEAr~D;JxHUzQYZhY(}{X$xY0SE&#JC# z5a%D|9QDv}6Qc3-Wv8+GlQ-*8<`8epNC>=NSLPUH1b$st*H{R=IXD*!fgA8x5Dt6l zUCo=!AsqI8={C$E9QGLr_q_i zFK;h=LxQhf>;v~gWIyoy(Zu$`w=UNZZuYl$t>-8&*n94Z?RTzqLWjlGhdMVK;w1@P zgX#l^|MHTQ1q9k0=J>%Sz9`L#Hix;bEVz#^(qoBse!qj(7b literal 0 HcmV?d00001 diff --git a/docs/latex/ogl/bugs.tex b/docs/latex/ogl/bugs.tex new file mode 100644 index 0000000000..d66f64e613 --- /dev/null +++ b/docs/latex/ogl/bugs.tex @@ -0,0 +1,11 @@ +\chapter{Bugs}\label{bugs}% +\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}% +\setfooter{\thepage}{}{}{}{}{\thepage} + +These are the known bugs. + +\begin{itemize}\itemsep=0pt +\item In the OGLEdit sample, .dia files are output double-spaced +due to an unidentified bug in the way a stream is converted to a file. +\end{itemize} + diff --git a/docs/latex/ogl/bullet.bmp b/docs/latex/ogl/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/docs/latex/ogl/changes.tex b/docs/latex/ogl/changes.tex new file mode 100644 index 0000000000..5590ce3fd9 --- /dev/null +++ b/docs/latex/ogl/changes.tex @@ -0,0 +1,19 @@ +\chapter{Change log} +\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}% +\setfooter{\thepage}{}{}{}{}{\thepage} + +Version 3.0, September 8th 1998 + +\begin{itemize}\itemsep=0pt +\item Version for wxWindows 2.0. +\item Various enhancements especially to wxDrawnShape +(multiple metafiles, for different orientations). +\item More ability to override functions e.g. OnSizeDragLeft, so events can be +intercepted for Do/Undo. +\end{itemize} + +Version 2.0, June 1st 1996 + +\begin{itemize}\itemsep=0pt +\item First publicly released version. +\end{itemize} diff --git a/docs/latex/ogl/classes.tex b/docs/latex/ogl/classes.tex new file mode 100644 index 0000000000..a72adb3887 --- /dev/null +++ b/docs/latex/ogl/classes.tex @@ -0,0 +1,2861 @@ +\chapter{Class reference}\label{classref} +\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}% +\setfooter{\thepage}{}{}{}{}{\thepage} + +These are the main \ogl\ classes. + +\section{\class{wxOGLConstraint}}\label{wxoglconstraint} + +\overview{wxCompositeShape overview}{compositeshapeoverview} + +An wxOGLConstraint object helps specify how child shapes are laid out with respect +to siblings and parents. + +\wxheading{Derived from} + +wxObject + +\wxheading{See also} + +\helpref{wxCompositeShape}{wxcompositeshape} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxOGLConstraint::wxOGLConstraint}\label{wxoglconstraintconstr} + +\func{}{wxOGLConstraint}{\void} + +Default constructor. + +\func{}{wxOGLConstraint}{\param{int}{ type}, \param{wxShape *}{constraining}, \param{wxList\& }{constrained}} + +Constructor. + +\wxheading{Parameters} + +\docparam{constraining}{The shape which is used as the reference for positioning the {\it constrained} objects.} + +\docparam{constrained}{Contains a list of wxShapes which are to be constrained (with respect +to {\it constraining}) using {\it type}.} + +\docparam{type}{Can be one of: + +\begin{itemize}\itemsep=0pt +\item {\bf gyCONSTRAINT\_CENTRED\_VERTICALLY}: the Y co-ordinates of the centres of the +bounding boxes of the constrained objects and the constraining object +will be the same +\item {\bf gyCONSTRAINT\_CENTRED\_HORIZONTALLY}: the X co-ordinates of the centres of the +bounding boxes of the constrained objects and the constraining object +will be the same +\item {\bf gyCONSTRAINT\_CENTRED\_BOTH}: the co-ordinates of the centres of the bounding boxes +of the constrained objects and the constraining object will be the same +\item {\bf gyCONSTRAINT\_LEFT\_OF}: the X co-ordinates of the right hand vertical edges +of the bounding boxes of the constrained objects will be less than +the X co-ordinate of the left hand vertical edge of the bounding box +of the constraining object +\item {\bf gyCONSTRAINT\_RIGHT\_OF}: the X co-ordinates of the left hand vertical edges +of the bounding boxes of the constrained objects will be greater than +the X co-ordinate of the right hand vertical edge of the bounding box +of the constraining object +\item {\bf gyCONSTRAINT\_ABOVE}: the Y co-ordinates of the bottom horizontal edges of the +bounding boxes of the constrained objects will be less than the +Y co-ordinate of the top horizontal edge of the bounding box of the +constraining object +\item {\bf gyCONSTRAINT\_BELOW}: the Y co-ordinates of the top horizontal edges of the +bounding boxes of the constrained objects will be greater than +the X co-ordinate of the bottom horizontal edge of the bounding box +of the constraining object +\item {\bf gyCONSTRAINT\_ALIGNED\_TOP}: the Y co-ordinates of the top horizontal edges of the +bounding boxes of the constrained objects will be the same as the +Y co-ordinate of the top horizontal edge of the bounding box of the +constraining object +\item {\bf gyCONSTRAINT\_ALIGNED\_BOTTOM}: the Y co-ordinates of the bottom horizontal edges +of the bounding boxes of the constrained objects will be the same as +the Y co-ordinate of the bottom horizontal edge of the bounding box +of the constraining object +\item {\bf gyCONSTRAINT\_ALIGNED\_LEFT}: the X co-ordinates of the left hand vertical edges +of the bounding boxes of the constrained objects will be the same as +the X co-ordinate of the left hand vertical edge of the bounding box +of the constraining object +\item {\bf gyCONSTRAINT\_ALIGNED\_RIGHT}: the X co-ordinates of the right hand vertical edges +of the bounding boxes of the constrained objects will be the same as +the X co-ordinate of the right hand vertical edge of the bounding box +of the constraining object +\item {\bf gyCONSTRAINT\_MIDALIGNED\_TOP}: the Y co-ordinates of the centres of +the bounding boxes of the constrained objects will be the same +as the Y co-ordinate of the top horizontal edge of +the bounding box of the constraining object +\item {\bf gyCONSTRAINT\_MIDALIGNED\_BOTTOM}: the Y co-ordinates of the centres of +the bounding boxes of the constrained objects will be the same +as the Y co-ordinate of the bottom horizontal edge of +the bounding box of the constraining object +\item {\bf gyCONSTRAINT\_MIDALIGNED\_LEFT}: the X co-ordinates of the centres of +the bounding boxes of the constrained objects will be the same +as the X co-ordinate of the left hand vertical edge of +the bounding box of the constraining object +\item {\bf gyCONSTRAINT\_MIDALIGNED\_RIGHT}: the X co-ordinates of the centres of +the bounding boxes of the constrained objects will be the same as +the X co-ordinate of the right hand vertical edge of +the bounding box of the constraining object +\end{itemize} +} + +\membersection{wxOGLConstraint::\destruct{wxOGLConstraint}} + +\func{}{\destruct{wxOGLConstraint}}{\void} + +Destructor. + +\membersection{wxOGLConstraint::Equals} + +\func{bool}{Equals}{\param{double}{ x}, \param{double}{ y}} + +Returns TRUE if {\it x} and {\it y} are approximately equal (for the purposes +of evaluating the constraint). + +\membersection{wxOGLConstraint::Evaluate} + +\func{bool}{Evaluate}{\void} + +Evaluates this constraint, returning TRUE if anything changed. + +\membersection{wxOGLConstraint::SetSpacing}\label{wxoglconstraintsetspacing} + +\func{void}{SetSpacing}{\param{double}{ x}, \param{double}{ y}} + +Sets the horizontal and vertical spacing for the constraint. + +\section{\class{wxBitmapShape}}\label{wxbitmapshape} + +Draws a bitmap (non-resizable). + +\wxheading{Derived from} + +\helpref{wxRectangleShape}{wxrectangleshape} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxBitmapShape::wxBitmapShape} + +\func{}{wxBitmapShape}{\void} + +Constructor. + +\membersection{wxBitmapShape::\destruct{wxBitmapShape}} + +\func{}{\destruct{wxBitmapShape}}{\void} + +Destructor. + +\membersection{wxBitmapShape::GetBitmap} + +\constfunc{wxBitmap\&}{GetBitmap}{\void} + +Returns a reference to the bitmap associated with this shape. + +\membersection{wxBitmapShape::GetFilename} + +\constfunc{wxString}{GetFilename}{\void} + +Returns the bitmap filename. + +\membersection{wxBitmapShape::SetBitmap} + +\func{void}{SetBitmap}{\param{const wxBitmap\&}{ bitmap}} + +Sets the bitmap associated with this shape. You can delete the bitmap +from the calling application, since reference counting will take care of +holding on to the internal bitmap data. + +\membersection{wxBitmapShape::SetFilename} + +\func{void}{SetFilename}{\param{const wxString\& }{filename}} + +Sets the bitmap filename. + +\section{\class{wxDiagram}}\label{wxdiagram} + +Encapsulates an entire diagram, with methods for reading/writing and drawing. +A diagram has an associated wxShapeCanvas. + +\wxheading{Derived from} + +wxObject + +\wxheading{See also} + +\helpref{wxShapeCanvas}{wxshapecanvas} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxDiagram::wxDiagram} + +\func{}{wxDiagram}{\void} + +Constructor. + +\membersection{wxDiagram::\destruct{wxDiagram}} + +\func{}{\destruct{wxDiagram}}{\void} + +Destructor. + +\membersection{wxDiagram::AddShape} + +\func{void}{AddShape}{\param{wxShape*}{shape}, \param{wxShape *}{addAfter = NULL}} + +Adds a shape to the diagram. If {\it addAfter} is non-NULL, the shape will be added after this +one. + +\membersection{wxDiagram::Clear} + +\func{void}{Clear}{\param{wxDC\&}{ dc}} + +Clears the specified device context. + +\membersection{wxDiagram::DeleteAllShapes} + +\func{void}{DeletesAllShapes}{\void} + +Removes and deletes all shapes in the diagram. + +\membersection{wxDiagram::DrawOutline} + +\func{void}{DrawOutline}{\param{wxDC\&}{ dc}, \param{double}{ x1}, \param{double}{ y1}, \param{double}{ x2}, \param{double}{ y2}} + +Draws an outline rectangle on the current device context. + +\membersection{wxDiagram::FindShape}\label{wxdiagramfindshape} + +\constfunc{wxShape*}{FindShape}{\param{long}{ id}} + +Returns the shape for the given identifier. + +\membersection{wxDiagram::GetCanvas} + +\constfunc{wxShapeCanvas*}{GetCanvas}{\void} + +Returns the shape canvas associated with this diagram. + +\membersection{wxDiagram::GetCount}\label{wxdiagramgetcount} + +\constfunc{int}{GetCount}{\void} + +Returns the number of shapes in the diagram. + +\membersection{wxDiagram::GetGridSpacing} + +\constfunc{double}{GetGridSpacing}{\void} + +Returns the grid spacing. + +\membersection{wxDiagram::GetMouseTolerance} + +\func{int}{GetMouseTolerance}{\void} + +Returns the tolerance within which a mouse move is ignored. + +\membersection{wxDiagram::GetShapeList} + +\constfunc{wxList*}{GetShapeList}{\void} + +Returns a pointer to the internal shape list. + +\membersection{wxDiagram::GetQuickEditMode} + +\constfunc{bool}{GetQuickEditMode}{\void} + +Returns quick edit mode. + +\membersection{wxDiagram::GetSnapToGrid} + +\constfunc{bool}{GetSnapToGrid}{\void} + +Returns snap-to-grid mode. + +\membersection{wxDiagram::InsertShape} + +\func{void}{InsertShape}{\param{wxShape *}{shape}} + +Inserts a shape at the front of the shape list. + +\membersection{wxDiagram::LoadFile} + +\func{bool}{LoadFile}{\param{const wxString\& }{filename}} + +Loads the diagram from a file. + +\membersection{wxDiagram::OnDatabaseLoad} + +\func{void}{OnDatabaseLoad}{\param{wxExprDatabase\&}{ database}} + +Called just after the nodes and lines have been read from the wxExprDatabase. You may override this; +the default member does nothing. + +\membersection{wxDiagram::OnDatabaseSave} + +\func{void}{OnDatabaseSave}{\param{wxExprDatabase\&}{ database}} + +Called just after the nodes and lines have been written to the wxExprDatabase. You may override this; +the default member does nothing. + +\membersection{wxDiagram::OnHeaderLoad} + +\func{bool}{OnHeaderLoad}{\param{wxExprDatabase\&}{ database}, \param{wxExpr\&}{ expr}} + +Called to allow the `diagram' header object to be read. The default member reads no further information. +You may wish to override this to read version information, author name, etc. + +\membersection{wxDiagram::OnHeaderSave} + +\func{bool}{OnHeaderSave}{\param{wxExprDatabase\&}{ database}, \param{wxExpr\&}{ expr}} + +Called to allow instantiation of the `diagram' header object. The default member writes no further information. +You may wish to override this to include version information, author name, etc. + +\membersection{wxDiagram::OnShapeLoad} + +\func{bool}{OnShapeLoad}{\param{wxExprDatabase\&}{ database}, \param{wxShape\&}{ shape}, \param{wxExpr\&}{ expr}} + +Called to read the shape from the {\it expr}. You may override this, but call this function first. +The default member calls ReadAttributes for the shape. + +\membersection{wxDiagram::OnShapeSave} + +\func{bool}{OnShapeSave}{\param{wxExprDatabase\&}{ database}, \param{wxShape\&}{ shape}, \param{wxExpr\&}{ expr}} + +Called to save the shape to the {\it expr} and {\it database}. You may override this, but call this function first. +The default member calls WriteAttributes for the shape, appends the shape to the database, and of the shape +is a composite, recursively calls OnShapeSave for its children. + +\membersection{wxDiagram::ReadContainerGeometry} + +\func{void}{ReadContainerGeometry}{\param{wxExprDatabase\&}{ database}} + +Reads container geometry from a wxExprDatabase, linking up nodes which +are part of a composite. You probably won't need to redefine this. + +\membersection{wxDiagram::ReadLines} + +\func{void}{ReadLines}{\param{wxExprDatabase\&}{ database}} + +Reads lines from a wxExprDatabase. You probably won't need to redefine this. + +\membersection{wxDiagram::ReadNodes} + +\func{void}{ReadNodes}{\param{wxExprDatabase\&}{ database}} + +Reads nodes from a wxExprDatabase. You probably won't need to redefine this. + +\membersection{wxDiagram::RecentreAll} + +\func{void}{RecentreAll}{\param{wxDC\&}{ dc}} + +Make sure all text that should be centred, is centred. + +\membersection{wxDiagram::Redraw} + +\func{void}{Redraw}{\param{wxDC\&}{ dc}} + +Draws the shapes in the diagram on the specified device context. + +\membersection{wxDiagram::RemoveAllShapes} + +\func{void}{RemoveAllShapes}{\void} + +Removes all shapes from the diagram but does not delete the shapes. + +\membersection{wxDiagram::RemoveShape} + +\func{void}{RemoveShape}{\param{wxShape*}{ shape}} + +Removes the shape from the diagram (non-recursively) but does not delete it. + +\membersection{wxDiagram::SaveFile} + +\func{bool}{SaveFile}{\param{const wxString\& }{filename}} + +Saves the diagram in a file. + +\membersection{wxDiagram::SetCanvas}\label{wxdiagramsetcanvas} + +\func{void}{SetCanvas}{\param{wxShapeCanvas*}{ canvas}} + +Sets the canvas associated with this diagram. + +\membersection{wxDiagram::SetGridSpacing} + +\func{void}{SetGridSpacing}{\param{double}{ spacing}} + +Sets the grid spacing. The default is 5. + +\membersection{wxDiagram::SetMouseTolerance} + +\func{void}{SetMouseTolerance}{\param{int}{ tolerance}} + +Sets the tolerance within which a mouse move is ignored. The default is 3 pixels. + +\membersection{wxDiagram::SetQuickEditMode} + +\func{void}{SetQuickEditMode}{\param{bool}{ mode}} + +Sets quick-edit-mode on or off. In this mode, refreshes are minimized, but the +diagram may need manual refreshing occasionally. + +\membersection{wxDiagram::SetSnapToGrid} + +\func{void}{SetSnapToGrid}{\param{bool}{ snap}} + +Sets snap-to-grid mode on or off. The default is on. + +\membersection{wxDiagram::ShowAll} + +\func{void}{ShowAll}{\param{bool}{ show}} + +Calls Show for each shape in the diagram. + +\membersection{wxDiagram::Snap} + +\func{void}{Snap}{\param{double *}{x}, \param{double *}{y}} + +`Snaps' the coordinate to the nearest grid position, if snap-to-grid is on. + +\section{\class{wxDrawnShape}}\label{wxdrawnshape} + +Draws a pseduo-metafile shape, which can be loaded from a simple Windows metafile. + +wxDrawnShape allows you to specify a different shape for each of four orientations (North, West, +South and East). It also provides a set of drawing functions for programmatic drawing of a shape, +so that during construction of the shape you can draw into it as if it were a device context. + +\wxheading{Derived from} + +\helpref{wxRectangleShape}{wxrectangleshape} + +See also \helpref{wxRectangleShape}{wxrectangleshape}. + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxDrawnShape::wxDrawnShape} + +\func{}{wxDrawnShape}{\void} + +Constructor. + +\membersection{wxDrawnShape::\destruct{wxDrawnShape}} + +\func{}{\destruct{wxDrawnShape}}{\void} + +Destructor. + +\membersection{wxDrawnShape::CalculateSize} + +\func{void}{CalculateSize}{\void} + +Calculates the wxDrawnShape size from the current metafile. Call this after you have drawn +into the shape. + +\membersection{wxDrawnShape::DestroyClippingRect}\label{wxdrawnshapedestroyclippingrect} + +\func{void}{DestroyClippingRect}{\void} + +Destroys the clipping rectangle. See also \helpref{wxDrawnShape::SetClippingRect}{wxdrawnshapesetclippingrect}. + +\membersection{wxDrawnShape::DrawArc}\label{wxdrawnshapedrawarc} + +\func{void}{DrawArc}{\param{const wxPoint\&}{ centrePoint}, \param{const wxPoint\&}{ startPoint}, + \param{const wxPoint\&}{ endPoint}} + +Draws an arc (see wxWindows documentation for details). + +\membersection{wxDrawnShape::DrawAtAngle}\label{wxdrawnshapedrawatangle} + +\func{void}{DrawAtAngle}{\param{int}{ angle}} + +Sets the metafile for the given orientation, which can be one of: + +\begin{itemize}\itemsep=0pt +\item oglDRAWN\_ANGLE\_0 +\item oglDRAWN\_ANGLE\_90 +\item oglDRAWN\_ANGLE\_180 +\item oglDRAWN\_ANGLE\_270 +\end{itemize} + +See also \helpref{wxDrawnShape::GetAngle}{wxdrawnshapegetangle}. + +\membersection{wxDrawnShape::DrawEllipticArc}\label{wxdrawnshapedrawellipticarc} + +\func{void}{DrawEllipticArc}{\param{const wxRect\&}{ rect}, \param{double}{ startAngle}, \param{double}{ endAngle}} + +Draws an elliptic arc (see wxWindows documentation for details). + +\membersection{wxDrawnShape::DrawLine}\label{wxdrawnshapedrawline} + +\func{void}{DrawLine}{\param{const wxPoint\&}{ point1}, \param{const wxPoint\&}{ point2}} + +Draws a line from {\it point1} to {\it point2}. + +\membersection{wxDrawnShape::DrawLines}\label{wxdrawnshapedrawlines} + +\func{void}{DrawLines}{\param{int}{ n}, \param{wxPoint\&}{ points[]}} + +Draws {\it n} lines. + +\membersection{wxDrawnShape::DrawPoint}\label{wxdrawnshapedrawpoint} + +\func{void}{DrawPoint}{\param{const wxPoint\&}{ point}} + +Draws a point. + +\membersection{wxDrawnShape::DrawPolygon}\label{wxdrawnshapedrawpolygon} + +\func{void}{DrawPolygon}{\param{int}{ n}, \param{wxPoint\&}{ points[]}, \param{int}{ flags = 0}} + +Draws a polygon. {\it flags} can be one or more of {\bf oglMETAFLAGS\_OUTLINE} (use this polygon for the drag outline) +and {\bf oglMETAFLAGS\_ATTACHMENTS} (use the vertices of this polygon for attachments). + +\membersection{wxDrawnShape::DrawRectangle}\label{wxdrawnshapedrawrectangle} + +\func{void}{DrawRectangle}{\param{const wxRect\&}{ rect}} + +Draws a rectangle. + +\membersection{wxDrawnShape::DrawRoundedRectangle}\label{wxdrawnshapedrawroundedrectangle} + +\func{void}{DrawRoundedRectangle}{\param{const wxRect\&}{ rect}, \param{double}{ radius}} + +Draws a rounded rectangle. {\it radius} is the corner radius. If {\it radius} is negative, +it expresses the radius as a proportion of the smallest dimension of the rectangle. + +\membersection{wxDrawnShape::DrawSpline}\label{wxdrawnshapedrawspline} + +\func{void}{DrawSpline}{\param{int}{ n}, \param{wxPoint\&}{ points[]}} + +Draws a spline curve. + +\membersection{wxDrawnShape::DrawText}\label{wxdrawnshapedrawtext} + +\func{void}{DrawText}{\param{const wxString\&}{ text}, \param{const wxPoint\&}{ point}} + +Draws text at the given point. + +\membersection{wxDrawnShape::GetAngle}\label{wxdrawnshapegetangle} + +\constfunc{int}{GetAngle}{\void} + +Returns the current orientation, which can be one of: + +\begin{itemize}\itemsep=0pt +\item oglDRAWN\_ANGLE\_0 +\item oglDRAWN\_ANGLE\_90 +\item oglDRAWN\_ANGLE\_180 +\item oglDRAWN\_ANGLE\_270 +\end{itemize} + +See also \helpref{wxDrawnShape::DrawAtAngle}{wxdrawnshapedrawatangle}. + +\membersection{wxDrawnShape::GetMetaFile} + +\constfunc{wxPseudoMetaFile\& }{GetMetaFile}{\void} + +Returns a reference to the internal `pseudo-metafile'. + +\membersection{wxDrawnShape::GetRotation}\label{wxdrawnshapegetrotation} + +\constfunc{double}{GetRotation}{\void} + +Returns the current rotation of the shape in radians. + +\membersection{wxDrawnShape::LoadFromMetaFile} + +\func{bool}{LoadFromMetaFile}{\param{const wxString\& }{filename}} + +Loads a (very simple) Windows metafile, created for example by Top Draw, the Windows shareware graphics package. + +\membersection{wxDrawnShape::Rotate} + +\func{void}{Rotate}{\param{double }{x}, \param{double }{y}, \param{double }{theta}} + +Rotate about the given axis by the given amount in radians. + +\membersection{wxDrawnShape::SetClippingRect}\label{wxdrawnshapesetclippingrect} + +\func{void}{SetClippingRect}{\param{const wxRect\&}{ rect}} + +Sets the clipping rectangle. See also \helpref{wxDrawnShape::DestroyClippingRect}{wxdrawnshapedestroyclippingrect}. + +\membersection{wxDrawnShape::SetDrawnBackgroundColour}\label{wxdrawnshapesetdrawnbackgroundcolour} + +\func{void}{SetDrawnBackgroundColour}{\param{const wxColour\&}{ colour}} + +Sets the current background colour for the current metafile. + +\membersection{wxDrawnShape::SetDrawnBackgroundMode}\label{wxdrawnshapesetdrawnbackgroundmode} + +\func{void}{SetDrawnBackgroundMode}{\param{int}{ mode}} + +Sets the current background mode for the current metafile. + +\membersection{wxDrawnShape::SetDrawnBrush}\label{wxdrawnshapesetdrawnbrush} + +\func{void}{SetDrawnBrush}{\param{wxPen*}{ pen}, \param{bool}{ isOutline = FALSE}} + +Sets the pen for this metafile. If {\it isOutline} is TRUE, this pen is taken to indicate the outline +(and if the outline pen is changed for the whole shape, the pen will be replaced with the outline pen). + +\membersection{wxDrawnShape::SetDrawnFont}\label{wxdrawnshapesetdrawnfont} + +\func{void}{SetDrawnFont}{\param{wxFont*}{ font}} + +Sets the current font for the current metafile. + +\membersection{wxDrawnShape::SetDrawnPen}\label{wxdrawnshapesetdrawnpen} + +\func{void}{SetDrawnPen}{\param{wxPen*}{ pen}, \param{bool}{ isOutline = FALSE}} + +Sets the pen for this metafile. If {\it isOutline} is TRUE, this pen is taken to indicate the outline +(and if the outline pen is changed for the whole shape, the pen will be replaced with the outline pen). + +\membersection{wxDrawnShape::SetDrawnTextColour}\label{wxdrawnshapesetdrawntextcolour} + +\func{void}{SetDrawnTextColour}{\param{const wxColour\&}{ colour}} + +Sets the current text colour for the current metafile. + +\membersection{wxDrawnShape::Scale} + +\func{void}{Scale}{\param{double }{sx}, \param{double }{sy}} + +Scales the shape by the given amount. + +\membersection{wxDrawnShape::SetSaveToFile} + +\func{void}{SetSaveToFile}{\param{bool }{save}} + +If {\it save} is TRUE, the image will be saved along with the shape's other attributes. The reason +why this might not be desirable is that if there are many shapes with the same image, it would be +more efficient for the application to save one copy, and not duplicate the information for every +shape. The default is TRUE. + +\membersection{wxDrawnShape::Translate} + +\func{void}{Translate}{\param{double }{x}, \param{double }{y}} + +Translates the shape by the given amount. + +\section{\class{wxCircleShape}}\label{wxcircleshape} + +An wxEllipseShape whose width and height are the same. + +\wxheading{Derived from} + +\helpref{wxEllipseShape}{wxellipseshape}. + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxCircleShape::wxCircleShape} + +\func{}{wxCircleShape}{\param{double}{ width = 0.0}} + +Constructor. + +\membersection{wxCircleShape::\destruct{wxCircleShape}} + +\func{}{\destruct{wxCircleShape}}{\void} + +Destructor. + +\section{\class{wxCompositeShape}}\label{wxcompositeshape} + +This is an object with a list of child objects, and a list of size +and positioning constraints between the children. + +\wxheading{Derived from} + +\helpref{wxRectangleShape}{wxrectangleshape} + +\wxheading{See also} + +\helpref{wxCompositeShape overview}{compositeshapeoverview} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxCompositeShape::wxCompositeShape} + +\func{}{wxCompositeShape}{\void} + +Constructor. + +\membersection{wxCompositeShape::\destruct{wxCompositeShape}} + +\func{}{\destruct{wxCompositeShape}}{\void} + +Destructor. + +\membersection{wxCompositeShape::AddChild}\label{wxcompositeshapeaddchild} + +\func{void}{AddChild}{\param{wxShape *}{child}, \param{wxShape *}{addAfter = NULL}} + +Adds a child shape to the composite. If {\it addAfter} is non-NULL, the shape will be added +after this shape. + +\membersection{wxCompositeShape::AddConstraint}\label{wxcompositeshapeaddconstraint} + +\func{wxOGLConstraint *}{AddConstraint}{\param{wxOGLConstraint *}{constraint}} + +\func{wxOGLConstraint *}{AddConstraint}{\param{int}{ type}, \param{wxShape *}{constraining}, \param{wxList\&}{constrained}} + +\func{wxOGLConstraint *}{AddConstraint}{\param{int}{ type}, \param{wxShape *}{constraining}, \param{wxShape *}{constrained}} + +Adds a constraint to the composite. + +\membersection{wxCompositeShape::CalculateSize} + +\func{void}{CalculateSize}{\void} + +Calculates the size and position of the composite based on child sizes and positions. + +\membersection{wxCompositeShape::ContainsDivision} + +\func{bool}{FindContainerImage}{\param{wxDivisionShape *}{division}} + +Returns TRUE if {\it division} is a descendant of this container. + +\membersection{wxCompositeShape::DeleteConstraint} + +\func{void}{DeleteConstraint}{\param{wxOGLConstraint *}{constraint}} + +Deletes constraint from composite. + +\membersection{wxCompositeShape::DeleteConstraintsInvolvingChild} + +\func{void}{DeleteConstraintsInvolvingChild}{\param{wxShape *}{child}} + +This function deletes constraints which mention the given child. Used when +deleting a child from the composite. + +\membersection{wxCompositeShape::FindConstraint} + +\func{wxOGLConstraint *}{FindConstraint}{\param{long}{ id}, \param{wxCompositeShape **}{actualComposite}} + +Finds the constraint with the given id, also returning the actual composite the constraint was in, +in case that composite was a descendant of this composite. + +\membersection{wxCompositeShape::FindContainerImage} + +\func{wxShape *}{FindContainerImage}{\void} + +Finds the image used to visualize a container. This is any child +of the composite that is not in the divisions list. + +\membersection{wxCompositeShape::GetConstraints} + +\constfunc{wxList\&}{GetConstraints}{\void} + +Returns a reference to the list of constraints. + +\membersection{wxCompositeShape::GetDivisions} + +\constfunc{wxList\&}{GetDivisions}{\void} + +Returns a reference to the list of divisions. + +\membersection{wxCompositeShape::MakeContainer}\label{wxcompositeshapemakecontainer} + +\func{void}{MakeContainer}{\void} + +Makes this composite into a container by creating one child wxDivisionShape. + +\membersection{wxCompositeShape::OnCreateDivision} + +\func{wxDivisionShape *}{OnCreateDivision}{\void} + +Called when a new division shape is required. Can be overriden to allow an application +to use a different class of division. + +\membersection{wxCompositeShape::Recompute}\label{wxcompositeshaperecompute} + +\func{bool}{Recompute}{\void} + +Recomputes any constraints associated with the object. If FALSE is returned, +the constraints could not be satisfied (there was an inconsistency). + +\membersection{wxCompositeShape::RemoveChild} + +\func{void}{RemoveChild}{\param{wxShape *}{child}} + +Removes the child from the composite and any constraint relationships, but does not +delete the child. + +\section{\class{wxDividedShape}}\label{wxdividedshape} + +A wxDividedShape is a rectangle with a number of vertical divisions. Each +division may have its text formatted with independent characteristics, and +the size of each division relative to the whole image may be specified. + +\wxheading{Derived from} + +\helpref{wxRectangleShape}{wxrectangleshape} + +\wxheading{See also} + +\helpref{wxDividedShape overview}{dividedshapeoverview} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxDividedShape::wxDividedShape} + +\func{}{wxDividedShape}{\param{double}{ width = 0.0}, \param{double}{ height = 0.0}} + +Constructor. + +\membersection{wxDividedShape::\destruct{wxDividedShape}} + +\func{}{\destruct{wxDividedShape}}{\void} + +Destructor. + +\membersection{wxDividedShape::EditRegions} + +\func{void}{EditRegions}{\void} + +Edit the region colours and styles. + +\membersection{wxDividedShape::SetRegionSizes} + +\func{void}{SetRegionSizes}{\void} + +Set all region sizes according to proportions and +this object total size. + +\section{\class{wxDivisionShape}}\label{wxdivisionshape} + +A division shape is like a composite in that it can contain further objects, but is used exclusively to +divide another shape into regions, or divisions. A wxDivisionShape is never free-standing. + +\wxheading{Derived from} + +\helpref{wxCompositeShape}{wxcompositeshape} + +\wxheading{See also} + +\helpref{wxCompositeShape overview}{compositeshapeoverview} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxDivisionShape::wxDivisionShape} + +\func{}{wxDivisionShape}{\void} + +Constructor. + +\membersection{wxDivisionShape::\destruct{wxDivisionShape}} + +\func{}{\destruct{wxDivisionShape}}{\void} + +Destructor. + +\membersection{wxDivisionShape::AdjustBottom} + +\func{void}{AdjustBottom}{\param{double}{ bottom}, \param{bool}{ test}} + +Adjust a side, returning FALSE if it's not physically possible to adjust it to this point. + +\membersection{wxDivisionShape::AdjustLeft} + +\func{void}{AdjustLeft}{\param{double}{ left}, \param{bool}{ test}} + +Adjust a side, returning FALSE if it's not physically possible to adjust it to this point. + +\membersection{wxDivisionShape::AdjustRight} + +\func{void}{AdjustRight}{\param{double}{ right}, \param{bool}{ test}} + +Adjust a side, returning FALSE if it's not physically possible to adjust it to this point. + +\membersection{wxDivisionShape::AdjustTop} + +\func{void}{AdjustTop}{\param{double}{ top}, \param{bool}{ test}} + +Adjust a side, returning FALSE if it's not physically possible to adjust it to this point. + +\membersection{wxDivisionShape::Divide}\label{wxdivisionshapedivide} + +\func{void}{Divide}{\param{int}{ direction}} + +Divide this division into two further divisions, horizontally ({\it direction} is wxHORIZONTAL) or +vertically ({\it direction} is wxVERTICAL). + +\membersection{wxDivisionShape::EditEdge} + +\func{void}{EditEdge}{\param{int}{ side}} + +Interactively edit style of left or top side. + +\membersection{wxDivisionShape::GetBottomSide} + +\func{wxDivisionShape *}{GetBottomSide}{\void} + +Returns a pointer to the division on the bottom side of this division. + +\membersection{wxDivisionShape::GetHandleSide} + +\func{int}{GetHandleSide}{\void} + +Returns the side which the handle appears on (DIVISION\_SIDE\_LEFT or DIVISION\_SIDE\_TOP). + +\membersection{wxDivisionShape::GetLeftSide} + +\func{wxDivisionShape *}{GetLeftSide}{\void} + +Returns a pointer to the division on the left side of this division. + +\membersection{wxDivisionShape::GetLeftSideColour} + +\func{wxString}{GetLeftSideColour}{\void} + +Returns a pointer to the colour used for drawing the left side of the division. + +\membersection{wxDivisionShape::GetLeftSidePen} + +\func{wxPen *}{GetLeftSidePen}{\void} + +Returns a pointer to the pen used for drawing the left side of the division. + +\membersection{wxDivisionShape::GetRightSide} + +\func{wxDivisionShape *}{GetRightSide}{\void} + +Returns a pointer to the division on the right side of this division. + +\membersection{wxDivisionShape::GetTopSide} + +\func{wxDivisionShape *}{GetTopSide}{\void} + +Returns a pointer to the division on the top side of this division. + +\membersection{wxDivisionShape::GetTopSideColour} + +\func{wxString}{GetTopSideColour}{\void} + +Returns a pointer to the colour used for drawing the top side of the division. + +\membersection{wxDivisionShape::GetTopSidePen} + +\func{wxPen *}{GetTopSidePen}{\void} + +Returns a pointer to the pen used for drawing the left side of the division. + +\membersection{wxDivisionShape::ResizeAdjoining} + +\func{void}{ResizeAdjoining}{\param{int}{ side}, \param{double}{ newPos}, \param{bool}{ test}} + +Resize adjoining divisions at the given side. If {\it test} is TRUE, +just see whether it's possible for each adjoining region, +returning FALSE if it's not. + +{\it side} can be one of: + +\begin{itemize}\itemsep=0pt +\item DIVISION\_SIDE\_NONE +\item DIVISION\_SIDE\_LEFT +\item DIVISION\_SIDE\_TOP +\item DIVISION\_SIDE\_RIGHT +\item DIVISION\_SIDE\_BOTTOM +\end{itemize} + +\membersection{wxDivisionShape::PopupMenu} + +\func{void}{PopupMenu}{\param{double}{ x}, \param{double}{ y}} + +Popup the division menu. + +\membersection{wxDivisionShape::SetBottomSide} + +\func{void}{SetBottomSide}{\param{wxDivisionShape *}{shape}} + +Set the pointer to the division on the bottom side of this division. + +\membersection{wxDivisionShape::SetHandleSide} + +\func{int}{SetHandleSide}{\void} + +Sets the side which the handle appears on (DIVISION\_SIDE\_LEFT or DIVISION\_SIDE\_TOP). + +\membersection{wxDivisionShape::SetLeftSide} + +\func{void}{SetLeftSide}{\param{wxDivisionShape *}{shape}} + +Set the pointer to the division on the left side of this division. + +\membersection{wxDivisionShape::SetLeftSideColour} + +\func{void}{SetLeftSideColour}{\param{const wxString\& }{colour}} + +Sets the colour for drawing the left side of the division. + +\membersection{wxDivisionShape::SetLeftSidePen} + +\func{void}{SetLeftSidePen}{\param{wxPen *}{pen}} + +Sets the pen for drawing the left side of the division. + +\membersection{wxDivisionShape::SetRightSide} + +\func{void}{SetRightSide}{\param{wxDivisionShape *}{shape}} + +Set the pointer to the division on the right side of this division. + +\membersection{wxDivisionShape::SetTopSide} + +\func{void}{SetTopSide}{\param{wxDivisionShape *}{shape}} + +Set the pointer to the division on the top side of this division. + +\membersection{wxDivisionShape::SetTopSideColour} + +\func{void}{SetTopSideColour}{\param{const wxString\& }{colour}} + +Sets the colour for drawing the top side of the division. + +\membersection{wxDivisionShape::SetTopSidePen} + +\func{void}{SetTopSidePen}{\param{wxPen *}{pen}} + +Sets the pen for drawing the top side of the division. + +\section{\class{wxEllipseShape}}\label{wxellipseshape} + +The wxEllipseShape behaves similarly to the wxRectangleShape but is +elliptical. + +\wxheading{Derived from} + +\helpref{wxShape}{wxshape} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxEllipseShape::wxEllipseShape} + +\func{}{wxEllipseShape}{\param{double}{ width = 0.0}, \param{double}{ height = 0.0}} + +Constructor. + +\membersection{wxEllipseShape::\destruct{wxEllipseShape}} + +\func{}{\destruct{wxEllipseShape}}{\void} + +Destructor. + +\section{\class{wxLineShape}}\label{wxlineshape} + +A wxLineShape may be attached to two nodes; it may be segmented, in which +case a control point is drawn for each joint. + +A wxLineShape may have arrows at the beginning, end and centre. + +\wxheading{Derived from} + +\helpref{wxShape}{wxshape} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxLineShape::wxLineShape} + +\func{}{wxLineShape}{\void} + +Constructor. + +Usually you will call \helpref{wxLineShape::MakeLineControlPoints}{wxlineshapemakelinecontrolpoints} to +specify the number of segments in the line. + +\membersection{wxLineShape::\destruct{wxLineShape}} + +\func{}{\destruct{wxLineShape}}{\void} + +Destructor. + +\membersection{wxLineShape::AddArrow}\label{wxlineshapeaddarrow} + +\func{void}{AddArrow}{\param{WXTYPE}{ type}, \param{bool}{ end = ARROW\_POSITION\_END}, \param{double}{ arrowSize = 10.0}, + \param{double}{ xOffset = 0.0}, \param{const wxString\& }{name = ""}, \param{wxPseudoMetaFile *}{mf = NULL}, \param{long}{ arrowId = -1}} + +Adds an arrow (or annotation) to the line. + +{\it type} may currently be one of: + +\begin{description}\itemsep=0pt +\item[ARROW\_HOLLOW\_CIRCLE] Hollow circle. +\item[ARROW\_FILLED\_CIRCLE] Filled circle. +\item[ARROW\_ARROW] Conventional arrowhead. +\item[ARROW\_SINGLE\_OBLIQUE] Single oblique stroke. +\item[ARROW\_DOUBLE\_OBLIQUE] Double oblique stroke. +\item[ARROW\_DOUBLE\_METAFILE] Custom arrowhead. +\end{description} + +{\it end} may currently be one of: + +\begin{description}\itemsep=0pt +\item[ARROW\_POSITION\_END] Arrow appears at the end. +\item[ARROW\_POSITION\_START] Arrow appears at the start. +\end{description} + +{\it arrowSize} specifies the length of the arrow. + +{\it xOffset} specifies the offset from the end of the line. + +{\it name} specifies a name for the arrow. + +{\it mf} can be a wxPseduoMetaFile, perhaps loaded from a simple Windows metafile. + +{\it arrowId} is the id for the arrow. + +\membersection{wxLineShape::AddArrowOrdered} + +\func{void}{AddArrowOrdered}{\param{wxArrowHead *}{arrow}, \param{wxList\&}{ referenceList}, \param{int}{ end}} + +Add an arrowhead in the position indicated by the reference +list of arrowheads, which contains all legal arrowheads for this +line, in the correct order. +E.g. + +\begin{verbatim} + Reference list: a b c d e + Current line list: a d +\end{verbatim} + +Add c, then line list is: a c d. + +If no legal arrowhead position, return FALSE. Assume reference list is +for one end only, since it potentially defines the ordering for any one +of the 3 positions. So we don't check the reference list for arrowhead +position. + +\membersection{wxLineShape::ClearArrow} + +\func{bool}{ClearArrow}{\param{const wxString\& }{name}} + +Delete the arrow with the given name. + +\membersection{wxLineShape::ClearArrowsAtPosition} + +\func{void}{ClearArrowsAtPosition}{\param{int}{ position = -1}} + +Delete the arrows at the specified position, or at any position if {\it position} is -1. + +\membersection{wxLineShape::DrawArrow} + +\func{void}{DrawArrow}{\param{ArrowHead *}{arrow}, \param{double}{ xOffset}, \param{bool}{ proportionalOffset}} + +Draws the given arrowhead (or annotation). + +\membersection{wxLineShape::DeleteArrowHead} + +\func{bool}{DeleteArrowHead}{\param{long}{ arrowId}} + +\func{bool}{DeleteArrowHead}{\param{int}{ position}, \param{const wxString\& }{name}} + +Delete arrowhead by id or position and name. + +\membersection{wxLineShape::DeleteLineControlPoint} + +\func{bool}{DeleteLineControlPoint}{\void} + +Deletes an arbitary point on the line. + +\membersection{wxLineShape::DrawArrows} + +\func{void}{DrawArrows}{\param{wxDC\&}{ dc}} + +Draws all arrows. + +\membersection{wxLineShape::DrawRegion} + +\func{void}{DrawRegion}{\param{wxDC\&}{ dc}, \param{wxShapeRegion *}{region}, \param{double}{ x}, \param{double}{ y}} + +Format one region at this position. + +\membersection{wxLineShape::EraseRegion} + +\func{void}{EraseRegion}{\param{wxDC\&}{ dc}, \param{wxShapeRegion *}{region}, \param{double}{ x}, \param{double}{ y}} + +Format one region at this position. + +\membersection{wxLineShape::FindArrowHead} + +\func{wxArrowHead *}{FindArrowHead}{\param{long}{ arrowId}} + +\func{wxArrowHead *}{FindArrowHead}{\param{int}{ position}, \param{const wxString\& }{name}} + +Find arrowhead by id or position and name. + +\membersection{wxLineShape::FindLineEndPoints} + +\func{void}{FindLineEndPoints}{\param{double *}{fromX}, \param{double *}{fromY}, \param{double *}{toX}, \param{double *}{toY}} + +Finds the x, y points at the two ends of the line. This function can be +used by e.g. line-routing routines to get the actual points on the two +node images where the lines will be drawn to/from. + +\membersection{wxLineShape::FindLinePosition} + +\func{int}{FindLinePosition}{\param{double }{x}, \param{double }{y}} + +Find which position we're talking about at this x, y. +Returns ARROW\_POSITION\_START, ARROW\_POSITION\_MIDDLE, ARROW\_POSITION\_END. + +\membersection{wxLineShape::FindMinimumWidth} + +\func{double}{FindMinimumWidth}{\void} + +Finds the horizontal width for drawing a line with arrows in minimum +space. Assume arrows at end only. + +\membersection{wxLineShape::FindNth} + +\func{void}{FindNth}{\param{wxShape *}{image}, \param{int *}{nth}, \param{int *}{noArcs}, \param{bool}{ incoming}} + +Finds the position of the line on the given object. Specify whether incoming or outgoing lines are +being considered with {\it incoming}. + +\membersection{wxLineShape::GetAttachmentFrom} + +\constfunc{int}{GetAttachmentFrom}{\void} + +Returns the attachment point on the `from' node. + +\membersection{wxLineShape::GetAttachmentTo} + +\constfunc{int}{GetAttachmentTo}{\void} + +Returns the attachment point on the `to' node. + +\membersection{wxLineShape::GetEnds} + +\func{void}{GetEnds}{\param{double *}{x1}, \param{double *}{y1}, \param{double *}{x2}, \param{double *}{y2}} + +Gets the visible endpoints of the lines for drawing between two objects. + +\membersection{wxLineShape::GetFrom} + +\constfunc{wxShape *}{GetFrom}{\void} + +Gets the `from' object. + +\membersection{wxLineShape::GetLabelPosition} + +\func{void}{GetLabelPosition}{\param{int}{ position}, \param{double *}{x}, \param{double *}{y}} + +Get the reference point for a label. Region x and y are offsets from this. +position is 0 (middle), 1 (start), 2 (end). + +\membersection{wxLineShape::GetNextControlPoint} + +\func{wxPoint *}{GetNextControlPoint}{\param{wxShape *}{shape}} + +Find the next control point in the line after the start/end point, +depending on whether the shape is at the start or end. + +\membersection{wxLineShape::GetTo} + +\func{wxShape *}{GetTo}{\void} + +Gets the `to' object. + +\membersection{wxLineShape::Initialise} + +\func{void}{Initialise}{\void} + +Initialises the line object. + +\membersection{wxLineShape::InsertLineControlPoint} + +\func{void}{InsertLineControlPoint}{\void} + +Inserts a control point at an arbitrary position. + +\membersection{wxLineShape::IsEnd} + +\func{bool}{IsEnd}{\param{wxShape *}{shape}} + +Returns TRUE if {\it shape} is at the end of the line. + +\membersection{wxLineShape::IsSpline} + +\func{bool}{IsSpline}{\void} + +Returns TRUE if a spline is drawn through the control points, and FALSE otherwise. + +\membersection{wxLineShape::MakeLineControlPoints}\label{wxlineshapemakelinecontrolpoints} + +\func{void}{MakeLineControlPoints}{\param{int}{ n}} + +Make a given number of control points (minimum of two). + +\membersection{wxLineShape::OnMoveLink} + +\func{void}{OnMoveLink}{\param{wxDC\&}{ dc}, \param{bool}{ moveControlPoints = TRUE}} + +Called when a connected object has moved, to move the link to +correct position. + +\membersection{wxLineShape::SetAttachmentFrom} + +\func{void}{SetAttachmentTo}{\param{int}{ fromAttach}} + +Sets the `from' shape attachment. + +\membersection{wxLineShape::SetAttachments} + +\func{void}{SetAttachments}{\param{int}{ fromAttach}, \param{int}{ toAttach}} + +Specifies which object attachment points should be used at each end of the line. + +\membersection{wxLineShape::SetAttachmentTo} + +\func{void}{SetAttachmentTo}{\param{int}{ toAttach}} + +Sets the `to' shape attachment. + +\membersection{wxLineShape::SetEnds} + +\func{void}{SetEnds}{\param{double}{ x1}, \param{double}{ y1}, \param{double}{ x2}, \param{double}{ y2}} + +Sets the end positions of the line. + +\membersection{wxLineShape::SetFrom} + +\func{void}{SetFrom}{\param{wxShape *}{object}} + +Sets the `from' object for the line. + +\membersection{wxLineShape::SetIgnoreOffsets} + +\func{void}{SetIgnoreOffsets}{\param{bool}{ ignore}} + +Tells the shape whether to ignore offsets from the end of the line when drawing. + +\membersection{wxLineShape::SetSpline} + +\func{void}{SetSpline}{\param{bool}{ spline}} + +Specifies whether a spline is to be drawn through the control points (TRUE), or a line (FALSE). + +\membersection{wxLineShape::SetTo} + +\func{void}{SetTo}{\param{wxShape *}{object}} + +Sets the `to' object for the line. + +\membersection{wxLineShape::Straighten} + +\func{void}{Straighten}{\param{wxDC*}{ dc = NULL}} + +Straighten verticals and horizontals. {\it dc} is optional. + +\membersection{wxLineShape::Unlink} + +\func{void}{Unlink}{\void} + +Unlinks the line from the nodes at either end. + +\section{\class{wxPolygonShape}}\label{wxpolygonshape} + +A wxPolygonShape's shape is defined by a number of points passed to the object's +constructor. It can be used to create new shapes such as diamonds and triangles. + +\wxheading{Derived from} + +\helpref{wxShape}{wxshape} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxPolygonShape::wxPolygonShape} + +\func{}{wxPolygonShape}{void} + +Constructor. Call \helpref{wxPolygonShape::Create}{wxpolygonshapecreate} to specify the polygon's vertices. + +\membersection{wxPolygonShape::\destruct{wxPolygonShape}} + +\func{}{\destruct{wxPolygonShape}}{\void} + +Destructor. + +\membersection{wxPolygonShape::Create}\label{wxpolygonshapecreate} + +\func{void}{Create}{\param{wxList*}{ points}} + +Takes a list of wxRealPoints; each point is an {\it offset} from the centre. +The polygon's destructor will delete these points, so do not delete them yourself. + +\membersection{wxPolygonShape::AddPolygonPoint} + +\func{void}{AddPolygonPoint}{\param{int}{ pos = 0}} + +Add a control point after the given point. + +\membersection{wxPolygonShape::CalculatePolygonCentre} + +\func{void}{CalculatePolygonCentre}{\void} + +Recalculates the centre of the polygon. + +\membersection{wxPolygonShape::DeletePolygonPoint} + +\func{void}{DeletePolygonPoint}{\param{int}{ pos = 0}} + +Deletes a control point. + +\membersection{wxPolygonShape::GetPoints} + +\func{wxList *}{GetPoints}{\void} + +Returns a pointer to the internal list of polygon vertices (wxRealPoints). + +\membersection{wxPolygonShape::UpdateOriginalPoints} + +\func{void}{UpdateOriginalPoints}{\void} + +If we've changed the shape, must make the original +points match the working points with this function. + +\section{\class{wxRectangleShape}}\label{wxrectangleshape} + +The wxRectangleShape has rounded or square corners. + +\wxheading{Derived from} + +\helpref{wxShape}{wxshape} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxRectangleShape::wxRectangleShape} + +\func{}{wxRectangleShape}{\param{double}{ width = 0.0}, \param{double}{ height = 0.0}} + +Constructor. + +\membersection{wxRectangleShape::\destruct{wxRectangleShape}} + +\func{}{\destruct{wxRectangleShape}}{\void} + +Destructor. + +\membersection{wxRectangleShape::SetCornerRadius} + +\func{void}{SetCornerRadius}{\param{double}{ radius}} + +Sets the radius of the rectangle's rounded corners. If the radius is zero, a non-rounded +rectangle will be drawn. If the radius is negative, the value is the proportion of the +smaller dimension of the rectangle. + +\section{\class{wxPseudoMetaFile}}\label{wxpseudometafile} + +A simple metafile-like class which can load data from a Windows metafile on all platforms. + +\wxheading{Derived from} + +wxObject + +\section{\class{wxShape}}\label{wxshape} + +The wxShape is the top-level, abstract object that all other +objects are derived from. All common functionality is represented by +wxShape's members, and overriden members that appear in derived +classes and have behaviour as documented for wxShape, are not +documented separately. + +\wxheading{Derived from} + +\helpref{wxShapeEvtHandler}{wxshapeevthandler} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxShape::wxShape} + +\func{}{wxShape}{\param{wxShapeCanvas*}{ canvas = NULL}} + +Constructs a new wxShape. + +\membersection{wxShape::\destruct{wxShape}} + +\func{}{\destruct{wxShape}}{\void} + +Destructor. + +\membersection{wxShape::AddLine} + +\func{void}{AddLine}{\param{wxLineShape*}{ line}, \param{wxShape*}{ other}, \param{int}{ attachFrom = 0}, \param{int}{ attachTo = 0}, + \param{int}{ positionFrom = -1}, \param{int}{ positionTo = -1}} + +Adds a line between the specified canvas shapes, at the specified attachment points. + +The position in the list of lines at each end can also be specified, so that the line will be drawn +at a particular point on its attachment point. + +\membersection{wxShape::AddRegion} + +\func{void}{AddRegion}{\param{wxShapeRegion*}{ region}} + +Adds a region to the shape. + +\membersection{wxShape::AddText} + +\func{void}{AddText}{\param{const wxString\& }{string}} + +Adds a line of text to the shape's default text region. + +\membersection{wxShape::AddToCanvas} + +\func{void}{AddToCanvas}{\param{wxShapeCanvas*}{ theCanvas}, \param{wxShape*}{ addAfter=NULL}} + +Adds the shape to the canvas's shape list. If {\it addAfter} is +non-NULL, will add the shape after this one. + +\membersection{wxShape::AncestorSelected} + +\constfunc{bool}{AncestorSelected}{\void} + +TRUE if the shape's ancestor is currently selected. + +\membersection{wxShape::ApplyAttachmentOrdering}\label{wxshapeapplyattachmentordering} + +\func{void}{ApplyAttachmentOrdering}{\param{wxList\&}{ linesToSort}} + +Applies the line ordering in {\it linesToSort} to the shape, to reorder the way lines are attached. + +\membersection{wxShape::AssignNewIds} + +\func{void}{AssignNewIds}{\void} + +Assigns new ids to this image and its children. + +\membersection{wxShape::Attach}\label{wxshapeattach} + +\func{void}{Attach}{\param{wxShapeCanvas*}{ can}} + +Sets the shape's internal canvas pointer to point to the given canvas. + +\membersection{wxShape::AttachmentIsValid}\label{wxshapeattachmentisvalid} + +\constfunc{bool}{AttachmentIsValid}{\param{int}{ attachment}} + +Returns TRUE if {\it attachment} is a valid attachment point. + +\membersection{wxShape::AttachmentSortTest}\label{wxshapeattachmentsorttest} + +\constfunc{bool}{AttachmentSortTest}{\param{int}{ attachment}, \param{const wxRealPoint\&}{ pt1}, + \param{const wxRealPoint\&}{ pt2}} + +Returns TRUE if {\it pt1} is less than or equal to {\it pt2}, in the sense +that one point comes before another on an edge of the shape. {\it attachment} is +the attachment point (side) in question. + +This function is used in \helpref{wxShape::MoveLineToNewAttachment}{wxshapemovelinetonewattachment} to +determine the new line ordering. + +\membersection{wxShape::CalcSimpleAttachment}\label{wxshapecalcsimpleattachment} + +\func{wxRealPoint}{CalcSimpleAttachment}{\param{const wxRealPoint\&}{ pt1}, + \param{const wxRealPoint\&}{ pt2}, \param{int}{ nth}, \param{int}{ noArcs}, \param{wxLineShape*}{ line}} + +Assuming the attachment lies along a vertical or horizontal line, +calculates the position on that point. + +\wxheading{Parameters} + +\docparam{pt1}{The first point of the line repesenting the edge of the shape.} + +\docparam{pt2}{The second point of the line representing the edge of the shape.} + +\docparam{nth}{The position on the edge (for example there may be 6 lines at this attachment point, +and this may be the 2nd line.} + +\docparam{noArcs}{The number of lines at this edge.} + +\docparam{line}{The line shape.} + +\wxheading{Remarks} + +This function expects the line to be either vertical or horizontal, and determines which. + +\membersection{wxShape::CalculateSize} + +\func{void}{CalculateSize}{\void} + +Called to calculate the shape's size if dependent on children sizes. + +\membersection{wxShape::ClearAttachments} + +\func{void}{ClearAttachments}{\void} + +Clears internal custom attachment point shapes (of class wxAttachmentPoint). + +\membersection{wxShape::ClearRegions} + +\func{void}{ClearRegions}{\void} + +Clears the wxShapeRegions from the shape. + +\membersection{wxShape::ClearText} + +\func{void}{ClearText}{\param{int}{ regionId = 0}} + +Clears the text from the specified text region. + +\membersection{wxShape::Constrain} + +\func{bool}{Constrain}{\void} + +Calculates the shape's constraints (if any). Applicable +only to wxCompositeShape, does nothing if the shape is of +a different class. + +\membersection{wxShape::Copy}\label{wxshapecopy} + +\func{void}{Copy}{\param{wxShape\&}{ copy}} + +Copy this shape into {\it copy}. Every derived class must have one of these, and each Copy implementation +must call the derived class's implementation to ensure everything is copied. See also \helpref{wxShape::CreateNewCopy}{wxshapecreatenewcopy}. + +\membersection{wxShape::CreateNewCopy}\label{wxshapecreatenewcopy} + +\func{wxShape* }{CreateNewCopy}{\param{bool}{ resetMapping = TRUE}, \param{bool}{ recompute = TRUE}} + +Creates and returns a new copy of this shape (calling \helpref{wxShape::Copy}{wxshapecopy}). Do not override this function. + +This function should always be used to create a new copy, since it must do special processing +for copying constraints associated with constraints. + +If {\it resetMapping} is TRUE, a mapping table used for complex shapes is reset; this may not be desirable +if the shape being copied is a child of a composite (and so the mapping table is in use). + +If {\it recompute} is TRUE, \helpref{wxShape::Recompute}{wxshaperecompute} is called for the new shape. + +\wxheading{Remarks} + +This function uses the wxWindows dynamic object creation system to create a new shape of the same +type as `this', before calling Copy. + +If the event handler for this shape is not the same as the shape itself, the event handler is also copied +using \helpref{wxShapeEvtHandler::CreateNewCopy}{wxshapeevthandlercreatenewcopy}. + +\membersection{wxShape::DeleteControlPoints} + +\func{void}{DeleteControlPoints}{\void} + +Deletes the control points (or handles) for the shape. Does not redraw +the shape. + +\membersection{wxShape::Detach} + +\func{void}{Detach}{\void} + +Disassociates the shape from its canvas by setting the internal shape +canvas pointer to NULL. + +\membersection{wxShape::Draggable} + +\func{bool}{Draggable}{\void} + +TRUE if the shape may be dragged by the user. + +\membersection{wxShape::Draw} + +\func{void}{Draw}{\param{wxDC\&}{ dc}} + +Draws the whole shape and any lines attached to it. + +Do not override this function: override OnDraw, which is called +by this function. + +\membersection{wxShape::DrawContents} + +\func{void}{DrawContents}{\param{wxDC\&}{ dc}} + +Draws the internal graphic of the shape (such as +text). + +Do not override this function: override OnDrawContents, which is called +by this function. + +\membersection{wxShape::DrawLinks} + +\func{void}{DrawLinks}{\param{wxDC\&}{ dc}, \param{int}{ attachment = -1}} + +Draws any lines linked to this shape. + +\membersection{wxShape::Erase} + +\func{void}{Erase}{\param{wxDC\&}{ dc}} + +Erases the shape, but does not repair damage caused to other +shapes. + +\membersection{wxShape::EraseContents} + +\func{void}{EraseContents}{\param{wxDC\&}{ dc}} + +Erases the shape contents, that is, the area within the shape's +minimum bounding box. + +\membersection{wxShape::EraseLinks} + +\func{void}{EraseLinks}{\param{wxDC\&}{ dc}, \param{int}{ attachment = -1}} + +Erases links attached to this shape, but does not repair +damage caused to other shapes. + +\membersection{wxShape::FindRegion} + +\func{wxShape *}{FindRegion}{\param{const wxString\& }{regionName}, \param{int *}{regionId}} + +Finds the actual image (`this' if non-composite) and region id for the given +region name. + +\membersection{wxShape::FindRegionNames} + +\func{void}{FindRegionNames}{\param{wxStringList\&}{ list}} + +Finds all region names for this image (composite or simple). +Supply an empty string list. + +\membersection{wxShape::Flash} + +\func{void}{Flash}{\void} + +Flashes the shape. + +\membersection{wxShape::FormatText} + +\func{void}{FormatText}{\param{const wxString\& }{s}, \param{int}{ i = 0}} + +Reformats the given text region; defaults to formatting the default region. + +\membersection{wxShape::GetAttachmentMode} + +\constfunc{bool}{GetAttachmentMode}{\void} + +Returns the attachment mode, which is TRUE if attachments are used, FALSE otherwise (in which case +lines will be drawn as if to the centre of the shape). See \helpref{wxShape::SetAttachmentMode}{wxshapesetattachmentmode}. + +\membersection{wxShape::GetAttachmentPosition}\label{wxshapegetattachmentposition} + +\func{bool}{GetAttachmentPosition}{\param{int}{ attachment}, \param{double*}{ x}, \param{double*}{ y}, + \param{int}{ nth = 0}, \param{int}{ noArcs = 1}, \param{wxLineShape*}{ line = NULL}} + +Gets the position at which the given attachment point should be drawn. + +If {\it attachment} isn't found among the attachment points of the shape, returns FALSE. + +\membersection{wxShape::GetBoundingBoxMax} + +\func{void}{GetBoundingBoxMax}{\param{double *}{width}, \param{double *}{height}} + +Gets the maximum bounding box for the shape, taking into +account external features such as shadows. + +\membersection{wxShape::GetBoundingBoxMin} + +\func{void}{GetBoundingBoxMin}{\param{double *}{width}, \param{double *}{height}} + +Gets the minimum bounding box for the shape, that defines +the area available for drawing the contents (such as text). + +\membersection{wxShape::GetBrush} + +\constfunc{wxBrush*}{GetBrush}{\void} + +Returns the brush used for filling the shape. + +\membersection{wxShape::GetCanvas} + +\constfunc{wxShapeCanvas*}{GetCanvas}{\void} + +Gets the internal canvas pointer. + +\membersection{wxShape::GetCentreResize} + +\constfunc{bool}{GetCentreResize}{\void} + +Returns TRUE if the shape is to be resized from the centre (the centre +stands still), or FALSE if from the corner or side being dragged (the +other corner or side stands still). + +\membersection{wxShape::GetChildren} + +\constfunc{wxList\&}{GetChildren}{\void} + +Returns a reference to the list of children for this shape. + +\membersection{wxShape::GetClientData} + +\func{wxObject*}{GetClientData}{\void} + +Gets the client data associated with the shape (NULL if there is +none). + +\membersection{wxShape::GetDisableLabel} + +\constfunc{bool}{GetDisableLabel}{\void} + +Returns TRUE if the default region will not be shown, FALSE otherwise. + +\membersection{wxShape::GetEventHandler} + +\constfunc{wxShapeEvtHandler*}{GetEventHandler}{\void} + +Returns the event handler for this shape. + +\membersection{wxShape::GetFixedHeight} + +\constfunc{bool}{GetFixedHeight}{\void} + +Returns TRUE if the shape cannot be resized in the vertical plane. + +\membersection{wxShape::GetFixedSize} + +\func{void}{GetFixedSize}{\param{bool *}{ x}, \param{bool *}{ y}} + +Returns flags indicating whether the shape is of fixed size in either direction. + +\membersection{wxShape::GetFixedWidth} + +\constfunc{bool}{GetFixedWidth}{\void} + +Returns TRUE if the shape cannot be resized in the horizontal plane. + +\membersection{wxShape::GetFont} + +\constfunc{wxFont*}{GetFont}{\param{int}{ regionId = 0}} + +Gets the font for the specified text region. + +\membersection{wxShape::GetFunctor} + +\constfunc{wxString}{GetFunctor}{\void} + +Gets a string representing the type of the shape, to be used when +writing out shape descriptions to a file. This is overridden by +each derived shape class to provide an appropriate type string. By default, +"node\_image" is used for non-line shapes, and "arc\_image" for lines. + +\membersection{wxShape::GetId} + +\constfunc{long}{GetId}{\void} + +Returns the integer identifier for this shape. + +\membersection{wxShape::GetLinePosition}\label{wxshapegetlineposition} + +\func{int}{GetLinePosition}{\param{wxLineShape*}{ line}} + +Gets the zero-based position of {\it line} in the list of lines for this shape. + +\membersection{wxShape::GetLines} + +\constfunc{wxList\&}{GetLines}{\void} + +Returns a reference to the list of lines connected to this shape. + +\membersection{wxShape::GetMaintainAspectRatio}\label{wxshapegetmaintainaspectratio} + +\constfunc{bool}{GetMaintainAspectRatio}{\void} + +If returns TRUE, resizing the shape will not change the aspect ratio +(width and height will be in the original proportion). + +\membersection{wxShape::GetNumberOfAttachments}\label{wxshapegetnumberofattachments} + +\constfunc{int}{GetNumberOfAttachments}{\void} + +Gets the number of attachment points for this shape. + +\membersection{wxShape::GetNumberOfTextRegions} + +\constfunc{int}{GetNumberOfTextRegions}{\void} + +Gets the number of text regions for this shape. + +\membersection{wxShape::GetParent} + +\constfunc{wxShape *}{GetParent}{\void} + +Returns the parent of this shape, if it is part of a composite. + +\membersection{wxShape::GetPen} + +\constfunc{wxPen*}{GetPen}{\void} + +Returns the pen used for drawing the shape's outline. + +\membersection{wxShape::GetPerimeterPoint} + +\func{bool}{GetPerimeterPoint}{\param{double}{ x1}, \param{double}{ y1}, \param{double}{ x2}, \param{double}{ y2}, \param{double *}{x3}, \param{double *}{y3}} + +Gets the point at which the line from (x1, y1) to (x2, y2) hits the shape. Returns TRUE if the +line hits the perimeter. + +\membersection{wxShape::GetRegionId}\label{getregionid} + +\func{int}{GetRegionId}{\param{const wxString\& }{name}} + +Gets the region's identifier by name. This is {\it not} unique for within an entire composite, but +is unique for the image. + +\membersection{wxShape::GetRegionName}\label{getregionname} + +\func{wxString}{GetRegionName}{\param{int}{ regionId = 0}} + +Gets the region's name. A region's name can be used to uniquely determine a region within +an entire composite image hierarchy. See also \helpref{wxShape::SetRegionName}{wxshapesetregionname}. + +\membersection{wxShape::GetRegions}\label{getregions} + +\func{wxList\&}{GetRegions}{\void} + +Returns the list of wxShapeRegions. + +\membersection{wxShape::GetRotation} + +\constfunc{double}{GetRotatation}{\void} + +Returns the angle of rotation in radians. + +\membersection{wxShape::GetSensitivityFilter} + +\constfunc{void}{GetSensitivityFilter}{\void} + +Returns the sensitivity filter, a bitlist of values. See \helpref{wxShape::SetSensitivityFilter}{wxshapesetsensitivityfilter}. + +\membersection{wxShape::GetShadowMode} + +\constfunc{int}{SetShadowMode}{\void} + +Returns the shadow mode. See \helpref{wxShape::SetShadowMode}{wxshapesetshadowmode}. + +\membersection{wxShape::GetSpaceAttachments} + +\constfunc{bool}{GetSpaceAttachments}{\void} + +Indicates whether lines should be spaced out evenly at the point they touch the node (TRUE), or whether they +should join at a single point (FALSE). + +\membersection{wxShape::GetTextColour} + +\constfunc{wxString}{GetTextColour}{\param{int}{ regionId = 0}} + +Gets the colour for the specified text region. + +\membersection{wxShape::GetTopAncestor} + +\constfunc{wxShape *}{GetTopAncestor}{\void} + +Returns the top-most ancestor of this shape (the root of the composite). + +\membersection{wxShape::GetX} + +\constfunc{double}{GetX}{\void} + +Gets the x position of the centre of the shape. + +\membersection{wxShape::GetY} + +\constfunc{double}{GetY}{\void} + +Gets the y position of the centre of the shape. + +\membersection{wxShape::HitTest} + +\func{bool}{HitTest}{\param{double}{ x}, \param{double}{ y}, \param{int*}{ attachment}, \param{double*}{ distance}} + +Given a point on a canvas, returns TRUE if the point was on the shape, and returns +the nearest attachment point and distance from the given point and target. + +\membersection{wxShape::Insert} + +\func{void}{InsertInCanvas}{\param{wxShapeCanvas*}{ canvas}} + +Inserts the shape at the front of the shape list of {\it canvas}. + +\membersection{wxShape::IsHighlighted} + +\constfunc{bool}{IsHighlighted}{\void} + +Returns TRUE if the shape is highlighted. Shape highlighting is unimplemented. + +\membersection{wxShape::IsShown} + +\constfunc{bool}{IsShown}{\void} + +Returns TRUE if the shape is in a visible state, FALSE otherwise. Note +that this has nothing to do with whether the window is hidden or the +shape has scrolled off the canvas; it refers to the internal +visibility flag. + +\membersection{wxShape::MakeControlPoints} + +\func{void}{MakeControlPoints}{\void} + +Make a list of control points (draggable handles) appropriate to the shape. + +\membersection{wxShape::MakeMandatoryControlPoints} + +\func{void}{MakeMandatoryControlPoints}{\void} + +Make the mandatory control points. For example, the control point on a dividing line should +appear even if the divided rectangle shape's handles should not appear (because it is the child of +a composite, and children are not resizable). + +\membersection{wxShape::Move}\label{wxshapemove} + +\func{void}{Move}{\param{wxDC\&}{ dc}, \param{double}{ x1}, \param{double}{ y1}, \param{bool}{ display = TRUE}} + +Move the shape to the given position, redrawing if {\it display} is TRUE. + +\membersection{wxShape::MoveLineToNewAttachment}\label{wxshapemovelinetonewattachment} + +\func{void}{MoveLineToNewAttachment}{\param{wxDC\&}{ dc}, \param{wxLineShape*}{ toMove}, \param{double}{ x}, \param{double}{ y}} + +Move the given line (which must already be attached to the shape) to +a different attachment point on the shape, or a different order on the same attachment. + +Cals \helpref{wxShape::AttachmentSortTest}{wxshapeattachmentsorttest} and then \helpref{wxShapeEvtHandler::OnChangeAttachment}{wxshapeevthandleronchangeattachment}. + +\membersection{wxShape::MoveLinks} + +\func{void}{MoveLinks}{\param{wxDC\&}{ dc}} + +Redraw all the lines attached to the shape. + +\membersection{wxShape::NameRegions} + +\func{void}{NameRegions}{\param{const wxString\& }{parentName = ``"}} + +Make unique names for all the regions in a shape or composite shape. + +\membersection{wxShape::Rotate} + +\func{void}{Rotate}{\param{double }{x}, \param{double }{y}, \param{double }{theta}} + +Rotate about the given axis by the given amount in radians (does nothing +for most shapes). But even non-rotating shapes should record their +notional rotation in case it's important (e.g. in dog-leg code). + +\membersection{wxShape::ReadConstraints} + +\func{void}{ReadConstraints}{\param{wxExpr *}{clause}, \param{wxExprDatabase *}{database}} + +If the shape is a composite, it may have constraints that need to be read in in a separate pass. + +\membersection{wxShape::ReadAttributes} + +\func{void}{ReadAttributes}{\param{wxExpr*}{ clause}} + +Reads the attributes (data member values) from the given expression. + +\membersection{wxShape::ReadRegions} + +\func{void}{ReadRegions}{\param{wxExpr *}{clause}} + +Reads in the regions. + +\membersection{wxShape::Recentre} + +\func{void}{Recentre}{\void} + +Does recentring (or other formatting) for all the text regions for this shape. + +\membersection{wxShape::RemoveFromCanvas} + +\func{void}{RemoveFromCanvas}{\param{wxShapeCanvas*}{ canvas}} + +Removes the shape from the canvas. + +\membersection{wxShape::ResetControlPoints} + +\func{void}{ResetControlPoints}{\void} + +Resets the positions of the control points (for instance when the +shape's shape has changed). + +\membersection{wxShape::ResetMandatoryControlPoints} + +\func{void}{ResetMandatoryControlPoints}{\void} + +Reset the mandatory control points. For example, the control point on a dividing line should +appear even if the divided rectangle shape's handles should not appear (because it is the child of +a composite, and children are not resizable). + +\membersection{wxShape::Recompute}\label{wxshaperecompute} + +\func{bool}{Recompute}{\void} + +Recomputes any constraints associated with the shape (normally +applicable to wxCompositeShapes only, but harmless for other +classes of shape). + +\membersection{wxShape::RemoveLine} + +\func{void}{RemoveLine}{\param{wxLineShape*}{ line}} + +Removes the given line from the shape's list of attached lines. + +\membersection{wxShape::Select}\label{wxshapeselect} + +\func{void}{Select}{\param{bool}{ select = TRUE}} + +Selects or deselects the given shape, drawing or erasing control points +(handles) as necessary. + +\membersection{wxShape::Selected}\label{wxshapeselected} + +\constfunc{bool}{Selected}{\void} + +TRUE if the shape is currently selected. + +\membersection{wxShape::SetAttachmentMode}\label{wxshapesetattachmentmode} + +\func{void}{SetAttachmentMode}{\param{bool}{ flag}} + +Sets the attachment mode to TRUE or FALSE. If TRUE, attachment points +will be significant when drawing lines to and from this shape. +If FALSE, lines will be drawn as if to the centre of the shape. + +\membersection{wxShape::SetBrush} + +\func{void}{SetBrush}{\param{wxBrush *}{brush}} + +Sets the brush for filling the shape's shape. + +\membersection{wxShape::SetCanvas}\label{wxshapesetcanvas} + +\func{void}{SetCanvas}{\param{wxShapeCanvas*}{ theCanvas}} + +Identical to \helpref{wxShape::Attach}{wxshapesetcanvas}. + +\membersection{wxShape::SetCentreResize} + +\func{void}{SetCentreResize}{\param{bool}{ cr}} + +Specify whether the shape is to be resized from the centre (the centre stands still) or from the corner or side +being dragged (the other corner or side stands still). + +\membersection{wxShape::SetClientData} + +\func{void}{SetClientData}{\param{wxObject *}{clientData}} + +Sets the client data. + +\membersection{wxShape::SetDefaultRegionSize}\label{setdefaultregionsize} + +\func{void}{SetDefaultRegionSize}{\void} + +Set the default region to be consistent with the shape size. + +\membersection{wxShape::SetDisableLabel} + +\func{void}{SetDisableLabel}{\param{bool}{ flag}} + +Set {\it flag} to TRUE to stop the default region being shown, FALSE otherwise. + +\membersection{wxShape::SetDraggable} + +\func{void}{SetDraggable}{\param{bool}{ drag}, \param{bool}{ recursive = FALSE}} + +Sets the shape to be draggable or not draggable. + +\membersection{wxShape::SetDrawHandles} + +\func{void}{SetDrawHandles}{\param{bool}{ drawH}} + +Sets the {\it drawHandles} flag for this shape and all descendants. If {\it drawH} is TRUE (the default), +any handles (control points) will be drawn. Otherwise, the handles will not be drawn. + +\membersection{wxShape::SetEventHandler} + +\func{void}{GetEventHandler}{\param{wxShapeEvtHandler *}{handler}} + +Sets the event handler for this shape. + +\membersection{wxShape::SetFixedSize} + +\func{void}{SetFixedSize}{\param{bool}{ x}, \param{bool}{ y}} + +Sets the shape to be of the given, fixed size. + +\membersection{wxShape::SetFont} + +\func{void}{SetFont}{\param{wxFont *}{font}, \param{int}{ regionId = 0}} + +Sets the font for the specified text region. + +\membersection{wxShape::SetFormatMode}\label{setformatmode} + +\func{void}{SetFormatMode}{\param{int}{ mode}, \param{int}{ regionId = 0}} + +Sets the format mode of the default text region. The argument can be a bit list +of the following: + +\begin{description}\itemsep=0pt +\item[FORMAT\_NONE] No formatting. +\item[FORMAT\_CENTRE\_HORIZ] Horizontal centring. +\item[FORMAT\_CENTRE\_VERT] Vertical centring. +\end{description} + +\membersection{wxShape::SetHighlight} + +\func{void}{SetHighlight}{\param{bool}{ hi}, \param{bool}{ recurse = FALSE}} + +Sets the highlight for a shape. Shape highlighting is unimplemented. + +\membersection{wxShape::SetId} + +\func{void}{SetId}{\param{long}{ id}} + +Set the integer identifier for this shape. + +\membersection{wxShape::SetMaintainAspectRatio}\label{wxshapesetmaintainaspectratio} + +\func{void}{SetMaintainAspectRatio}{\param{bool}{ flag}} + +If the argument is TRUE, tells the shape that resizes should not change the aspect ratio +(width and height should be in the original proportion). + +\membersection{wxShape::SetPen} + +\func{void}{SetPen}{\param{wxPen *}{pen}} + +Sets the pen for drawing the shape's outline. + +\membersection{wxShape::SetRegionName}\label{wxshapesetregionname} + +\func{void}{SetRegionName}{\param{const wxString\& }{name}, \param{int}{ regionId = 0}} + +Sets the name for this region. The name for a region is unique within the scope of the whole +composite, whereas a region id is unique only for a single image. + +\membersection{wxShape::SetSensitivityFilter}\label{wxshapesetsensitivityfilter} + +\func{void}{SetSensitivityFilter}{\param{int}{ sens=OP\_ALL}, \param{bool}{ recursive = FALSE}} + +Sets the shape to be sensitive or insensitive to specific mouse operations. + +{\it sens} is a bitlist of the following: + +\begin{itemize}\itemsep=0pt +\item OP\_CLICK\_LEFT +\item OP\_CLICK\_RIGHT +\item OP\_DRAG\_LEFT +\item OP\_DRAG\_RIGHT +\item OP\_ALL (equivalent to a combination of all the above). +\end{itemize} + +\membersection{wxShape::SetShadowMode}\label{wxshapesetshadowmode} + +\func{void}{SetShadowMode}{\param{int}{ mode}, \param{bool}{ redraw = FALSE}} + +Sets the shadow mode (whether a shadow is drawn or not). {\it mode} can be one of +the following: + +\begin{description}\itemsep=0pt +\item[SHADOW\_NONE] No shadow (the default). +\item[SHADOW\_LEFT] Shadow on the left side. +\item[SHADOW\_RIGHT] Shadow on the right side. +\end{description} + +\membersection{wxShape::SetSize} + +\func{void}{SetSize}{\param{double}{ x}, \param{double}{ y}, \param{bool}{ recursive = TRUE}} + +Sets the shape's size. + +\membersection{wxShape::SetSpaceAttachments} + +\func{void}{SetSpaceAttachments}{\param{bool}{ sp}} + +Indicate whether lines should be spaced out evenly at the point they touch the node (TRUE), or whether they +should join at a single point (FALSE). + +\membersection{wxShape::SetTextColour} + +\func{void}{SetTextColour}{\param{const wxString\& }{colour}, \param{int}{ regionId = 0}} + +Sets the colour for the specified text region. + +\membersection{wxShape::SetX} + +\func{void}{SetX}{\param{double}{ x}} + +Sets the {\it x} position of the shape. + +\membersection{wxShape::SetX} + +\func{void}{SetY}{\param{double}{ y}} + +Sets the {\it y} position of the shape. + +\membersection{wxShape::SpaceAttachments} + +\func{void}{SpaceAttachments}{\param{bool}{ sp}} + +Sets the spacing mode: if TRUE, lines at the same attachment point will be +spaced evenly across that side of the shape. If false, all lines at the +same attachment point will emanate from the same point. + +\membersection{wxShape::Show} + +\func{void}{Show}{\param{bool}{ show}} + +Sets a flag indicating whether the shape should be drawn. + +\membersection{wxShape::Unlink} + +\func{void}{Unlink}{\void} + +If the shape is a line, unlinks the nodes attached to the shape, removing itself from the list of +lines for each of the `to' and `from' nodes. + +\membersection{wxShape::WriteAttributes} + +\func{void}{WriteAttributes}{\param{wxExpr *}{clause}} + +Writes the shape's attributes (data member values) into the given expression. + +\membersection{wxShape::WriteRegions} + +\func{void}{WriteRegions}{\param{wxExpr *}{clause}} + +Writes the regions. + +\section{\class{wxShapeCanvas}}\label{wxshapecanvas} + +A canvas for drawing diagrams on. + +\wxheading{Derived from} + +wxScrolledWindow + +\wxheading{See also} + +\helpref{wxDiagram}{wxdiagram} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxShapeCanvas::wxShapeCanvas} + +\func{}{wxShapeCanvas}{\param{wxWindow*}{ parent = NULL}, \param{wxWindowID}{ id = -1}, + \param{const wxPoint\&}{ pos = wxDefaultPosition}, \param{const wxSize\&}{ size = wxDefaultSize}, + \param{long}{ style = wxBORDER}} + +Constructor. + +\membersection{wxShapeCanvas::\destruct{wxShapeCanvas}} + +\func{}{\destruct{wxShapeCanvas}}{\void} + +Destructor. + +\membersection{wxShapeCanvas::AddShape} + +\func{void}{AddShape}{\param{wxShape *}{shape}, \param{wxShape *}{addAfter = NULL}} + +Adds a shape to the diagram. If {\it addAfter} is non-NULL, the shape will be added after this +one. + +\membersection{wxShapeCanvas::FindShape} + +\func{wxShape *}{FindShape}{\param{double}{ x1}, \param{double}{ y}, \param{int *}{attachment}, \param{wxClassInfo *}{info = NULL}, + \param{wxShape *}{notImage = NULL}} + +Find a shape under this mouse click. Returns the shape (or NULL), and the nearest attachment point. + +If {\it info} is non-NULL, a shape whose class which is a descendant of the desired class is found. + +If {\it notImage} is non-NULL, shapes which are descendants of {\it notImage} are ignored. + +\membersection{wxShapeCanvas::FindFirstSensitiveShape} + +\func{wxShape *}{FindFirstSensitiveShape}{\param{double}{ x1}, \param{double}{ y}, \param{int *}{attachment}, \param{int}{ op}} + +Finds the first sensitive shape whose sensitivity filter matches {\it op}, working up the hierarchy of composites until +one (or none) is found. + +\membersection{wxShapeCanvas::GetDiagram} + +\constfunc{wxDiagram*}{GetDiagram}{\void} + +Returns the canvas associated with this diagram. + +\membersection{wxShapeCanvas::GetGridSpacing} + +\constfunc{double}{GetGridSpacing}{\void} + +Returns the grid spacing. + +\membersection{wxShapeCanvas::GetMouseTolerance} + +\constfunc{int}{GetMouseTolerance}{\void} + +Returns the tolerance within which a mouse move is ignored. + +\membersection{wxShapeCanvas::GetShapeList} + +\constfunc{wxList*}{GetShapeList}{\void} + +Returns a pointer to the internal shape list. + +\membersection{wxShapeCanvas::GetQuickEditMode} + +\constfunc{bool}{GetQuickEditMode}{\void} + +Returns quick edit mode for the associated diagram. + +\membersection{wxShapeCanvas::InsertShape} + +\func{void}{InsertShape}{\param{wxShape*}{ shape}} + +Inserts a shape at the front of the shape list. + +\membersection{wxShapeCanvas::OnBeginDragLeft}\label{wxshapecanvasonbegindragleft} + +\func{void}{OnBeginDragLeft}{\param{double}{ x}, \param{double}{ y}, \param{int}{ keys = 0}} + +Called when the start of a left-button drag event on the canvas background is detected by OnEvent. You may override this member; +by default it does nothing. + +{\it keys} is a bit list of the following: + +\begin{itemize}\itemsep=0pt +\item KEY\_SHIFT +\item KEY\_CTRL +\end{itemize} + +See also \helpref{wxShapeCanvas::OnDragLeft}{wxshapecanvasondragleft}, \helpref{wxShapeCanvas::OnEndDragLeft}{wxshapecanvasonenddragleft}. + +\membersection{wxShapeCanvas::OnBeginDragRight}\label{wxshapecanvasonbegindragright} + +\func{void}{OnBeginDragRight}{\param{double}{ x}, \param{double}{ y}, \param{int}{ keys = 0}} + +Called when the start of a right-button drag event on the canvas background is detected by OnEvent. You may override this member; +by default it does nothing. + +{\it keys} is a bit list of the following: + +\begin{itemize}\itemsep=0pt +\item KEY\_SHIFT +\item KEY\_CTRL +\end{itemize} + +See also \helpref{wxShapeCanvas::OnDragRight}{wxshapecanvasondragright}, \helpref{wxShapeCanvas::OnEndDragRight}{wxshapecanvasonenddragright}. + +\membersection{wxShapeCanvas::OnEndDragLeft}\label{wxshapecanvasonenddragleft} + +\func{void}{OnEndDragLeft}{\param{double}{ x}, \param{double}{ y}, \param{int}{ keys = 0}} + +Called when the end of a left-button drag event on the canvas background is detected by OnEvent. You may override this member; +by default it does nothing. + +{\it keys} is a bit list of the following: + +\begin{itemize}\itemsep=0pt +\item KEY\_SHIFT +\item KEY\_CTRL +\end{itemize} + +See also \helpref{wxShapeCanvas::OnDragLeft}{wxshapecanvasondragleft}, \helpref{wxShapeCanvas::OnBeginDragLeft}{wxshapecanvasonbegindragleft}. + +\membersection{wxShapeCanvas::OnEndDragRight}\label{wxshapecanvasonenddragright} + +\func{void}{OnEndDragRight}{\param{double}{ x}, \param{double}{ y}, \param{int}{ keys = 0}} + +Called when the end of a right-button drag event on the canvas background is detected by OnEvent. You may override this member; +by default it does nothing. + +{\it keys} is a bit list of the following: + +\begin{itemize}\itemsep=0pt +\item KEY\_SHIFT +\item KEY\_CTRL +\end{itemize} + +See also \helpref{wxShapeCanvas::OnDragRight}{wxshapecanvasondragright}, \helpref{wxShapeCanvas::OnBeginDragRight}{wxshapecanvasonbegindragright}. + +\membersection{wxShapeCanvas::OnDragLeft}\label{wxshapecanvasondragleft} + +\func{void}{OnDragLeft}{\param{bool}{ draw}, \param{double}{ x}, \param{double}{ y}, \param{int}{ keys = 0}} + +Called when a left-button drag event on the canvas background is detected by OnEvent. You may override this member; +by default it does nothing. + +{\it draw} is alternately TRUE and FALSE, to assist drawing and erasing. + +{\it keys} is a bit list of the following: + +\begin{itemize}\itemsep=0pt +\item KEY\_SHIFT +\item KEY\_CTRL +\end{itemize} + +See also \helpref{wxShapeCanvas::OnBeginDragLeft}{wxshapecanvasonbegindragleft}, \helpref{wxShapeCanvas::OnEndDragLeft}{wxshapecanvasonenddragleft}. + +\membersection{wxShapeCanvas::OnDragRight}\label{wxshapecanvasondragright} + +\func{void}{OnDragRight}{\param{bool}{ draw}, \param{double}{ x}, \param{double}{ y}, \param{int}{ keys = 0}} + +Called when a right-button drag event on the canvas background is detected by OnEvent. You may override this member; +by default it does nothing. + +{\it draw} is alternately TRUE and FALSE, to assist drawing and erasing. + +{\it keys} is a bit list of the following: + +\begin{itemize}\itemsep=0pt +\item KEY\_SHIFT +\item KEY\_CTRL +\end{itemize} + +See also \helpref{wxShapeCanvas::OnBeginDragRight}{wxshapecanvasonbegindragright}, \helpref{wxShapeCanvas::OnEndDragRight}{wxshapecanvasonenddragright}. + +\membersection{wxShapeCanvas::OnLeftClick}\label{wxshapecanvasonleftclick} + +\func{void}{OnLeftClick}{\param{double}{ x}, \param{double}{ y}, \param{int}{ keys = 0}} + +Called when a left click event on the canvas background is detected by OnEvent. You may override this member; +by default it does nothing. + +{\it keys} is a bit list of the following: + +\begin{itemize}\itemsep=0pt +\item KEY\_SHIFT +\item KEY\_CTRL +\end{itemize} + +\membersection{wxShapeCanvas::OnRightClick}\label{wxshapecanvasonrightclick} + +\func{void}{OnRightClick}{\param{double}{ x}, \param{double}{ y}, \param{int}{ keys = 0}} + +Called when a right click event on the canvas background is detected by OnEvent. You may override this member; +by default it does nothing. + +{\it keys} is a bit list of the following: + +\begin{itemize}\itemsep=0pt +\item KEY\_SHIFT +\item KEY\_CTRL +\end{itemize} + +\membersection{wxShapeCanvas::Redraw} + +\func{void}{Redraw}{\void} + +Calls wxDiagram::Redraw. + +\membersection{wxShapeCanvas::RemoveShape} + +\func{void}{RemoveShape}{\param{wxShape *}{shape}} + +Calls wxDiagram::RemoveShape. + +\membersection{wxShapeCanvas::SetDiagram} + +\func{void}{SetDiagram}{\param{wxDiagram *}{diagram}} + +Sets the diagram associated with this diagram. + +\membersection{wxShapeCanvas::Snap} + +\func{void}{Snap}{\param{double *}{x}, \param{double *}{y}} + +Calls wxDiagram::Snap. + + + +\section{\class{wxShapeEvtHandler}}\label{wxshapeevthandler} + +wxShapeEvtHandler is a class from which wxShape (and therefore all shape classes) are derived. +A wxShape also contains a pointer to its current wxShapeEvtHandler. Event handlers +can be swapped in and out, altering the behaviour of a shape. This allows, for example, +a range of behaviours to be redefined in one class, rather than requiring +each shape class to be subclassed. + +\wxheading{Derived from} + +wxObject + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxShapeEvtHandler::m\_handlerShape} + +\member{wxShape*}{m\_handlerShape} + +Pointer to the shape associated with this handler. + +\membersection{wxShapeEvtHandler::m\_previousHandler} + +\member{wxShapeEvtHandler*}{m\_previousHandler} + +Pointer to the previous handler. + +\membersection{wxShapeEvtHandler::wxShapeEvtHandler} + +\func{void}{wxShapeEvtHandler}{\param{wxShapeEvtHandler *}{previous = NULL}, \param{wxShape *}{shape = NULL}} + +Constructs a new event handler. + +\membersection{wxShapeEvtHandler::\destruct{wxShapeEvtHandler}} + +\func{void}{\destruct{wxShapeEvtHandler}}{\void} + +Destructor. + +\membersection{wxShapeEvtHandler::CopyData}\label{wxshapeevthandlercopydata} + +\func{void}{CopyData}{\param{wxShapeEvtHandler\&}{ handler}} + +A virtual function to copy the data from this object to {\it handler}. Override if you +derive from wxShapeEvtHandler and have data to copy. + +\membersection{wxShapeEvtHandler::CreateNewCopy}\label{wxshapeevthandlercreatenewcopy} + +\func{wxShapeEvtHandler*}{CreateNewCopy}{\void} + +Creates a new event handler object of the same class as this object, and then +calls \helpref{wxShapeEvtHandler::CopyData}{wxshapeevthandlercopydata}. + +\membersection{wxShapeEvtHandler::GetPreviousHandler}\label{wxshapeevthandlergetprevioushandler} + +\constfunc{wxShapeEvtHandler*}{GetPreviousHandler}{\void} + +Returns the previous handler. + +\membersection{wxShapeEvtHandler::GetShape}\label{wxshapeevthandlergetshape} + +\constfunc{wxShape*}{GetShape}{\void} + +Returns the shape associated with this handler. + +\membersection{wxShapeEvtHandler::OnBeginDragLeft} + +\func{void}{OnBeginDragLeft}{\param{double}{ x}, \param{double}{ y}, \param{int}{ keys=0}, \param{int}{ attachment = 0}} + +Called when the user is beginning to drag using the left mouse button. + +\membersection{wxShapeEvtHandler::OnBeginDragRight} + +\func{void}{OnBeginDragRight}{\param{double}{ x}, \param{double}{ y}, \param{int}{ keys=0}, \param{int}{ attachment = 0}} + +Called when the user is beginning to drag using the right mouse button. + +\membersection{wxShapeEvtHandler::OnBeginSize} + +\func{void}{OnBeginSize}{\param{double}{ width}, \param{double}{ height}} + +Called when a shape starts to be resized. + +\membersection{wxShapeEvtHandler::OnChangeAttachment}\label{wxshapeevthandleronchangeattachment} + +\func{void}{OnChangeAttachment}{\param{int}{ attachment}, \param{wxLineShape*}{ line}, \param{wxList\&}{ ordering}} + +Override this to prevent or intercept line reordering. wxShape's implementation of this function +calls \helpref{wxShape::ApplyAttachmentOrdering}{wxshapeapplyattachmentordering} to apply +the new ordering. + +\membersection{wxShapeEvtHandler::OnDragLeft} + +\func{void}{OnDragLeft}{\param{bool}{ draw}, \param{double}{ x}, \param{double}{ y}, \param{int}{ keys=0}, \param{int}{ attachment = 0}} + +Called twice when the shape is being dragged, once to allow erasing the old +image, and again to allow drawing at the new position. + +\membersection{wxShapeEvtHandler::OnDragRight} + +\func{void}{OnDragRight}{\param{bool}{ draw}, \param{double}{ x}, \param{double}{ y}, \param{int}{ keys=0}, \param{int}{ attachment = 0}} + +Called twice when the shape is being dragged, once to allow erasing the old +image, and again to allow drawing at the new position. + +\membersection{wxShapeEvtHandler::OnDraw} + +\func{void}{OnDraw}{\param{wxDC\&}{ dc}} + +Defined for each class to draw the main graphic, but +not the contents. + +\membersection{wxShapeEvtHandler::OnDrawContents} + +\func{void}{OnDrawContents}{\param{wxDC\&}{ dc}} + +Defined for each class to draw the contents of the +shape, such as text. + +\membersection{wxShapeEvtHandler::OnDrawControlPoints} + +\func{void}{OnDrawControlPoints}{\param{wxDC\&}{ dc}} + +Called when the shape's control points (handles) should +be drawn. + +\membersection{wxShapeEvtHandler::OnDrawOutline} + +\func{void}{OnDrawOutline}{\param{wxDC\&}{ dc}} + +Called when the outline of the shape should be drawn. + +\membersection{wxShapeEvtHandler::OnEndDragLeft} + +\func{void}{OnEndDragLeft}{\param{double}{ x}, \param{double}{ y}, \param{int}{ keys=0}, \param{int}{ attachment = 0}} + +Called when the user is stopping dragging using the left mouse button. + +\membersection{wxShapeEvtHandler::OnEndDragRight} + +\func{void}{OnEndDragRight}{\param{double}{ x}, \param{double}{ y}, \param{int}{ keys=0}, \param{int}{ attachment = 0}} + +Called when the user is stopping dragging using the right mouse button. + +\membersection{wxShapeEvtHandler::OnEndSize} + +\func{void}{OnEndSize}{\param{double}{ width}, \param{double}{ height}} + +Called after a shape is resized. + +\membersection{wxShapeEvtHandler::OnErase} + +\func{void}{OnErase}{\param{wxDC\&}{ dc}} + +Called when the whole shape should be erased. + +\membersection{wxShapeEvtHandler::OnEraseContents} + +\func{void}{OnEraseContents}{\param{wxDC\&}{ dc}} + +Called when the contents should be erased. + +\membersection{wxShapeEvtHandler::OnEraseControlPoints} + +\func{void}{OnEraseControlPoints}{\param{wxDC\&}{ dc}} + +Called when the shape's control points (handles) should +be erased. + +\membersection{wxShapeEvtHandler::OnHighlight} + +\func{void}{OnHighlight}{\param{wxDC\&}{ dc}} + +Called when the shape should be highlighted. + +\membersection{wxShapeEvtHandler::OnLeftClick} + +\func{void}{OnLeftClick}{\param{double}{ x}, \param{double}{ y}, \param{int}{ keys =0}, \param{int}{ attachment = 0}} + +Called when the shape receives a left mouse click event. + +\membersection{wxShapeEvtHandler::OnMoveLink} + +\func{void}{OnMoveLink}{\param{wxDC\&}{ dc}, \param{bool}{ moveControlPoints=TRUE}} + +Called when the line attached to an shape need to be repositioned, +because the shape has moved. + +\membersection{wxShapeEvtHandler::OnMoveLinks} + +\func{void}{OnMoveLinks}{\param{wxDC\&}{ dc}} + +Called when the lines attached to an shape need to be repositioned, +because the shape has moved. + +\membersection{wxShapeEvtHandler::OnMovePost} + +\func{bool}{OnMovePost}{\param{wxDC\&}{ dc}, \param{double}{ x}, \param{double}{ y}, \param{double}{ oldX}, \param{double}{ oldY}, \param{bool}{ display = TRUE}} + +Called just after the shape receives a move request. + +\membersection{wxShapeEvtHandler::OnMovePre} + +\func{bool}{OnMovePre}{\param{wxDC\&}{ dc}, \param{double}{ x}, \param{double}{ y}, \param{double}{ oldX}, \param{double}{ oldY}, \param{bool}{ display = TRUE}} + +Called just before the shape receives a move request. Returning TRUE +allows the move to be processed; returning FALSE vetoes the move. + +\membersection{wxShapeEvtHandler::OnRightClick} + +\func{void}{OnRightClick}{\param{double}{ x}, \param{double}{ y}, \param{int}{ keys = 0}, \param{int}{ attachment = 0}} + +Called when the shape receives a mouse mouse click event. + +\membersection{wxShapeEvtHandler::OnSize} + +\func{void}{OnSize}{\param{double}{ x}, \param{double}{ y}} + +Called when the shape receives a resize request. + +\membersection{wxShapeEvtHandler::OnSizingBeginDragLeft} + +\func{void}{OnSizingBeginDragLeft}{\param{wxControlPoint*}{ pt}, \param{double}{ x}, \param{double}{ y}, \param{int}{ keys=0}, \param{int}{ attachment = 0}} + +Called when a sizing drag is beginning. + +\membersection{wxShapeEvtHandler::OnSizingDragLeft} + +\func{void}{OnSizingDragLeft}{\param{wxControlPoint*}{ pt}, \param{bool}{ draw}, \param{double}{ x}, \param{double}{ y}, \param{int}{ keys=0}, \param{int}{ attachment = 0}} + +Called when a sizing drag is occurring. + +\membersection{wxShapeEvtHandler::OnSizingEndDragLeft} + +\func{void}{OnSizingEndDragLeft}{\param{wxControlPoint*}{ pt}, \param{double}{ x}, \param{double}{ y}, \param{int}{ keys=0}, \param{int}{ attachment = 0}} + +Called when a sizing drag is ending. + +\membersection{wxShapeEvtHandler::SetPreviousHandler}\label{wxshapeevthandlersetprevioushandler} + +\func{void}{SetPreviousHandler}{\param{wxShapeEvtHandler*}{ handler}} + +Sets the previous handler. + +\membersection{wxShapeEvtHandler::SetShape}\label{wxshapeevthandlersetshape} + +\func{void}{SetShape}{\param{wxShape*}{ shape}} + +Sets the shape for this handler. + +\section{\class{wxTextShape}}\label{wxtextshape} + +As wxRectangleShape, but only the text is displayed. + +\wxheading{Derived from} + +\helpref{wxRectangleShape}{wxrectangleshape} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxTextShape::wxTextShape} + +\func{void}{wxTextShape}{\param{double}{ width = 0.0}, \param{double}{ height = 0.0}} + +Constructor. + +\membersection{wxTextShape::\destruct{wxTextShape}} + +\func{void}{\destruct{wxTextShape}}{\void} + +Destructor. + +\section{Functions}\label{functions} + +These are the OGL functions. + +\membersection{::wxOGLInitialize} + +\func{void}{wxOGLInitialize}{\void} + +Initializes OGL. + +\membersection{::wxOGLCleanUp} + +\func{void}{wxOGLCleanUp}{\void} + +Cleans up OGL. + diff --git a/docs/latex/ogl/contents.gif b/docs/latex/ogl/contents.gif new file mode 100644 index 0000000000000000000000000000000000000000..3dddfa3dd5f0c652e8b27cd6c29e1fdd49ced5a8 GIT binary patch literal 231 zcmVG0Pz3-zrVld=jU&4Z(9HWEC2ui06_p40008OjE||y?GK}z zO&EZ)-n{z{a)K3v=81;mmA0S4Fj_r^UyThZDG{h6k9m zHI_(7spd!5_$SH6m{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/docs/latex/ogl/intro.tex b/docs/latex/ogl/intro.tex new file mode 100644 index 0000000000..6d208fff9b --- /dev/null +++ b/docs/latex/ogl/intro.tex @@ -0,0 +1,47 @@ +\chapter{Introduction} +\pagenumbering{arabic}% +\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}% +\setfooter{\thepage}{}{}{}{}{\thepage} + +Object Graphics Library (\ogl) is a C++ library supporting the creation and +manipulation of simple and complex graphic images on a canvas. + +It can be found in the directory {\tt utils/ogl/src} in the +wxWindows distribution. The file {\tt ogl.h} must be included to make use +of the library. + +Please see \helpref{OGL overview}{ogloverview} for a general description how the object library works. For details, +please see the \helpref{class reference}{classref}. + +\section{File structure} + +These are the files that comprise the \ogl\ library. + +\begin{description}\itemsep=0pt +\item[basic.h] Header for basic objects such as wxShape and wxRectangleShape. +\item[basic.cpp] Basic objects implementation (1). +\item[basic2.cpp] Basic objects implementation (2). +\item[bmpshape.h] wxBitmapShape class header. +\item[bmpshape.cpp] wxBitmapShape implementation. +\item[canvas.h] wxShapeCanvas class header. +\item[canvas.cpp] wxShapeCanvas class implementation. +\item[composit.h] Composite object class header. +\item[composit.cpp] Composite object class implementation. +\item[constrnt.h] Constraint classes header. +\item[constrnt.cpp] Constraint classes implementation. +\item[divided.h] Divided object class header. +\item[divided.cpp] Divided object class implementation. +\item[drawn.h] Drawn (metafile) object class header. +\item[drawn.cpp] Drawn (metafile) object class implementation. +\item[graphics.h] Main include file. +\item[lines.h] wxLineShape class header. +\item[lines.cpp] wxLineShape class implementation. +\item[misc.h] Miscellaneous graphics functions header. +\item[misc.cpp] Miscellaneous graphics functions implementation. +\item[ogldiag.h] wxDiagram class header. +\item[ogldiag.cpp] wxDiagram implementation. +\item[mfutils.h] Metafile utilities header. +\item[mfutils.cpp] Metafile utilities implementation. +\end{description} + + diff --git a/docs/latex/ogl/ogl.hpj b/docs/latex/ogl/ogl.hpj new file mode 100644 index 0000000000..5db5ace6f0 --- /dev/null +++ b/docs/latex/ogl/ogl.hpj @@ -0,0 +1,17 @@ +[OPTIONS] +BMROOT=d:\wx2\wxwind~1\docs\latex\ogl ; Assume that bitmaps are where the source is +TITLE=OGL Manual +CONTENTS=Contents +COMPRESS=HIGH + +[FILES] +ogl.rtf + +[CONFIG] +CreateButton("Up", "&Up", "JumpId(`ogl.hlp', `Contents')") +BrowseButtons() + +[MAP] + +[BITMAPS] + diff --git a/docs/latex/ogl/ogl.tex b/docs/latex/ogl/ogl.tex new file mode 100644 index 0000000000..c9c9c215f3 --- /dev/null +++ b/docs/latex/ogl/ogl.tex @@ -0,0 +1,46 @@ +\documentstyle[a4,makeidx,verbatim,texhelp,fancyhea,mysober,mytitle]{report} +\newcommand{\ogl}[0]{{OGL}}% +\definecolour{black}{0}{0}{0}% +\definecolour{cyan}{0}{255}{255}% +\definecolour{green}{0}{255}{0}% +\definecolour{magenta}{255}{0}{255}% +\definecolour{red}{255}{0}{0}% +\definecolour{blue}{0}{0}{200}% +\definecolour{yellow}{255}{255}{0}% +\definecolour{white}{255}{255}{255}% +\input psbox.tex +\parindent 0pt +\parskip 11pt +\title{Object Graphics Library 3.0} +\author{Julian Smart} +\date{September 1998} + +\makeindex +\begin{document} +\maketitle + +\pagestyle{fancyplain} +\bibliographystyle{plain} +\pagenumbering{roman} +\setheader{{\it CONTENTS}}{}{}{}{}{{\it CONTENTS}} +\setfooter{\thepage}{}{}{}{}{\thepage} +\tableofcontents% + +\input{intro.tex} +% +\input{sample.tex} +% +\input{classes.tex} +% +\input{topics.tex} +% +\input{bugs.tex} +% +\input{changes.tex} + +% +\addcontentsline{toc}{chapter}{Index} +\setheader{{\it INDEX}}{}{}{}{}{{\it INDEX}} +\setfooter{\thepage}{}{}{}{}{\thepage}% +\printindex +\end{document} diff --git a/docs/latex/ogl/ogledit.bmp b/docs/latex/ogl/ogledit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e7cf417cf5d40022505909a5653ac5f30b6aa6e3 GIT binary patch literal 87670 zcmeI5&1x*U8HQ`%fH@p+XKo>@A)DO75DrWT1n+VQA*-Yb!*uWZ1Onr%e74?ZIV$>276a|zfYwqNhMWDDoOR@mfh8=pDydE=aWjRc31!5&p-U-tBTSOczlD$ z|1kRrkFTnCw79C8^_2Zh^PqfH{mj4B&p%TR5BwnW%P+rFpFVxUlA3?3x~3c+_@PBK zc?0QqyYU2vr^B|>@y##}RmhhWrn3M#9A58kUw^cD+=~i&#kKU)X@%(^ihekpZeQ>0 zj9fvFS1(jeKdn$Bip)jF1R`Io9yP`lYCIiUMu>EJygIDh;}t@XWV&N@-!ZP#W7RO8 zoUvMUj4Q2=AYhLNXRL0=b}}OV^v*k-XnSe7si#hs&)M)+Eudjy6tvV^vSo)*bJGreSYL?iuUp2>KmH|;No!` zCNCZ@9@laN#9K9&c6BYjT;;rYbRC&>Ex&kNmoHaoFCJY-Cdcw!j-B#87vu4K&c?Wy z{_3vICUPkrVKJM?rFbNXxkN6+BRk9`av>gt!b~EU;juB8N#rs-N`dk@?P+8Y9$SBH zCMo11Ja+oJTtdnvcvS2u*>sRg@TkgD^QkBo;8Am@%_M?cfJa@OK9_`YevgJZV>Sik z{2onl=KOTZ***5W^%hKqoZI8MudTmiBIVp3EkMad&g{|3W8t1;a%PWK94q()%6UCH zXsqP%kn?(Uz&OxjDQETQWO1-ZLeA>ZiQW10SKg=&*KQi;1LLeoX_J3#K<8Cp`6X*D8tAx2!Nc;BM{CNCKV>t4%6yP z_kTH8XWR;Aha16+9t3a7xjZt#j;1@%oRQnnyR7ssB=S6}OeS(Jj|{-?s}dt|sf_$K z9Ulg7Spyr+e@Yu7KJ>DcBe**gFM zh4Sj_BNHG(9SMBSb&i*~7td558G+9oR$bJtCev8YRUbzg(rK(`^EeiZ=`_yhaX1(g zYMjyIu*ifO=kz!vGNr~jJ!2?##bABX=lpG>=?{TXXu|WdUh-qT)EA&IoD;!erRy-bG;^r+TF$v9Rghb0n9ca*xEL`)E_fgZKG z*g|&Y>F35I(kohfZAROV4P4t`WG2j`B~l4=pb+B{sep0^@>wr**Z*@4xm+u7n%f0l z2e4{HiM`q~V~|IOMyE(Wi3BMiBnmCjl7w`j3^NAR zM~6m-NMDIW!vZn8GgKSJ778T324Fa;N7>)wV5m01%B4_uFAA4x+Ct*n9LCbVJ7)eK2Q`XdJ-`2q zf0Rl^WZ6#xc^(6#_51eq{vJITaltU3L@u&`91B!&2wIWe9!Elzf)!V{Keq=jQ-&bD zG%6y!J&rS;-xpw{v#6iO!$FEn=n;tb_j13PG}3N8HFhGsJ&sgIG&+2uD!}Ngu@&j< zahx%uI(66H8e5UR9!INVuREufD`h^M(bwa082v+42J8AfhBIC~cJ*j6u^LbvWuxQk zakN=AhgaRYr!-(OYu z*;o5!IS(;|Jw6CJD`V+cC0le70V)4n9l(npdd3s4!|HI4lJP+VDzrX)5qYdBTOT_{ zMp9U@#$*hrkB!GK)rSvwfDRMNQ`}P9^WX}vq|47---r=o0QNvgAs$smB~Rf>sU%~CZvmqAhT0g>{(u(W$ccGE z=XEV(h)03qoR(xHNiwl9IYZCg0uieL9-VN_in$n7JkEDlCIzFf$MYCrsqy2vhcvJt z%;Pc`(OiZxo@=lJoWL=pA#wU{J20yFZJ;~%(EL{kpL4TLBKiOU^>Iif-vlQso7{N>V?ccz5J|PMP_#xchIn*~ zB)&q?8o?Ok(N!Zwqk5L%l=sQXr zhBJnFtcO3RQzTjgD&$_+5AfY4Xboo!^oUPCnOAc(E`_(NL5Xwz!P=B2)FU9Z z?#_dTIP$;!X<)rYHlbPvd&G%QfqXE<>BwoI%)R)Elw}L|2uONIm6GlA$a2SK!4l4U zij*2-JW^>f-bS*OyF_=#Ph@+vV?5f>x@84UAYLL{jj;$ytxbak<(+AXbsm` z=k%DPa~`2F@cuai72Ccl;;7qqB$vkQFt5kt(Hf&Mx5v;^nbhTaj?tL8KBA~mrE(!g zY0U01?Fl6AfMu?a5E6InttJEeaB?46&yV7d#2tKDK;=31Xyx~qE?Q#`RsoNxqBT}y z{&tmOEwUadVM^IpjrrSEE@*V|6wGLiWjrQ{*7)O8qCP^#^k|LOSjgjq$|R#TUSpy9 zh@QZNG7{zljm11pDkK=E9HK(?abhW_9ibDa!x2|!PsaO{dy0{CX;QRK(O9fL;#f_n zQq!8{avmqtsR>7i;;>wOoY1yTiqu^1BRgtwq>sp#wS_3@F}AxiQDeFDqd2ND#ht3L zXnh1`OnGCDOB<(@DcP>l-wQtr#2gm-OI<2kAMtmCtpvZIgKKiS$J;K+8?*FYF>yg? zcW1grqdsXjh#F@{8Icr$Ei zF7$Sl;PCC!nHl|0ASoi%JU;^N4kJktnbD*F2_!|Nn&S@Eh<}I7&FJaJb2CeLYKzSC zBWYxjSv^v;dN}gfM1yh6nDr6=)QSX=c^T{7`7?U2{Ks6AT_TNUyDBu2$jpqmVLLv< z{4|tyi8Pw$$6}22IAfCY28FL#A4|n5{}bwnM@RJvUToIKLTwIxaqj)D5Tof4U4R1T z4ydT`MHqz`O^;>z02FTcLX$#_J&#>q&ef(*T`rqTM9fgL`Xsjtu7BnWdLALN>60JP z+sTo-vKM0Pd%TrnEA#yi}Yp-=0UUj@e_iy+56{ zZNSXj^-(LTol)B)W~Mx&ULUnGtBiZT$KVz2aK`r^e-DYTJ9xSQ)G9es`cd$CxMez8`Z<~kmq*;U4k~fyGrwCA zX#2#B;jx0k#|n(q<29bI#XR+ZihJaHD~ecE!qqIl&%D71!l&z}3e&22e!?@QWQ+mz zk^JH21GvX2ZXJoc4yKA#VtnKu@tmA7pgwY|Llg0kQy+KgHipMX#HwU`#7Kl{CPp?{ zJ<`ZY6v?cQc^JD`ZG2vnMQOu=WHjpI zUYvUP#wIGG8f+8uMyx`ZBjxfa_e-)i!>D^~G~!~*mKgQ=xJ|~3$BE60_2uQ;9NlC4 zRkVX`PICfnPozNM`@LI{dJD@l>h-a?fv~vg@Ibpthrmb}S^A~&jD|;XAEvBMM1{SAXda z@A8*0`PTMVfaJ~OT3*rJFdVAOGnyWicvEAQM5uritP+q>C8InJSj!u<8?`%jGFI36 z)d1Na2^{tJH}83D%VK)$VimCb-C%&IND+TESmSX5<0JRPyN+El#sH5zV8jSgiAL~| zC_FlkVgs>+SMj>;&^bLm=^FEmJG!#;J&J)bO}jQnG%T3nj{Q7rrg601<`ARO5W5+# zuRDpz&EZigCm#u_qk2Xz=!VbjHr=Z7jQ;fzA*!dg{B5RNFSoUMm@g0>p7=>7e2v~x$C3uG0#6Cm1orJqs}!8SQgGtSG3vO31oCzA7%KfW3ghI` z`|ZH+s1|24jHX8gax;u!9zDLtMmb3KZ24FX@Q5PI%cl0y`z` zN{jWFh>vztp3&E1I>_>jdVQpS1`r8M>bWBw;_My^U+eJercB<-@F@3pzIdDxy0h2E zH|OyriIYAr%VYNIM=t5a1_%2n&nU)-)SU~JynQ0t?kyfKR}jPWBV_bV;2DnB@M`u<~%v;dFzbX4;$pzubVH= z*z1$io#gs$PLGkSD!)JgmShBG$7JTpGxqxA{5jiRyJ}@bznncf6zM$#ONI2}61kA_DsyJSR&TGKKaQ2~P)`TV#dM*O4SIHQ#( zZs8oUiu!k9jML?O)v`RcEo{=v42)`@obp{db=j1;*JPh*@GX^4r1Z&?Irp6#A4+!zizGZHrFOw2Uu;a=nb-(zOaDz5BMA zdDk+2e^l95pfQy}x^?gO29O~*)=JKRj5epwIOuVJ(baS;zdru!>#y(jfBl=a&EWtht%C_syO1`A`ZucBuqX^#i+|e-(f-HEY?AEyZITWi$iq+L7YW*nf#8drF vE@(YAD`u@xxel-F=j7V|6876La_!vgyq7z literal 0 HcmV?d00001 diff --git a/docs/latex/ogl/ogledit.gif b/docs/latex/ogl/ogledit.gif new file mode 100644 index 0000000000000000000000000000000000000000..9784681b2d44f95979f6b95e5b699f94e115e85a GIT binary patch literal 7163 zcmVNk%w1VZ#A{0kZ%A0002L0002L0KdNg006(g0KWjgzreu2fPjGi00030 z0RR60009600RI60|NsC0A^8LW008v>EC2ui0K)-*0RRO4@W@H4y*TU5yZ>M)j$~<` zXsWJk`vJ!z&vb3yc&_h!@BhG{a7Zi~kI1BQ$!zuzu!n0(ty-_xtai)omY^}OcuX#v z&**d&EIkn3@VINH@w9CxR&d<iO*aW?8ZwSJ}#m5fGaW&^Oa58c>xijhS@X_tcx%Bw?`h3LM}XbEiWDtcTt|`PMU4LO_T5t_vZTp;{V@D{IB;OWiW34- zka+-M%}>AJ-N3l9r@f6KJ=PNn6sSI*CzC2=mh!?%7#5&zvqqEVOj`O}QolAF9QwvWoNZkc_%tqpOU2 zcjnrigA4ETnL_9adkx0?YdWhpj0kwm5FkK-0s*XM%S{{9G54`}a$_FfyS&lwz=x|} zKc_h0TLATr_6rc|Rc_8fJ%|n`Om*wm!T$EzR+<&~m22RkW!YurHOSk8h@mGNdlXjK z7fUX^*M@yF%~v0N_npRz9DD(2od9NerPf+qEw&hK6Nc9!d1Xz;TVnDEXyK0RP16#G zPyI;KRNC+*B1~|!_P~GEnZo0fP)3P}d!A5vpOt~(lnZOCQ71raQidt!nBfs)=9y^T zg65iL^0gnEYZ{p!YBB6U=AC$oDde7f?)gTaKVl_Vj&|m0=%I*Ka%7^6HtMJ)r>P<7 zq?A@_>7|(ZgA)sjWa{aspoS`{2!e5{$f&5Ms_LqembyZxti~$qthB1&stT~ys_U-2 z_Ij&d1i`=|26Vi*PDOUe7ZV1<{`TtZv(Res>$0M4P%K)<&Y^64+eYi{x8R~MEw{*V zaIG}i%F%7JBj#T*6a)n>+6hU~^G@W8u{3vhhGQj2eUab<*T zjC!?1Zo>8jOz_1RqiXQ56lb__JMA4S86EusOtHclr>rul8<(4K2KlBtGQ{*g)UM4H zudMUVmbTpC%QjaKGbAD-t8LByA{_M6JU8w17(UlqAG^gGwy)7~l#C(5_df0Q*H;)^ zLaroO4EEV*i#so{U0bWKih4vPWCmuZZTH?7a8xJL#X*{-zbCK!@GihXi+U({2&suXhdf$(TQkuA{4VC#fY^n16Cvs7Qfg-G0KdH zcqC)UxHvO9nvr#B3?v$B0w-d`k8TpX;Q@0v$1*x{h~m@Z5hsbqJ7$rLS7XK*1bwa znag4_Z+14YpnH7D0bq{LEwF&wlZa`|YPv6YhpZt>KHyC1J%gIo4Cm|CsLTyiOmY(F zrZ<}bPI0;ufY{`v2B?Sub*@v1fPAMuVMoqvmJXfKQ{5EuxzBO=p%Bez6C~P36;u>2XVQj6+o{o#27#l)limrGw4Z}~G;J6)sZ5E0 z(omk@rN)_tL#~0-v&D3#K>YzB3+Ydfu2iROFcVUVB&8t-Tx>ud9jjBJoz+aIX*qT(fut`1a$`Y&Cs517mZM+2#*fm+e zB-N=+B}Qu3h&Rr5cBY@*D=$TB3&~QH0@Ikm1Xgo7$hr2lGL0=?LmLFrngC8CJqT@q z{@YpMs+G8-wXI)oklbr5m$`~{t}kwNT^<;>x?A`yb|I==$8xW`JNPbmvmoB_KD4~E zEv|Iei-q>Occ1W$Z*)mXU-qK+zCq0|cje39{sIobc+D?#Ys=q4I{3j5jouX0VD^yoUd_n7l83Zj5y? zUmCl>zBe{zhtKd zai+}WcMdtsGd97KeVpVnr_sx3hH?ow#4dC)uFY;9q?MD3WiX#Wa&}%Ep7YH9L^yx% z&-4;jpbIx>Lc{RPhgNfr}J6eKRlQ{=Y&b6*TxoRDVdL}YX^PHJO>zi5Bz5pPHvX{;5W;^@Y&c3yy zTMdvR?^etgmG%vi4ef4w``gUcHlcrA?G(#-1apfrvcb*nc0XI(Zl?A_tesA5uVCHo z&bPkd9q&EsH`v#<_u=?G18(d4;NT`WmF3NE^$PsB3QrBfC+_WtE1BH$Hg~`u4sjwF zoZ=u~w#9GEaC(24jo$DZ& zI@rT*bsNaL-06iQ+DD-FweP#_Zf|-hsaoo}hoJ6ucemIP{C2DQ{qJ56{KN-Oc)g!| z1aTHK;1!>6ysrl9DFs2~wLJNKf1T}?*RA6>|9Er$rPeP90qRAt=+$>!eA;LC|{t!an55{`}o%?{7YrUZuA`wF`8Qh2GaU@hcC0^od`4wkE$`=lqvd zGSoGX5xXiA3zogWue9xV-~35CJ@z|31mW-70qz$(@r&PAKmK3;LzGrDsyp4Toc&B{ z{>OhgGl1HMG6M*JxW|8A0DZt05Ysn%)t6=Ww>0BdZ2PBZ_u_vp!7;LiY6p0M6sUX? zqkupIG&RS76lZYp$8L-VU}R@_6ZnB77=i&KgC;nG9+-e77=kE6gFd)_C-{4d=YRrH zbr6VoeU@%jWNI^LgFnbLPWXXIBY?PPfjBsV2PlO%_2vA zCvE{lda5@{Qv-<#Rfe>3h=|y1U^reo2XOUvc#eaD{+C#Bia2_%#&gH#iIy0OE$4^Y z^=~pKY@SFBps0$8$ck2$b>7uuv1na;NQ=>Ci^3&Oj95>*SR}pZi{UnktvD@#D0jsu zi^qtJt9XR1*ilnMhGr9MYo>rA*n>4gIkO0V191#RNQB(xfW|P6=@@+ID30w&4wVIqjiDET_BUtq)Pr?qPG19f>Ii=a zNs$A&jzxHp@YoU}r;N9ldE9i5k%%)L_=f1GkBAkH2kDOjd66uskuCX))Od^5XnSWE zfG5+9J1B$vIEyc-f&nRx8rhCtw}SDAU1DhdeGJKIIk|>v$Td&-H2pY{?r4$gD3n!c zjv0xO@0gCj_+s@(0*&-2$CK!mQ2ZwO{jyE#xtoXa$N~_ zM+saCDVBfch89?o;&+mFX;*3~jb8bcpaqwT^o+dNg^DSY3HgVl=ZK~!PRmYvMVc zq%croe0T850!xIRJ2>w56fN z>5*>aOgM`wBec_u9?plITxPl^OMdZjPapNsXGL$##x37$XtrAI)f zq2s2o)tgHNp#w3X1S+Cz3Z}ROr@>{W%2}t)iKlt$aeOK|g_==W%AMXBoNGF$wqQ+R zdTHe5V89uuaObGHaHy}Nss8vSr=WRZUW%!>woja@Pm}6%p(?62P^z)Rs^OHVpxUUa zI;9Zhs@9a0YBsAlV5_~utGV=-=%%YR5UCmEt4n64D`2eHrL4ZgtZ(M2Ea0r2C9S<$ zX1F?M!b+?_MXiqpt;wpZ+?qV$>O$9AHma(vWHqi31gxwls_MEt@5*Y(ssiy^tnP)b z@>q?ISvrG?udh|F+EcE<%BBFDJq3GA-b$|odt(Q?JObOUK;tmnl&~ovvVml>A?scbd$IP3vhCxtpkuMTH-8e#Wib0WD?78ZceDP( zvza5aFA#b)OK3ie{y8}tw0Kvv5TvwA0JI*!wAur;o+PzLaI{Zrbwi7_2}ZIgK()%_ zwGsrjF*L6wyJ}f0v}EP99U!)?im7bt16I4Xm-eZ-n?~0~w~T8}lv}wcTX1hHxtiNzoXbi2 zNuyQfx63EG!aAjOI;_HQl=69>0!n*$o2wgkwgfx71!tm}6T7YByYyF+d5d79TerHq zoV**P$7`s%3%c_JV7S|_%Zt3PtGuoIyT_Zk&wH<{i)+(+bTgWXz{|YX>%4Tsz1_R3 z-|M+j3Z?7*%Q?WSz30nZ(VM>M<+bL^Ec9!?PEe)(8=*)bzxq3^#apYCNGSqQ1o^8M z)5^c@yDIf7dZ^n11w5<{yaa@(1_ZajQE@%IHaZb}!Mj>38%(xc`#UYM04lt~EUd!s zs{|GNP#KKCK)}JN%DgR{!#d2uA?#f-Y)~^?Dexx147{lUvBOA=#0d<;B8#ezzrR4m4Byu%Uv!?lXW zvg5_JOQLU_$4Wd}X1vAVLS|}wsWPg^gsj7XD93aB$2>s99SpyP{Kzd#W{6y@;R49D zi>>|@3dx$h!v9sqeY~pgV#yO6t(m;ZrrceVtWiNMDpMB7W!Jx^9Lo!^T&b+ep}Yf( ze8X)j%d)JWwQS4o(#n^7xJ}T;yd2BFTvDjVOv!3z2VBHCkjqkR1jc;K$o$E@i*DXn zvZ<%DPc+N}3#Hb~%gId1tfw$;h<~(3XIA)RQF*m@JIdcG&f`qZ*xbL`%q<{U)Y{df6 z-Yy*6@jc7({oZ-K0(3?2X+n%*pr7+mY%c3|`GdPT@t~ly z6fB8JecmIU-jD5ZuzlKNPUe<<+h`8xecpb9{>XTq=Ta@=+L`A525#bw4%~&Vh7KCBTVY0o}`Ly(5bHKL(b~0&c%!D*o)5Sv@YDX ze(TU8ZG>&!g5K-y&7_5{=Yv?sqfNmmZR~qIqZewr$^OJb)#*9?+Rz@!;5+T2?nJcQ zE8>RN&%W(qo*K!!-`c9|WWaC3{>qze?z6nA3Ch-U?XT?a1@5lvvL5f|j$RgeqMq!o zx0df)pm6Wrf+&9JQ--eguEn_f%$O3w@f~21j zH1PkM^4F`t{BG6d-s@mU^59-@J)6uRAEd?(yE5-WmmB`F0RO@j3iQ3(*v(GLy-VxH z`S6gsZ3b&&<4e9uf1ufm?dl!!jSi<#-$_o-JT?3DZz}ZG%hnY?$b+t_Sr57CC9a3O z@*oWM{X6xUeZr1x+OB%`WBO{n%7||N_H6(4U|sa{Jokrftak57k7~rlwfDuW_!tcL z2=43$I`~n$^Y>X?m49(9|Kn4P)s!!zolm0e$Gp}`^?{DZDGjiNFRoaq_zssFo45cA)T=%!BTA@2LTuf#t4`=HOnBj0N`pZ9OB z{LByTy^r@$3Z}!)>{jmD@QUm}eEqu`q-4DP*Zv;&Urg{xFQeEGzF3<1SU#)OF9e+_ z$wMmsuND2>`}w=s@c9V=;7wZX#aVCO{RhMCcu2EE4;2AS^@U@3ekJk7bA9Lg3jq2a zHsOY70VI@(W6}A9K2Ousf#srQwW?;+`vr$9z;3AgZ336dv)KJEQst{wX?vfw;d_4n z7ZlO+B1&3g0`yB%?2t>byRyTRgd_V9L>oFJ+q?{QYn-CPn#2PYU1ilo#84f4 zZKdrat%5|IjIHhU%|x=~^(Ef9#md!9EoN^1vl-@eo{n>zOIF^BrsnpWt=#VJK90oB z&I%V-4@;L`e;={7wyHbVhR0uQ2iwnY{w055&Yp~Z{tSXB=ocjFE8R#2>{Z zQnV$nl*336BVq*U<08M1+!_k>NU7w?KuCZE!<2?4vxXc~5}cWnLm6noD(dWYvffP? zBY|=|Lx{r537?uu==l^;kXM;_9{s1WicO+5uwreabj;YLPlrGqLiTJ^wq{{{T_yD4 zO`~v$=@DCYjMKDz(dzB%SM5)`i)x}wS+{Vnuz=e>7A*Kk-l&iVFHR)4BT>beX(hEB zI5427e;!$Z3s=)9U$7rsktTXjlRYHFyYsmheiTB{4h9%Ba=b^M8PS z^|6~OFS`B~+Ao6w#k0@70|!({9|qxQPr(NX^l3sd5`1kz3!ykr!}B7{aKnT4^AN%R z0KBh65sOGqMH7$VD#R5H`p(7fFx+m&5#O-!#o=PiQAZk&>+!}Df#gg`3I|bgloN}C zsK_RFs7p#CVMNlrDQR48%L|{>E=e!_k;qCPNkLJm_-l$G0}4#Wt6}9Dvbh1F)@7y6iOjQQ_^fc z<FY>pRbqdyS( z}_}Ck-2h-X+k!{O!$0|9th+C!UKK zn5QATzx&0aaIK+de|`P)=YN0y`LAE%;3tCzAi!{RaY5GZ7rp;AuzwG9U<4ufIxg7H zAz3J(0n?_a0E&-y(wm?JMHoU7j?jS}ykGqECcl(%upMe03*dh-#m<+X=%kHyPl;+Po6F5btG zheTu|6}d=8Hqw!ggrxHzIY~-Z(vp|NWF|EkIx)7ycIZImhEs(dwWiEBOOJ4TUm%jvNFoiixViwbw$3$i_0T2NI06Rl2pX2}l literal 0 HcmV?d00001 diff --git a/docs/latex/ogl/sample.tex b/docs/latex/ogl/sample.tex new file mode 100644 index 0000000000..4e0a437d39 --- /dev/null +++ b/docs/latex/ogl/sample.tex @@ -0,0 +1,87 @@ +\chapter{OGLEdit: a sample OGL application}\label{ogledit}% +\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}% +\setfooter{\thepage}{}{}{}{}{\thepage} + +OGLEdit is a sample OGL application that allows the user to draw, edit, +save and load a few shapes. It should clarify aspects of OGL usage, and +can act as a template for similar applications. OGLEdit can be found in\rtfsp +{\tt samples/ogledit} in the OGL distribution. + +$$\image{10cm;0cm}{ogledit.eps}$$\par + +The wxWindows document/view model has been used in OGL, to reduce the amount of +housekeeping logic required to get it up and running. OGLEdit also provides +a demonstration of the Undo/Redo capability supported by the document/view classes, +and how a typical application might implement this feature. + +\section{OGLEdit files} + +OGLEdit comprises the following source files. + +\begin{itemize}\itemsep=0pt +\item doc.h, doc.cpp: MyDiagram, DiagramDocument, DiagramCommand, MyEvtHandler +classes related to diagram functionality and documents. +\item view.h, view.cpp: MyCanvas, DiagramView classes related to visualisation of +the diagram. +\item ogledit.h, ogledit.cpp: MyFrame, MyApp classes related to the overall application. +\item palette.h, palette.cpp: EditorToolPalette implementing the shape palette. +\end{itemize} + +\section{How OGLEdit works} + +OGLEdit defines a DiagramDocument class, each of instance of which holds a MyDiagram +member which itself contains the shapes. + +In order to implement specific mouse behaviour for shapes, a class MyEvtHandler is +defined which is `plugged into' each shape when it is created, instead of overriding each shape class +individually. This event handler class also holds a label string. + +The DiagramCommand class is the key to implementing Undo/Redo. Each instance of DiagramCommand +stores enough information about an operation (create, delete, change colour etc.) to allow +it to carry out (or undo) its command. In DiagramView::OnMenuCommand, when the user initiates the +command, a new DiagramCommand instance is created which is then sent to the document's +command processor (see wxWindows manual for more information about doc/view and command +processing). + +Apart from menu commands, another way commands are initiated is by the user left-clicking on +the canvas or right-dragging on a node. MyCanvas::OnLeftClick in view.cpp shows how +the appropriate wxClassInfo is passed to a DiagramCommand, to allow DiagramCommand::Do +to create a new shape given the wxClassInfo. + +The MyEvtHandler right-drag methods in doc.cpp implement drawing a line between +two shapes, detecting where the right mouse button was released and looking for a second +shape. Again, a new DiagramCommand instance is created and passed to the command +processor to carry out the command. + +DiagramCommand::Do and DiagramCommand::Undo embody much of the +interesting interaction with the OGL library. A complication of note +when implementing undo is the problem of deleting a node shape which has +one or more arcs attached to it. If you delete the node, the arc(s) +should be deleted too. But multiple arc deletion represents more information +that can be incorporated in the existing DiagramCommand scheme. OGLEdit +copes with this by treating each arc deletion as a separate command, and +sending Cut commands recursively, providing an undo path. Undoing such a +Cut will only undo one command at a time - not a one to one +correspondence with the original command - but it's a reasonable +compromise and preserves Do/Undo whilst keeping our DiagramCommand class +simple. + +\section{Possible enhancements} + +OGLEdit is very simplistic and does not employ the more advanced features +of OGL, such as: + +\begin{itemize}\itemsep=0pt +\item attachment points (arcs are drawn to particular points on a shape) +\item metafile and bitmaps shapes +\item divided rectangles +\item composite shapes, and constraints +\item creating labels in shape regions +\item arc labels (OGL has support for three movable labels per arc) +\item spline and multiple-segment line arcs +\item adding annotations to node and arc shapes +\item line-straightening (supported by OGL) and alignment (not supported directly by OGL) +\end{itemize} + +These could be added to OGLEdit, at the risk of making it a less +useful example for beginners. diff --git a/docs/latex/ogl/tex2rtf.ini b/docs/latex/ogl/tex2rtf.ini new file mode 100644 index 0000000000..41dd2cffa3 --- /dev/null +++ b/docs/latex/ogl/tex2rtf.ini @@ -0,0 +1,35 @@ +; Last change: JS 8 Sep 98 2:54 pm +runTwice = yes +titleFontSize = 12 +authorFontSize = 10 +chapterFontSize = 12 +sectionFontSize = 12 +subsectionFontSize = 12 +headerRule = yes +footerRule = yes +useHeadingStyles = yes +listItemIndent=40 +generateHPJ = no +htmlBrowseButtons = bitmap +winHelpVersion = 3 +winHelpContents = yes +winHelpTitle = "OGL Manual" +truncateFilenames = yes +combineSubSections = yes +\overview [2] {\rtfonly{See also }\settransparency{on}\sethotspotcolour{off}\sethotspotunderline{on}\winhelponly{\image{}{books.bmp}\settransparency{off}} +\htmlonly{\image{}{books.gif}}\helpref{#1}{#2} +\sethotspotcolour{on}\sethotspotunderline{on}} +\docparam [2]{\parskip{0}{\it #1}\htmlignore{\par}\parskip{10}\indented{1cm}{#2}} +\wxheading [1]{{\bf \htmlignore{\fcol{blue}{#1}}\htmlonly{\fcol{red}{#1}}}} +\const [0] {{\bf const}} +\constfunc [3] {{\bf #1} {\bf #2}(#3) {\bf const}\index{#2}} +\windowstyle [1] {{\bf #1}\index{#1}} + +;; +;; These two are for generating MS HTML Help project, contents and index files. +;; +htmlWorkshopFiles = true +htmlIndex = true +\pythonnote [1] {{\bf \fcol{blue}{wxPython note:}} #1} +%\pythonnote [1] {} + diff --git a/docs/latex/ogl/texhelp.sty b/docs/latex/ogl/texhelp.sty new file mode 100644 index 0000000000..af91bd531d --- /dev/null +++ b/docs/latex/ogl/texhelp.sty @@ -0,0 +1,298 @@ +% LaTeX style file +% Name: texhelp.sty +% Author: Julian Smart +% +% Purpose +% ------- +% Style file to enable the simultaneous preparation of printed LaTeX and on-line +% hypertext manuals. +% Use in conjunction with Tex2RTF (see Tex2RTF documentation). +% +% Note that if a non-ASCII character starts a newline and there should be a space +% between the last word on the previous line and the first word on this line, +% you need to use \rtfsp to generate a space in Windows Help. \rtfsp is ignored +% in all other formats. +% +% Julian Smart +% Artificial Intelligence Applications Institute +% +% +% ============== C++/CLIPS Documentation Facilities ============== +% +% Each class definition should be typeset with e.g. +% +% \section{\class{Name}: Parent} +% +% followed by a description of the class. +% Each member should follow: +% +% \membersection{wxName::Member} +% +% with a description of what this member does. +% Then, one (or more if overloaded) member (function) in detail: +% +% \func{return type}{name}{args} +% or +% \member{type}{name} +% +% where args is a list of \param{type}{name}, ... + +% Function, e.g. +% e.g. to typeset +% +% void DoIt(char *string); +% +% write: +% +% \func{void}{DoIt}{\param{char *}{string}} +% + +\newcommand{\func}[3]{\hangafter=1\noindent\hangindent=10mm +{{\it #1} {\bf #2}\index{#2}}(#3)} + +% For function/type definition where the name is a pointer, +% e.g. to typeset +% +% typedef void (*wxFunction)(wxObject&) +% +% write: +% +% \pfunc{typedef void}{wxFunction}{param{wxObject&}} + +\newcommand{\pfunc}[3]{\hangafter=1\noindent\hangindent=10mm +{{\it #1} ({\bf *#2})\index{#2}}(#3)} + +% Use an ordinary \section command for class name definitions. + +% This is used for a member, such as wxBitmap: GetDepth +\newcommand{\membersection}[1]{\subsection*{#1}\index{#1}} + +% CLIPS function +\newcommand{\clipsfunc}[3]{\hangafter=1\noindent\hangindent=10mm +{{\bf #1} ({\bf #2}\index{#2}}#3)} + +\newcommand{\clipssection}[1]{\chapter{#1}} + +% This is used for a CLIPS function name +\newcommand{\functionsection}[1]{\subsection*{#1}} + +% Member: a type and a name +\newcommand{\member}[2]{{\bf #1 \it #2}} + +% C++ Parameter: a type and a name (no intervening space) +\newcommand{\param}[2]{{\it #1}{\bf #2}} + +% CLIPS Parameter: a type and a name (one intervening space) +\newcommand{\cparam}[2]{{\bf #1} {\it #2}} + +% Class: puts in index +\newcommand{\class}[1]{#1\index{#1}} + +%\newcommand{\docparam}[2]{\parskip=0pt {\it #1}\par\parskip=10pt\begin{indented}{1cm}{#2}\end{indented}} + +% Void type +\newcommand{\void}{{\it void}} + +% Typeset destructor +\newcommand{\destruct}[1]{{$\sim$}#1} + +% Typeset insert/extract operators +\newcommand{\cinsert}{$<<$} +\newcommand{\cextract}{$>>$} + + +% =================== Hypertext facilities =================== +% +% To insert hyperlinks (or references, in Latex), \label the sections +% or membersections \label{ref-label} immediately after the section, on the same line, +% and use \helpref{text-to-show}{ref-label} to make a reference. +% + +% Type text with section reference +\newcommand{\helpref}[2]{{\it #1} (p.\ \pageref{#2}) } + +% Type text with URL in verbatim mode +\newcommand{\urlref}[2]{#1 (\verb$#2$)} + +% Don't typeset section number in LaTeX +\newcommand{\helprefn}[2]{{\it #1}} + +% Like helpref, but popup text in WinHelp instead of hyperlinked +\newcommand{\popref}[2]{{\it #1}} + +% Like footnote, but popup text. +\newcommand{\footnotepopup}[2]{{\it #1}\footnote{#2}} + +% =================== On-line help specific macros =================== +% + +% Global document font size/family, help only. +\newcommand{\helpfontsize}[1]{} +\newcommand{\helpfontfamily}[1]{} + +% Ignore in all on-line help +\newcommand{\helpignore}[1]{#1} +% Only print in all on-line help +\newcommand{\helponly}[1]{} + +% Ignore in LaTeX +\newcommand{\latexignore}[1]{} +% Only print in LaTeX +\newcommand{\latexonly}[1]{#1} + +% Ignore in linear RTF +\newcommand{\rtfignore}[1]{#1} +% Only print in linear RTF +\newcommand{\rtfonly}[1]{} + +% Ignore in WinHelp RTF +\newcommand{\winhelpignore}[1]{#1} +% Only print in WinHelp RTF +\newcommand{\winhelponly}[1]{} + +% Ignore in wxHelp +\newcommand{\xlpignore}[1]{#1} +% Only print in wxHelp +\newcommand{\xlponly}[1]{} + +% Ignore in HTML +\newcommand{\htmlignore}[1]{#1} +% Only print in HTML +\newcommand{\htmlonly}[1]{} + +% Input a file only for help system (binder thickness is not a limitation +% in help systems!) +\newcommand{\helpinput}[1]{} + +\newcommand{\rtfsp}{ } % Force a space in RTF, ignore in Latex + +% =================== Miscellaneous macros =================== +% +% Headings consistent with generated ones +\newcommand{\myheading}[1]{\vspace*{25pt} +\begin{flushleft} +{\LARGE \bf #1} +\end{flushleft} +\vskip 20pt +} + +% Heading with entry in contents page. +\newcommand{\chapterheading}[1]{\myheading{#1} +\addcontentsline{toc}{chapter}{#1}} + +\newcommand{\sectionheading}[1]{\myheading{#1} +\addcontentsline{toc}{section}{#1}} + +% Glossary environment +\newenvironment{helpglossary}{\newpage\chapterheading{Glossary}\begin{description}}{\end{description}} + +% Glossary entry +\newcommand{\gloss}[1]{\item[#1]\index{#1}} + +% Image: EPS in Latex, BMP or MF (whatever's available) in RTF. Requires psbox. +\newcommand{\image}[2]{\psboxto(#1){#2}} + +% Image, left aligned (HTML) +\newcommand{\imager}[2]{\psboxto(#1){#2}} + +% Image, right aligned (HTML) +\newcommand{\imagel}[2]{\psboxto(#1){#2}} + +% Imagemap: principally for HTML only. In Latex, +% acts like \image. +\newcommand{\imagemap}[3]{\psboxto(#1){#2}} + +% Headers and footers +% \setheader{EvenPageLeft}{EvenPageCentre}{EvenPageRight} +% {OddPageLeft}{OddPageCentre}{OddPageRight} +\newcommand{\setheader}[6]{ +\lhead[\fancyplain{}{#1}]{\fancyplain{}{#4}} +\chead[\fancyplain{}{#2}]{\fancyplain{}{#5}} +\rhead[\fancyplain{}{#3}]{\fancyplain{}{#6}} +} + +% \setfooter{EvenPageLeft}{EvenPageCentre}{EvenPageRight} +% {OddPageLeft}{OddPageCentre}{OddPageRight} +\newcommand{\setfooter}[6]{ +\lfoot[\fancyplain{#1}{#1}]{\fancyplain{#4}{#4}} +\cfoot[\fancyplain{#2}{#2}]{\fancyplain{#5}{#5}} +\rfoot[\fancyplain{#3}{#3}]{\fancyplain{#6}{#6}} +} + +% Needed for telling RTF where margin paragraph should go +% in mirrored margins mode. +\newcommand{\marginpareven}[1]{\hspace*{0pt}\marginpar{#1}} +\newcommand{\marginparodd}[1]{\hspace*{0pt}\marginpar{#1}} + +% Environment for two-column table popular in WinHelp and manuals. +\newcommand{\twocolwidtha}[1]{\def\twocolwidthaval{#1}} +\newcommand{\twocolwidthb}[1]{\def\twocolwidthbval{#1}} +\newcommand{\twocolspacing}[1]{\def\twocolspacingval{#1}} + +\twocolwidtha{3cm} +\twocolwidthb{8.5cm} +\twocolspacing{2} + +\newcommand{\twocolitem}[2]{#1 & #2\\} +\newcommand{\twocolitemruled}[2]{#1 & #2\\\hline} + +\newenvironment{twocollist}{\renewcommand{\arraystretch}{\twocolspacingval}\begin{tabular}{lp{\twocolwidthbval}}}% +{\end{tabular}\renewcommand{\arraystretch}{1}} + +% Specifying table rows for RTF compatibility +\newcommand{\row}[1]{#1\\} + +% Use for the last ruled row for correct RTF generation. +\newcommand{\ruledrow}[1]{#1\\\hline} + +% Indentation environment. Arg1 is left margin size +\newenvironment{indented}[1]{\begin{list}{}{\leftmargin=#1}\item[]}% +{\end{list}} + +% Framed box of text, normal formatting. +\newcommand{\normalbox}[1]{\fbox{\vbox{#1}}} +% Double-framed box of text. +\newcommand{\normalboxd}[1]{\fbox{\fbox{\vbox{#1}}}} + +% WITHDRAWN -- can't do in RTF, easily. +% Framed box of text, horizontally centred. Ragged right within box. +% \newcommand{\centeredbox}[2]{\begin{center}\fbox{\parbox{#1}{\raggedright#2}}\end{center}} +% Double-framed box of text, horizontally centred. Ragged right within box. +% \newcommand{\centeredboxd}[2]{\begin{center}\fbox{\fbox{\parbox{#1}{\raggedright#2}}}\end{center}} + +% toocomplex environment: simply prints the argument in LaTeX, +% comes out verbatim in all generated formats. +\newenvironment{toocomplex}{}{} + +% Colour: dummy commands since LaTeX doesn't support colour. +% \definecolour{name}{red}{blue}{green} +% \fcol{name}{text} ; Foreground +% \bcol{name}{text} ; Background +\newcommand{\definecolour}[4]{} +\newcommand{\definecolor}[4]{} +\newcommand{\fcol}[2]{#2} +\newcommand{\bcol}[2]{#2} +\newcommand{\sethotspotcolour}[1]{} +\newcommand{\sethotspotunderline}[1]{} +\newcommand{\settransparency}[1]{} +\newcommand{\backslashraw}[0]{} +\newcommand{\lbraceraw}[0]{} +\newcommand{\rbraceraw}[0]{} +\newcommand{\registered}[0]{(r)} +\newcommand{\background}[1]{} +\newcommand{\textcolour}[1]{} +\newcommand{\overview}[2]{See \helpref{#1}{#2}.} +\newcommand{\docparam}[2]{{\it #1}\begin{list}{}{\leftmargin=1cm}\item[] +#2% +\end{list}} +\newcommand{\wxheading}[1]{{\bf #1}} +\newcommand{\const}[0]{{\bf const}} +\newcommand{\constfunc}[3]{{\bf #1} {\bf #2}(#3) {\bf const}\index{#2}} +\newcommand{\windowstyle}[1]{{\bf #1}\index{#1}} + +\addtolength{\textwidth}{1in} +\addtolength{\oddsidemargin}{-0.5in} +\addtolength{\topmargin}{-0.5in} +\addtolength{\textheight}{1in} +\sloppy + diff --git a/docs/latex/ogl/topics.tex b/docs/latex/ogl/topics.tex new file mode 100644 index 0000000000..ece8016fce --- /dev/null +++ b/docs/latex/ogl/topics.tex @@ -0,0 +1,161 @@ +\chapter{Topic overviews} +\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}% +\setfooter{\thepage}{}{}{}{}{\thepage} + +The following sections describe particular topics. + +\section{OGL overview}\label{ogloverview} + +\helpref{wxShapeCanvas}{wxshapecanvas}, derived from {\bf wxCanvas}, is the drawing area +for a number of \helpref{wxShape}{wxshape} instances. Everything drawn on a +wxShapeCanvas is derived from wxShape, which provides virtual +member functions for redrawing, creating and destroying +resize/selection `handles', movement and erasing behaviour, mouse +click behaviour, calculating the bounding box of the shape, linking +nodes with arcs, and so on. + +The way a client application copes with `damage' to the canvas is to +erase (white out) anything should no longer be displayed, redraw the shape, +and then redraw everything on the canvas to repair any damage. If quick edit +mode is on for the canvas, the complete should be omitted by OGL and the +application. + +Selection handles (called control points in the code) are implemented as +wxRectangleShapes. + +Events are passed to shapes by the canvas in a high-level form, for example {\bf OnLeftClick}, +{\bf OnBeginDragLeft}, {\bf OnDragLeft}, {\bf OnEndDragLeft}. The canvas decides +what is a click and what is a drag, whether it is on a shape or the canvas itself, +and (by interrogating the shape) which attachment point the click is associated with. + +In order to provide event-handling flexibility, each shapes has an `event handler' associated with it, +which by default is the shape itself (all shapes derive from wxShapeEvtHandler). +An application can modify the event-handling behaviour simply by plugging a new +event handler into the shape. This can avoid the need for multiple inheritance when +new properties and behaviour are required for a number of different shape classes: instead +of overriding each class, one new event handler class can be defined and used for all +existing shape classes. + +A range of shapes have been predefined in the library, including rectangles, ellipses, +polygons. A client application can derive from these shapes and/or derive entirely +new shapes from wxShape. + +Instances of a class called \helpref{wxDiagram}{wxdiagram} organise collections of +shapes, providing default file input and output behaviour. + +\section{wxDividedShape overview}\label{dividedshapeoverview} + +Classes: \helpref{wxDividedShape}{wxdividedshape} + +A wxDividedShape is a rectangle with a number of vertical divisions. Each +division may have its text formatted with independent characteristics, and +the size of each division relative to the whole image may be specified. + +Once a wxDividedShape has been created, the user may move the divisions with the +mouse. By pressing Ctrl while right-clicking, the region attributes can be edited. + +Here are examples of creating wxDividedShape objects: + +{\small +\begin{verbatim} + /* + * Divided rectangle with 3 regions + * + */ + + wxDividedShape *dividedRect = new wxDividedShape(50, 60); + + wxShapeRegion *region = new wxShapeRegion; + region->SetProportions(0.0, 0.25); + dividedRect->AddRegion(region); + + region = new wxShapeRegion; + region->SetProportions(0.0, 0.5); + dividedRect->AddRegion(region); + + region = new wxShapeRegion; + region->SetProportions(0.0, 0.25); + dividedRect->AddRegion(region); + + dividedRect->SetSize(50, 60); // Allow it to calculate region sizes + dividedRect->SetPen(wxBLACK_PEN); + dividedRect->SetBrush(wxWHITE_BRUSH); + dividedRect->Show(TRUE); + dividedRect->NameRegions(); + + /* + * Divided rectangle with 3 regions, rounded + * + */ + + wxDividedShape *dividedRect3 = new wxDividedShape(50, 60); + dividedRect3->SetCornerRadius(-0.4); + + region = new wxShapeRegion; + region->SetProportions(0.0, 0.25); + dividedRect3->AddRegion(region); + + region = new wxShapeRegion; + region->SetProportions(0.0, 0.5); + dividedRect3->AddRegion(region); + + region = new wxShapeRegion; + region->SetProportions(0.0, 0.25); + dividedRect3->AddRegion(region); + + dividedRect3->SetSize(50, 60); // Allow it to calculate region sizes + dividedRect3->SetPen(wxBLACK_PEN); + dividedRect3->SetBrush(wxWHITE_BRUSH); + dividedRect3->Show(TRUE); + dividedRect3->NameRegions(); +\end{verbatim} +} + +\section{wxCompositeShape overview}\label{compositeshapeoverview} + +Classes: \helpref{wxCompositeShape}{wxcompositeshape}, \helpref{wxOGLConstraint}{wxoglconstraint} + +The wxCompositeShape allows fairly complex shapes to be created, and maintains +a set of constraints which specify the layout and proportions of child shapes. + +Add child shapes to a wxCompositeShape using \helpref{AddChild}{wxcompositeshapeaddchild}, and +add constraints using \helpref{AddConstraint}{wxcompositeshapeaddconstraint}. + +After children and shapes have been added, call \helpref{Recompute}{wxcompositeshaperecompute} which +will return TRUE is the constraints could be satisfied, FALSE otherwise. If +constraints have been correctly and consistently specified, this call will succeed. + +If there is more than one child, constraints must be specified: OGL cannot calculate +the size and position of children otherwise. Don't assume that children will simply +move relative to the parent without the use of constraints. + +To specify a constraint, you need three things: + +\begin{enumerate}\itemsep=0pt +\item a constraint type, such as gyCONSTRAINT\_CENTRED\_VERTICALLY; +\item a reference shape, with respect to which other shapes are going to be positioned - the\rtfsp +{\it constraining} shape; +\item a list of one or more shapes to be constrained: the {\it constrained} shapes. +\end{enumerate} + +The constraining shape can be either the parent of the constrained shapes, or a sibling. The +constrained shapes must all be siblings of each other. + +For an exhaustive list and description of the available constraint types, see the \helpref{wxOGLConstraint constructor}{wxoglconstraintconstr}. +Note that most constraints operate in one dimension only (vertically or horizontally), so you will +usually need to specify constraints in pairs. + +You can set the spacing between constraining and constrained shapes by +calling \helpref{wxOGLConstraint::SetSpacing}{wxoglconstraintsetspacing}. + +Finally, a wxCompositeShape can have {\it divisions}, which are special child shapes of class +wxDivisionShape (not to be confused with wxDividedShape). The purpose of this is to allow +the composite to be divided into user-adjustable regions (divisions) into which other shapes +can be dropped dynamically, given suitable application code. Divisons allow the child +shapes to have an identity of their own - they can be manipulated independently of their container - +but to behave as if they are contained with the division, moving with the parent shape. +Divisions boundaries can themselves be moved using the mouse. + +To create an initial division, call \helpref{wxCompositeShape::MakeContainer}{wxcompositeshapemakecontainer}. +Make further divisions by calling \helpref{wxDivisionShape::Divide}{wxdivisionshapedivide}. + diff --git a/docs/latex/ogl/up.gif b/docs/latex/ogl/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---------<- shoulder2 + // | | | | |<- stem + // <- branching attachment point N-1 + + // This function gets the root point at the given attachment. + virtual wxRealPoint GetBranchingAttachmentRoot(int attachment); + + // This function gets information about where branching connections go (calls GetBranchingAttachmentRoot) + virtual bool GetBranchingAttachmentInfo(int attachment, wxRealPoint& root, wxRealPoint& neck, + wxRealPoint& shoulder1, wxRealPoint& shoulder2); + + // n is the number of the adjoining line, from 0 to N-1 where N is the number of lines + // at this attachment point. + // attachmentPoint is where the arc meets the stem, and stemPoint is where the stem meets the + // shoulder. + virtual bool GetBranchingAttachmentPoint(int attachment, int n, wxRealPoint& attachmentPoint, + wxRealPoint& stemPoint); + + // Get the number of lines at this attachment position. + virtual int GetAttachmentLineCount(int attachment) const; + + // Draw the branches (not the actual arcs though) + virtual void OnDrawBranches(wxDC& dc, int attachment, bool erase = FALSE); + virtual void OnDrawBranches(wxDC& dc, bool erase = FALSE); + + // Branching attachment settings + inline void SetBranchNeckLength(int len) { m_branchNeckLength = len; } + inline int GetBranchNeckLength() const { return m_branchNeckLength; } + + inline void SetBranchStemLength(int len) { m_branchStemLength = len; } + inline int GetBranchStemLength() const { return m_branchStemLength; } + + inline void SetBranchSpacing(int len) { m_branchSpacing = len; } + inline int GetBranchSpacing() const { return m_branchSpacing; } + + // Further detail on branching style, e.g. blobs on interconnections + inline void SetBranchStyle(long style) { m_branchStyle = style; } + inline long GetBranchStyle() const { return m_branchStyle; } + + // Rotate the standard attachment point from physical (0 is always North) + // to logical (0 -> 1 if rotated by 90 degrees) + virtual int PhysicalToLogicalAttachment(int physicalAttachment) const; + + // Rotate the standard attachment point from logical + // to physical (0 is always North) + virtual int LogicalToPhysicalAttachment(int logicalAttachment) const; + + // This is really to distinguish between lines and other images. + // For lines, want to pass drag to canvas, since lines tend to prevent + // dragging on a canvas (they get in the way.) + virtual bool Draggable() const { return TRUE; } + + // Returns TRUE if image is a descendant of this image + bool HasDescendant(wxShape *image); + + // Creates a copy of this shape. + wxShape *CreateNewCopy(bool resetMapping = TRUE, bool recompute = TRUE); + + // Does the copying for this object + virtual void Copy(wxShape& copy); + + // Does the copying for this object, including copying event + // handler data if any. Calls the virtual Copy function. + void CopyWithHandler(wxShape& copy); + + // Rotate about the given axis by the given amount in radians. + virtual void Rotate(double x, double y, double theta); + virtual inline double GetRotation() const { return m_rotation; } + + void ClearAttachments(); + + // Recentres all the text regions for this object + void Recentre(wxDC& dc); + + // Clears points from a list of wxRealPoints + void ClearPointList(wxList& list); + + private: + wxObject* m_clientData; + + protected: + wxShapeEvtHandler* m_eventHandler; + bool m_formatted; + double m_xpos, m_ypos; + wxPen* m_pen; + wxBrush* m_brush; + wxFont* m_font; + wxColour* m_textColour; + wxString m_textColourName; + wxShapeCanvas* m_canvas; + wxList m_lines; + wxList m_text; + wxList m_controlPoints; + wxList m_regions; + wxList m_attachmentPoints; + bool m_visible; + bool m_disableLabel; + long m_id; + bool m_selected; + bool m_highlighted; // Different from selected: user-defined highlighting, + // e.g. thick border. + double m_rotation; + int m_sensitivity; + bool m_draggable; + int m_attachmentMode; // 0 for no attachments, 1 if using normal attachments, + // 2 for branching attachments + bool m_spaceAttachments; // TRUE if lines at one side should be spaced + bool m_fixedWidth; + bool m_fixedHeight; + bool m_centreResize; // Default is to resize keeping the centre constant (TRUE) + bool m_drawHandles; // Don't draw handles if FALSE, usually TRUE + wxList m_children; // In case it's composite + wxShape* m_parent; // In case it's a child + int m_formatMode; + int m_shadowMode; + wxBrush* m_shadowBrush; + int m_shadowOffsetX; + int m_shadowOffsetY; + int m_textMarginX; // Gap between text and border + int m_textMarginY; + wxString m_regionName; + bool m_maintainAspectRatio; + int m_branchNeckLength; + int m_branchStemLength; + int m_branchSpacing; + long m_branchStyle; +}; + +class wxPolygonShape: public wxShape +{ + DECLARE_DYNAMIC_CLASS(wxPolygonShape) + public: + wxPolygonShape(); + ~wxPolygonShape(); + + // Takes a list of wxRealPoints; each point is an OFFSET from the centre. + // Deletes user's points in destructor. + virtual void Create(wxList *points); + virtual void ClearPoints(); + + void GetBoundingBoxMin(double *w, double *h); + void CalculateBoundingBox(); + bool GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3); + bool HitTest(double x, double y, int *attachment, double *distance); + void SetSize(double x, double y, bool recursive = TRUE); + void OnDraw(wxDC& dc); + void OnDrawOutline(wxDC& dc, double x, double y, double w, double h); + + // Control points ('handles') redirect control to the actual shape, to make it easier + // to override sizing behaviour. + virtual void OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys=0, int attachment = 0); + virtual void OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys=0, int attachment = 0); + virtual void OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys=0, int attachment = 0); + + // A polygon should have a control point at each vertex, + // with the option of moving the control points individually + // to change the shape. + void MakeControlPoints(); + void ResetControlPoints(); + + // If we've changed the shape, must make the original + // points match the working points + void UpdateOriginalPoints(); + + // Add a control point after the given point + virtual void AddPolygonPoint(int pos = 0); + + // Delete a control point + virtual void DeletePolygonPoint(int pos = 0); + + // Recalculates the centre of the polygon + virtual void CalculatePolygonCentre(); + +#ifdef PROLOGIO + void WriteAttributes(wxExpr *clause); + void ReadAttributes(wxExpr *clause); +#endif + + int GetNumberOfAttachments() const; + bool GetAttachmentPosition(int attachment, double *x, double *y, + int nth = 0, int no_arcs = 1, wxLineShape *line = NULL); + bool AttachmentIsValid(int attachment); + // Does the copying for this object + void Copy(wxShape& copy); + + inline wxList *GetPoints() { return m_points; } + + // Rotate about the given axis by the given amount in radians + virtual void Rotate(double x, double y, double theta); + + private: + wxList* m_points; + wxList* m_originalPoints; + double m_boundWidth; + double m_boundHeight; + double m_originalWidth; + double m_originalHeight; +}; + +class wxRectangleShape: public wxShape +{ + DECLARE_DYNAMIC_CLASS(wxRectangleShape) + public: + wxRectangleShape(double w = 0.0, double h = 0.0); + void GetBoundingBoxMin(double *w, double *h); + bool GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3); + void OnDraw(wxDC& dc); + void SetSize(double x, double y, bool recursive = TRUE); + void SetCornerRadius(double rad); // If > 0, rounded corners + +#ifdef PROLOGIO + void WriteAttributes(wxExpr *clause); + void ReadAttributes(wxExpr *clause); +#endif + + int GetNumberOfAttachments() const; + bool GetAttachmentPosition(int attachment, double *x, double *y, + int nth = 0, int no_arcs = 1, wxLineShape *line = NULL); + // Does the copying for this object + void Copy(wxShape& copy); + + inline double GetWidth() const { return m_width; } + inline double GetHeight() const { return m_height; } + inline void SetWidth(double w) { m_width = w; } + inline void SetHeight(double h) { m_height = h; } + +protected: + double m_width; + double m_height; + double m_cornerRadius; +}; + +class wxTextShape: public wxRectangleShape +{ + DECLARE_DYNAMIC_CLASS(wxTextShape) + public: + wxTextShape(double width = 0.0, double height = 0.0); + + void OnDraw(wxDC& dc); + +#ifdef PROLOGIO + void WriteAttributes(wxExpr *clause); +#endif + + // Does the copying for this object + void Copy(wxShape& copy); +}; + +class wxEllipseShape: public wxShape +{ + DECLARE_DYNAMIC_CLASS(wxEllipseShape) + public: + wxEllipseShape(double w = 0.0, double h = 0.0); + + void GetBoundingBoxMin(double *w, double *h); + bool GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3); + + void OnDraw(wxDC& dc); + void SetSize(double x, double y, bool recursive = TRUE); + +#ifdef PROLOGIO + void WriteAttributes(wxExpr *clause); + void ReadAttributes(wxExpr *clause); +#endif + + int GetNumberOfAttachments() const; + bool GetAttachmentPosition(int attachment, double *x, double *y, + int nth = 0, int no_arcs = 1, wxLineShape *line = NULL); + + // Does the copying for this object + void Copy(wxShape& copy); + + inline double GetWidth() const { return m_width; } + inline double GetHeight() const { return m_height; } + + inline void SetWidth(double w) { m_width = w; } + inline void SetHeight(double h) { m_height = h; } + +protected: + double m_width; + double m_height; +}; + +class wxCircleShape: public wxEllipseShape +{ + DECLARE_DYNAMIC_CLASS(wxCircleShape) + public: + wxCircleShape(double w = 0.0); + + bool GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3); + // Does the copying for this object + void Copy(wxShape& copy); +}; + +#endif + // _OGL_BASIC_H_ diff --git a/include/wx/ogl/basicp.h b/include/wx/ogl/basicp.h new file mode 100644 index 0000000000..aa1067764f --- /dev/null +++ b/include/wx/ogl/basicp.h @@ -0,0 +1,223 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: basicp.h +// Purpose: Private OGL classes and definitions +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_BASICP_H_ +#define _OGL_BASICP_H_ + +#ifdef __GNUG__ +#pragma interface "basicp.h" +#endif + +#define CONTROL_POINT_SIZE 6 + +class wxShapeTextLine: public wxObject +{ + DECLARE_DYNAMIC_CLASS(wxShapeTextLine) +public: + wxShapeTextLine(double the_x = 0.0, double the_y = 0.0, const wxString& the_line = ""); + ~wxShapeTextLine(); + + inline double GetX() const { return m_x; } + inline double GetY() const { return m_y; } + + inline void SetX(double x) { m_x = x; } + inline void SetY(double y) { m_y = y; } + + inline void SetText(const wxString& text) { m_line = text; } + inline wxString GetText() const { return m_line; } + +protected: + wxString m_line; + double m_x; + double m_y; +}; + +class wxShape; +class wxControlPoint: public wxRectangleShape +{ + DECLARE_DYNAMIC_CLASS(wxControlPoint) + + friend class wxShapeEvtHandler; + friend class wxShape; + + public: + wxControlPoint(wxShapeCanvas *the_canvas = NULL, wxShape *object = NULL, double size = 0.0, double the_xoffset = 0.0, + double the_yoffset = 0.0, int the_type = 0); + ~wxControlPoint(); + + void OnDraw(wxDC& dc); + void OnErase(wxDC& dc); + void OnDrawContents(wxDC& dc); + 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); + + bool GetAttachmentPosition(int attachment, double *x, double *y, + int nth = 0, int no_arcs = 1, wxLineShape *line = NULL); + int GetNumberOfAttachments() const; + + inline void SetEraseObject(bool er) { m_eraseObject = er; } + +public: + int m_type; + double m_xoffset; + double m_yoffset; + wxShape* m_shape; + wxCursor* m_oldCursor; + bool m_eraseObject; // If TRUE, erases object before dragging handle. + +/* + * Store original top-left, bottom-right coordinates + * in case we're doing non-vertical resizing. + */ + static double sm_controlPointDragStartX; + static double sm_controlPointDragStartY; + static double sm_controlPointDragStartWidth; + static double sm_controlPointDragStartHeight; + static double sm_controlPointDragEndWidth; + static double sm_controlPointDragEndHeight; + static double sm_controlPointDragPosX; + static double sm_controlPointDragPosY; +}; + +class wxPolygonShape; +class wxPolygonControlPoint: public wxControlPoint +{ + DECLARE_DYNAMIC_CLASS(wxPolygonControlPoint) + friend class wxPolygonShape; + public: + wxPolygonControlPoint(wxShapeCanvas *the_canvas = NULL, wxShape *object = NULL, double size = 0.0, wxRealPoint *vertex = NULL, + double the_xoffset = 0.0, double the_yoffset = 0.0); + ~wxPolygonControlPoint(); + + 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); + + // Calculate what new size would be, at end of resize + virtual void CalculateNewSize(double x, double y); + + // Get new size + inline wxRealPoint GetNewSize() const { return m_newSize; }; + +public: + wxRealPoint* m_polygonVertex; + wxRealPoint m_originalSize; + double m_originalDistance; + wxRealPoint m_newSize; +}; + +/* + * Object regions. + * Every shape has one or more text regions with various + * properties. Not all of a region's properties will be used + * by a shape. + * + */ + +class wxShapeRegion: public wxObject +{ + DECLARE_DYNAMIC_CLASS(wxShapeRegion) + + public: + // Constructor + wxShapeRegion(); + // Copy constructor + wxShapeRegion(wxShapeRegion& region); + // Destructor + ~wxShapeRegion(); + + // Accessors + inline void SetText(const wxString& s) { m_regionText = s; } + void SetFont(wxFont *f); + void SetMinSize(double w, double h); + void SetSize(double w, double h); + void SetPosition(double x, double y); + void SetProportions(double x, double y); + void SetFormatMode(int mode); + inline void SetName(const wxString& s) { m_regionName = s; }; + void SetColour(const wxString& col); // Text colour + + inline wxString GetText() const { return m_regionText; } + inline wxFont *GetFont() const { return m_font; } + inline void GetMinSize(double *x, double *y) const { *x = m_minWidth; *y = m_minHeight; } + inline void GetProportion(double *x, double *y) const { *x = m_regionProportionX; *y = m_regionProportionY; } + inline void GetSize(double *x, double *y) const { *x = m_width; *y = m_height; } + inline void GetPosition(double *xp, double *yp) const { *xp = m_x; *yp = m_y; } + inline int GetFormatMode() const { return m_formatMode; } + inline wxString GetName() const { return m_regionName; } + inline wxString GetColour() const { return m_textColour; } + wxColour *GetActualColourObject(); + inline wxList& GetFormattedText() { return m_formattedText; } + inline wxString GetPenColour() const { return m_penColour; } + inline int GetPenStyle() const { return m_penStyle; } + inline void SetPenStyle(int style) { m_penStyle = style; m_actualPenObject = NULL; } + void SetPenColour(const wxString& col); + wxPen *GetActualPen(); + inline double GetWidth() const { return m_width; } + inline double GetHeight() const { return m_height; } + + void ClearText(); + +public: + wxString m_regionText; + wxList m_formattedText; // List of wxShapeTextLines + wxFont* m_font; + double m_minHeight; // If zero, hide region. + double m_minWidth; // If zero, hide region. + double m_width; + double m_height; + double m_x; + double m_y; + + double m_regionProportionX; // Proportion of total object size; + // -1.0 indicates equal proportion + double m_regionProportionY; // Proportion of total object size; + // -1.0 indicates equal proportion + + int m_formatMode; // FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT | FORMAT_NONE + wxString m_regionName; + wxString m_textColour; + wxColour* m_actualColourObject; // For speed purposes + + // New members for specifying divided rectangle division colour/style 30/6/94 + wxString m_penColour; + int m_penStyle; + wxPen* m_actualPenObject; + +}; + +/* + * User-defined attachment point + */ + +class wxAttachmentPoint: public wxObject +{ + DECLARE_DYNAMIC_CLASS(wxAttachmentPoint) + +public: + inline wxAttachmentPoint() + { + m_id = 0; m_x = 0.0; m_y = 0.0; + } + inline wxAttachmentPoint(int id, double x, double y) + { + m_id = id; m_x = x; m_y = y; + } + +public: + int m_id; // Identifier + double m_x; // x offset from centre of object + double m_y; // y offset from centre of object +}; + +#endif + // _OGL_BASICP_H_ diff --git a/include/wx/ogl/bmpshape.h b/include/wx/ogl/bmpshape.h new file mode 100644 index 0000000000..8dd7caeb2f --- /dev/null +++ b/include/wx/ogl/bmpshape.h @@ -0,0 +1,53 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: bmpshape.h +// Purpose: wxBitmapShape +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_BITMAP_H_ +#define _OGL_BITMAP_H_ + +#ifdef __GNUG__ +#pragma interface "bmpshape.h" +#endif + +#include + +class wxBitmapShape: public wxRectangleShape +{ + DECLARE_DYNAMIC_CLASS(wxBitmapShape) + public: + wxBitmapShape(); + ~wxBitmapShape(); + + void OnDraw(wxDC& dc); + +#ifdef PROLOGIO + // I/O + void WriteAttributes(wxExpr *clause); + void ReadAttributes(wxExpr *clause); +#endif + + // Does the copying for this object + void Copy(wxShape& copy); + + void SetSize(double w, double h, bool recursive = TRUE); + inline wxBitmap& GetBitmap() const { return (wxBitmap&) m_bitmap; } + void SetBitmap(const wxBitmap& bm); + inline void SetFilename(const wxString& f) { m_filename = f; }; + inline wxString GetFilename() const { return m_filename; } + +private: + wxBitmap m_bitmap; + wxString m_filename; +}; + +#endif + // _OGL_BITMAP_H_ + + diff --git a/include/wx/ogl/canvas.h b/include/wx/ogl/canvas.h new file mode 100644 index 0000000000..faeaaa30ad --- /dev/null +++ b/include/wx/ogl/canvas.h @@ -0,0 +1,83 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: canvas.h +// Purpose: wxShapeCanvas +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_CANVAS_H_ +#define _OGL_CANVAS_H_ + +#ifdef __GNUG__ +#pragma interface "canvas.h" +#endif + +// Drag states +#define NoDragging 0 +#define StartDraggingLeft 1 +#define ContinueDraggingLeft 2 +#define StartDraggingRight 3 +#define ContinueDraggingRight 4 + +// When drag_count reaches 0, process drag message + +class wxDiagram; + +class wxShapeCanvas: public wxScrolledWindow +{ + DECLARE_DYNAMIC_CLASS(wxShapeCanvas) + public: + wxShapeCanvas(wxWindow *parent = NULL, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxBORDER | wxRETAINED); + ~wxShapeCanvas(); + + inline void SetDiagram(wxDiagram *diag) { m_shapeDiagram = diag; } + inline wxDiagram *GetDiagram() const { return m_shapeDiagram; } + + 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); + + // Find object for mouse click, of given wxClassInfo (NULL for any type). + // If notImage is non-NULL, don't find an object that is equal to or a descendant of notImage + virtual wxShape *FindShape(double x, double y, int *attachment, wxClassInfo *info = NULL, wxShape *notImage = NULL); + wxShape *FindFirstSensitiveShape(double x, double y, int *new_attachment, int op); + wxShape *FindFirstSensitiveShape1(wxShape *image, int op); + + // Redirect to wxDiagram object + virtual void AddShape(wxShape *object, wxShape *addAfter = NULL); + virtual void InsertShape(wxShape *object); + virtual void RemoveShape(wxShape *object); + virtual bool GetQuickEditMode(); + virtual void Redraw(wxDC& dc); + void Snap(double *x, double *y); + + // Events + void OnPaint(wxPaintEvent& event); + void OnMouseEvent(wxMouseEvent& event); + + protected: + wxDiagram* m_shapeDiagram; + int m_dragState; + double m_oldDragX, m_oldDragY; // Previous drag coordinates + double m_firstDragX, m_firstDragY; // INITIAL drag coordinates + bool m_checkTolerance; // Whether to check drag tolerance + wxShape* m_draggedShape; + int m_draggedAttachment; + +DECLARE_EVENT_TABLE() +}; + +#endif + // _OGL_CANVAS_H_ diff --git a/include/wx/ogl/composit.h b/include/wx/ogl/composit.h new file mode 100644 index 0000000000..bbbcc835d3 --- /dev/null +++ b/include/wx/ogl/composit.h @@ -0,0 +1,238 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: composit.h +// Purpose: wxCompositeShape +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_COMPOSIT_H_ +#define _OGL_COMPOSIT_H_ + +#ifdef __GNUG__ +#pragma interface "composit.h" +#endif + +class wxDivisionShape; +class wxOGLConstraint; + +/* + * A composite object is an invisible rectangle surrounding all children + * + */ + +class wxCompositeShape: public wxRectangleShape +{ + DECLARE_DYNAMIC_CLASS(wxCompositeShape) +public: + + wxCompositeShape(); + ~wxCompositeShape(); + + void OnDraw(wxDC& dc); + void OnDrawContents(wxDC& dc); + void OnErase(wxDC& dc); + bool OnMovePre(wxDC& dc, double x, double y, double oldX, double oldY, bool display = TRUE); + void OnDragLeft(bool draw, double x, double y, int keys, int attachment = 0); + void OnBeginDragLeft(double x, double y, int keys, int attachment = 0); + void OnEndDragLeft(double x, double y, int keys, int attachment = 0); + + void OnRightClick(double x, double y, int keys, int attachment = 0); + + void SetSize(double w, double h, bool recursive = TRUE); + + // Returns TRUE if it settled down + bool Recompute(); + + // New members + void AddChild(wxShape *child, wxShape *addAfter = NULL); + void RemoveChild(wxShape *child); + + wxOGLConstraint *AddConstraint(wxOGLConstraint *constraint); + wxOGLConstraint *AddConstraint(int type, wxShape *constraining, wxList& constrained); + wxOGLConstraint *AddConstraint(int type, wxShape *constraining, wxShape *constrained); + + void DeleteConstraint(wxOGLConstraint *constraint); + + // Delete constraints that involve this child. + void DeleteConstraintsInvolvingChild(wxShape *child); + + // Remove the image from any constraints involving it, but DON'T + // remove any constraints. + void RemoveChildFromConstraints(wxShape *child); + + // Find constraint, also returning actual composite the constraint was in, + // in case it had to find it recursively. + wxOGLConstraint *FindConstraint(long id, wxCompositeShape **actualComposite = NULL); + + // Returns TRUE if something changed + bool Constrain(); + + // Make this composite into a container by creating one wxDivisionShape + void MakeContainer(); + + // Calculates size and position of composite object based on children + void CalculateSize(); + +#ifdef PROLOGIO + void WriteAttributes(wxExpr *clause); + void ReadAttributes(wxExpr *clause); + // In case the object has constraints it needs to read in in a different pass + void ReadConstraints(wxExpr *clause, wxExprDatabase *database); +#endif + // Does the copying for this object + void Copy(wxShape& copy); + + virtual wxDivisionShape *OnCreateDivision(); + + // Finds the image used to visualize a container. This is any child + // of the composite that is not in the divisions list. + wxShape *FindContainerImage(); + + // Returns TRUE if division is a descendant of this container + bool ContainsDivision(wxDivisionShape *division); + + inline wxList& GetDivisions() const { return (wxList&) m_divisions; } + inline wxList& GetConstraints() const { return (wxList&) m_constraints; } + +protected: + double m_oldX; + double m_oldY; + wxList m_constraints; + wxList m_divisions; // In case it's a container +}; + +/* + * A division object is a composite with special properties, + * to be used for containment. It's a subdivision of a container. + * A containing node image consists of a composite with a main child shape + * such as rounded rectangle, plus a list of division objects. + * It needs to be a composite because a division contains pieces + * of diagram. + * NOTE a container has at least one wxDivisionShape for consistency. + * This can be subdivided, so it turns into two objects, then each of + * these can be subdivided, etc. + */ +#define DIVISION_SIDE_NONE 0 +#define DIVISION_SIDE_LEFT 1 +#define DIVISION_SIDE_TOP 2 +#define DIVISION_SIDE_RIGHT 3 +#define DIVISION_SIDE_BOTTOM 4 + +class wxDivisionShape: public wxCompositeShape +{ + DECLARE_DYNAMIC_CLASS(wxDivisionShape) + public: + + wxDivisionShape(); + ~wxDivisionShape(); + + void OnDraw(wxDC& dc); + void OnDrawContents(wxDC& dc); + bool OnMovePre(wxDC& dc, double x, double y, double oldX, double oldY, bool display = TRUE); + void OnDragLeft(bool draw, double x, double y, int keys, int attachment = 0); + void OnBeginDragLeft(double x, double y, int keys, int attachment = 0); + void OnEndDragLeft(double x, double y, int keys, int attachment = 0); + + void OnRightClick(double x, double y, int keys = 0, int attachment = 0); + + // Don't want this kind of composite to resize its subdiagrams, so + // override composite's SetSize. + void SetSize(double w, double h, bool recursive = TRUE); + + // Similarly for calculating size: it's fixed at whatever SetSize + // set it to, not in terms of children. + void CalculateSize(); + + void MakeControlPoints(); + void ResetControlPoints(); + void MakeMandatoryControlPoints(); + void ResetMandatoryControlPoints(); + +#ifdef PROLOGIO + void WriteAttributes(wxExpr *clause); + void ReadAttributes(wxExpr *clause); +#endif + // Does the copying for this object + void Copy(wxShape& copy); + + // Divide horizontally (wxHORIZONTAL) or vertically (wxVERTICAL) + bool Divide(int direction); + + // Resize adjoining divisions at the given side. If test is TRUE, + // just see whether it's possible for each adjoining region, + // returning FALSE if it's not. + bool ResizeAdjoining(int side, double newPos, bool test); + + // Adjust a side, returning FALSE if it's not physically possible. + bool AdjustLeft(double left, bool test); + bool AdjustTop(double top, bool test); + bool AdjustRight(double right, bool test); + bool AdjustBottom(double bottom, bool test); + + // Edit style of left or top side + void EditEdge(int side); + + // Popup menu + void PopupMenu(double x, double y); + + inline void SetLeftSide(wxDivisionShape *shape) { m_leftSide = shape; } + inline void SetTopSide(wxDivisionShape *shape) { m_topSide = shape; } + inline void SetRightSide(wxDivisionShape *shape) { m_rightSide = shape; } + inline void SetBottomSide(wxDivisionShape *shape) { m_bottomSide = shape; } + inline wxDivisionShape *GetLeftSide() const { return m_leftSide; } + inline wxDivisionShape *GetTopSide() const { return m_topSide; } + inline wxDivisionShape *GetRightSide() const { return m_rightSide; } + inline wxDivisionShape *GetBottomSide() const { return m_bottomSide; } + + inline void SetHandleSide(int side) { m_handleSide = side; } + inline int GetHandleSide() const { return m_handleSide; } + + inline void SetLeftSidePen(wxPen *pen) { m_leftSidePen = pen; } + inline wxPen *GetLeftSidePen() const { return m_leftSidePen; } + inline void SetTopSidePen(wxPen *pen) { m_topSidePen = pen; } + inline wxPen *GetTopSidePen() const { return m_topSidePen; } + + void SetLeftSideColour(const wxString& colour); + void SetTopSideColour(const wxString& colour); + void SetLeftSideStyle(const wxString& style); + void SetTopSideStyle(const wxString& style); + + inline wxString GetLeftSideColour() const { return m_leftSideColour; } + inline wxString GetTopSideColour() const { return m_topSideColour; } + inline wxString GetLeftSideStyle() const { return m_leftSideStyle; } + inline wxString GetTopSideStyle() const { return m_topSideStyle; } + + protected: + // Adjoining divisions. NULL indicates edge + // of container, and that side shouldn't be + // drawn. + wxDivisionShape* m_leftSide; + wxDivisionShape* m_rightSide; + wxDivisionShape* m_topSide; + wxDivisionShape* m_bottomSide; + + int m_handleSide; // Side at which handle is legal + + wxPen* m_leftSidePen; + wxPen* m_topSidePen; + wxString m_leftSideColour; + wxString m_topSideColour; + wxString m_leftSideStyle; + wxString m_topSideStyle; +}; + + +#define DIVISION_MENU_SPLIT_HORIZONTALLY 1 +#define DIVISION_MENU_SPLIT_VERTICALLY 2 +#define DIVISION_MENU_EDIT_LEFT_EDGE 3 +#define DIVISION_MENU_EDIT_TOP_EDGE 4 +#define DIVISION_MENU_EDIT_RIGHT_EDGE 5 +#define DIVISION_MENU_EDIT_BOTTOM_EDGE 6 +#define DIVISION_MENU_DELETE_ALL 7 + +#endif + // _OGL_COMPOSIT_H_ diff --git a/include/wx/ogl/constrnt.h b/include/wx/ogl/constrnt.h new file mode 100644 index 0000000000..812aca19a9 --- /dev/null +++ b/include/wx/ogl/constrnt.h @@ -0,0 +1,87 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: constrnt.h +// Purpose: OGL constraint definitions +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_CONSTRNT_H_ +#define _OGL_CONSTRNT_H_ + +#ifdef __GNUG__ +#pragma interface "constrnt.h" +#endif + +/* + * OGL Constraints + * + */ + +class wxOGLConstraintType: public wxObject +{ + DECLARE_DYNAMIC_CLASS(wxOGLConstraintType) +public: + wxOGLConstraintType(int type = 0, const wxString& name = "", const wxString& phrase = ""); + ~wxOGLConstraintType(); + +public: + int m_type; // E.g. gyCONSTRAINT_CENTRED_VERTICALLY + wxString m_name; // E.g. "Centre vertically" + wxString m_phrase; // E.g. "centred vertically with respect to", "left of" + +}; + +extern wxList* wxOGLConstraintTypes; + +#define gyCONSTRAINT_CENTRED_VERTICALLY 1 +#define gyCONSTRAINT_CENTRED_HORIZONTALLY 2 +#define gyCONSTRAINT_CENTRED_BOTH 3 +#define gyCONSTRAINT_LEFT_OF 4 +#define gyCONSTRAINT_RIGHT_OF 5 +#define gyCONSTRAINT_ABOVE 6 +#define gyCONSTRAINT_BELOW 7 +#define gyCONSTRAINT_ALIGNED_TOP 8 +#define gyCONSTRAINT_ALIGNED_BOTTOM 9 +#define gyCONSTRAINT_ALIGNED_LEFT 10 +#define gyCONSTRAINT_ALIGNED_RIGHT 11 + +// Like aligned, but with the objects centred on the respective edge +// of the reference object. +#define gyCONSTRAINT_MIDALIGNED_TOP 12 +#define gyCONSTRAINT_MIDALIGNED_BOTTOM 13 +#define gyCONSTRAINT_MIDALIGNED_LEFT 14 +#define gyCONSTRAINT_MIDALIGNED_RIGHT 15 + +class wxOGLConstraint: public wxObject +{ + DECLARE_DYNAMIC_CLASS(wxOGLConstraint) + public: + wxOGLConstraint() { m_xSpacing = 0.0; m_ySpacing = 0.0; m_constraintType = 0; m_constraintName = ""; m_constraintId = 0; + m_constrainingObject = NULL; } + wxOGLConstraint(int type, wxShape *constraining, wxList& constrained); + ~wxOGLConstraint(); + + // Returns TRUE if anything changed + bool Evaluate(); + inline void SetSpacing(double x, double y) { m_xSpacing = x; m_ySpacing = y; }; + bool Equals(double a, double b); + + double m_xSpacing; + double m_ySpacing; + int m_constraintType; + wxString m_constraintName; + long m_constraintId; + wxShape* m_constrainingObject; + wxList m_constrainedObjects; + +}; + +void OGLInitializeConstraintTypes(); +void OGLCleanUpConstraintTypes(); + +#endif + // _OGL_CONSTRNT_H_ diff --git a/include/wx/ogl/divided.h b/include/wx/ogl/divided.h new file mode 100644 index 0000000000..f8404637df --- /dev/null +++ b/include/wx/ogl/divided.h @@ -0,0 +1,75 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: divided.h +// Purpose: wxDividedShape +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_DIVIDED_H_ +#define _OGL_DIVIDED_H_ + +#ifdef __GNUG__ +#pragma interface "basic.h" +#endif + +/* + * Definition of a region + * + */ + +/* + * Box divided into horizontal regions + * + */ + +extern wxFont *g_oglNormalFont; +class wxDividedShape: public wxRectangleShape +{ + DECLARE_DYNAMIC_CLASS(wxDividedShape) + + public: + wxDividedShape(double w = 0.0, double h = 0.0); + ~wxDividedShape(); + + void OnDraw(wxDC& dc); + void OnDrawContents(wxDC& dc); + + void SetSize(double w, double h, bool recursive = TRUE); + + void MakeControlPoints(); + void ResetControlPoints(); + + void MakeMandatoryControlPoints(); + void ResetMandatoryControlPoints(); + +#ifdef PROLOGIO + void WriteAttributes(wxExpr *clause); + void ReadAttributes(wxExpr *clause); +#endif + + void Copy(wxShape ©); + + // Set all region sizes according to proportions and + // this object total size + void SetRegionSizes(); + + // Edit region colours/styles + void EditRegions(); + + // Attachment points correspond to regions in the divided box + bool GetAttachmentPosition(int attachment, double *x, double *y, + int nth = 0, int no_arcs = 1, wxLineShape *line = NULL); + bool AttachmentIsValid(int attachment); + int GetNumberOfAttachments() const; + + // Invoke editor on CTRL-right click + void OnRightClick(double x, double y, int keys = 0, int attachment = 0); +}; + +#endif + // _OGL_DIVIDED_H_ + diff --git a/include/wx/ogl/drawn.h b/include/wx/ogl/drawn.h new file mode 100644 index 0000000000..913275a603 --- /dev/null +++ b/include/wx/ogl/drawn.h @@ -0,0 +1,227 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: drawn.h +// Purpose: wxDrawnShape +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_DRAWN_H_ +#define _OGL_DRAWN_H_ + +#ifdef __GNUG__ +#pragma interface "drawn.h" +#endif + +#include + +#define oglMETAFLAGS_OUTLINE 1 +#define oglMETAFLAGS_ATTACHMENTS 2 + +class wxDrawnShape; +class wxPseudoMetaFile: public wxObject +{ + DECLARE_DYNAMIC_CLASS(wxPseudoMetaFile) + public: + wxPseudoMetaFile(); + wxPseudoMetaFile(wxPseudoMetaFile& mf); + ~wxPseudoMetaFile(); + + void Draw(wxDC& dc, double xoffset, double yoffset); + +#ifdef PROLOGIO + void WriteAttributes(wxExpr *clause, int whichAngle); + void ReadAttributes(wxExpr *clause, int whichAngle); +#endif + + void Clear(); + + void Copy(wxPseudoMetaFile& copy); + + void Scale(double sx, double sy); + void ScaleTo(double w, double h); // Scale to fit size + void Translate(double x, double y); + + // Rotate about the given axis by theta radians from the x axis. + void Rotate(double x, double y, double theta); + + bool LoadFromMetaFile(char *filename, double *width, double *height); + + void GetBounds(double *minX, double *minY, double *maxX, double *maxY); + + // Calculate size from current operations + void CalculateSize(wxDrawnShape* shape); + + inline wxList& GetOutlineColours() const { return (wxList&) m_outlineColours; } + inline wxList& GetFillColours() const { return (wxList&) m_fillColours; } + inline void SetRotateable(bool rot) { m_rotateable = rot; } + inline bool GetRotateable() const { return m_rotateable; } + + inline void SetSize(double w, double h) { m_width = w; m_height = h; } + + inline void SetFillBrush(wxBrush* brush) { m_fillBrush = brush; } + inline wxBrush* GetFillBrush() const { return m_fillBrush; } + + inline void SetOutlinePen(wxPen* pen) { m_outlinePen = pen; } + inline wxPen* GetOutlinePen() const { return m_outlinePen; } + + inline void SetOutlineOp(int op) { m_outlineOp = op; } + inline int GetOutlineOp() const { return m_outlineOp; } + + inline wxList& GetOps() const { return (wxList&) m_ops; } + + // Is this a valid (non-empty) metafile? + inline bool IsValid() const { return (m_ops.Number() > 0); } + +public: + /// Set of functions for drawing into a pseudo metafile. + /// They use integers, but doubles are used internally for accuracy + /// when scaling. + + virtual void DrawLine(const wxPoint& pt1, const wxPoint& pt2); + virtual void DrawRectangle(const wxRect& rect); + virtual void DrawRoundedRectangle(const wxRect& rect, double radius); + virtual void DrawArc(const wxPoint& centrePt, const wxPoint& startPt, const wxPoint& endPt); + virtual void DrawEllipticArc(const wxRect& rect, double startAngle, double endAngle); + virtual void DrawEllipse(const wxRect& rect); + virtual void DrawPoint(const wxPoint& pt); + virtual void DrawText(const wxString& text, const wxPoint& pt); + virtual void DrawLines(int n, wxPoint pts[]); + // flags: + // oglMETAFLAGS_OUTLINE: will be used for drawing the outline and + // also drawing lines/arrows at the circumference. + // oglMETAFLAGS_ATTACHMENTS: will be used for initialising attachment points at + // the vertices (perhaps a rare case...) + virtual void DrawPolygon(int n, wxPoint pts[], int flags = 0); + virtual void DrawSpline(int n, wxPoint pts[]); + + virtual void SetClippingRect(const wxRect& rect); + virtual void DestroyClippingRect(); + + virtual void SetPen(wxPen* pen, bool isOutline = FALSE); // TODO: eventually, just store GDI object attributes, not actual + virtual void SetBrush(wxBrush* brush, bool isFill = FALSE); // pens/brushes etc. + virtual void SetFont(wxFont* font); + virtual void SetTextColour(const wxColour& colour); + virtual void SetBackgroundColour(const wxColour& colour); + virtual void SetBackgroundMode(int mode); + +public: + bool m_rotateable; + double m_width; + double m_height; + wxList m_ops; // List of drawing operations (see drawnp.h) + wxList m_gdiObjects; // List of pens, brushes and fonts for this object. + int m_outlineOp; // The op representing the outline, if any + + // Pen/brush specifying outline/fill colours + // to override operations. + wxPen* m_outlinePen; + wxBrush* m_fillBrush; + wxList m_outlineColours; // List of the GDI operations that comprise the outline + wxList m_fillColours; // List of the GDI operations that fill the shape + double m_currentRotation; +}; + +#define oglDRAWN_ANGLE_0 0 +#define oglDRAWN_ANGLE_90 1 +#define oglDRAWN_ANGLE_180 2 +#define oglDRAWN_ANGLE_270 3 + +class wxDrawnShape: public wxRectangleShape +{ + DECLARE_DYNAMIC_CLASS(wxDrawnShape) + public: + wxDrawnShape(); + ~wxDrawnShape(); + + void OnDraw(wxDC& dc); + +#ifdef PROLOGIO + // I/O + void WriteAttributes(wxExpr *clause); + void ReadAttributes(wxExpr *clause); +#endif + + // Does the copying for this object + void Copy(wxShape& copy); + + void Scale(double sx, double sy); + void Translate(double x, double y); + // Rotate about the given axis by theta radians from the x axis. + void Rotate(double x, double y, double theta); + + // Get current rotation + inline double GetRotation() const { return m_rotation; } + + void SetSize(double w, double h, bool recursive = TRUE); + bool LoadFromMetaFile(char *filename); + + inline void SetSaveToFile(bool save) { m_saveToFile = save; } + inline wxPseudoMetaFile& GetMetaFile(int which = 0) const { return (wxPseudoMetaFile&) m_metafiles[which]; } + + void OnDrawOutline(wxDC& dc, double x, double y, double w, double h); + + // Get the perimeter point using the special outline op, if there is one, + // otherwise use default wxRectangleShape scheme + bool GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3); + + /// Set of functions for drawing into a pseudo metafile. + /// They use integers, but doubles are used internally for accuracy + /// when scaling. + + virtual void DrawLine(const wxPoint& pt1, const wxPoint& pt2); + virtual void DrawRectangle(const wxRect& rect); + virtual void DrawRoundedRectangle(const wxRect& rect, double radius); + virtual void DrawArc(const wxPoint& centrePt, const wxPoint& startPt, const wxPoint& endPt); + virtual void DrawEllipticArc(const wxRect& rect, double startAngle, double endAngle); + virtual void DrawEllipse(const wxRect& rect); + virtual void DrawPoint(const wxPoint& pt); + virtual void DrawText(const wxString& text, const wxPoint& pt); + virtual void DrawLines(int n, wxPoint pts[]); + virtual void DrawPolygon(int n, wxPoint pts[], int flags = 0); + virtual void DrawSpline(int n, wxPoint pts[]); + + virtual void SetClippingRect(const wxRect& rect); + virtual void DestroyClippingRect(); + + virtual void SetDrawnPen(wxPen* pen, bool isOutline = FALSE); // TODO: eventually, just store GDI object attributes, not actual + virtual void SetDrawnBrush(wxBrush* brush, bool isFill = FALSE); // pens/brushes etc. + virtual void SetDrawnFont(wxFont* font); + virtual void SetDrawnTextColour(const wxColour& colour); + virtual void SetDrawnBackgroundColour(const wxColour& colour); + virtual void SetDrawnBackgroundMode(int mode); + + // Set the width/height according to the shapes in the metafile. + // Call this after drawing into the shape. + inline void CalculateSize() { m_metafiles[m_currentAngle].CalculateSize(this); } + + inline void DrawAtAngle(int angle) { m_currentAngle = angle; }; + + inline int GetAngle() const { return m_currentAngle; } + +// Implementation +protected: + // Which metafile do we use now? Based on current rotation and validity + // of metafiles. + int DetermineMetaFile(double rotation); + +private: + // One metafile for each 90 degree rotation (or just a single one). + wxPseudoMetaFile m_metafiles[4]; + + // Don't save all wxDrawnShape metafiles to file: sometimes + // we take the metafile data from a symbol library. + bool m_saveToFile; + + // Which angle are we using/drawing into? + int m_currentAngle; +}; + +#endif + // _DRAWN_H_ + diff --git a/include/wx/ogl/drawnp.h b/include/wx/ogl/drawnp.h new file mode 100644 index 0000000000..e819600e0a --- /dev/null +++ b/include/wx/ogl/drawnp.h @@ -0,0 +1,205 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: drawnp.h +// Purpose: Private header for wxDrawnShape +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_DRAWNP_H_ +#define _OGL_DRAWNP_H_ + +#ifdef __GNUG__ +#pragma interface "drawnp.h" +#endif + +#include + +/* + * Drawing operations + * + */ + +#define DRAWOP_SET_PEN 1 +#define DRAWOP_SET_BRUSH 2 +#define DRAWOP_SET_FONT 3 +#define DRAWOP_SET_TEXT_COLOUR 4 +#define DRAWOP_SET_BK_COLOUR 5 +#define DRAWOP_SET_BK_MODE 6 +#define DRAWOP_SET_CLIPPING_RECT 7 +#define DRAWOP_DESTROY_CLIPPING_RECT 8 + +/* +#define DRAWOP_CREATE_PEN 10 +#define DRAWOP_CREATE_BRUSH 11 +#define DRAWOP_CREATE_FONT 12 +*/ + +#define DRAWOP_DRAW_LINE 20 +#define DRAWOP_DRAW_POLYLINE 21 +#define DRAWOP_DRAW_POLYGON 22 +#define DRAWOP_DRAW_RECT 23 +#define DRAWOP_DRAW_ROUNDED_RECT 24 +#define DRAWOP_DRAW_ELLIPSE 25 +#define DRAWOP_DRAW_POINT 26 +#define DRAWOP_DRAW_ARC 27 +#define DRAWOP_DRAW_TEXT 28 +#define DRAWOP_DRAW_SPLINE 29 +#define DRAWOP_DRAW_ELLIPTIC_ARC 30 + +/* + * Base, virtual class + * + */ + +class wxDrawOp: public wxObject +{ +public: + inline wxDrawOp(int theOp) { m_op = theOp; } + inline ~wxDrawOp() {} + inline virtual void Scale(double xScale, double yScale) {}; + inline virtual void Translate(double x, double y) {}; + inline virtual void Rotate(double x, double y, double theta, double sinTheta, double cosTheta) {}; + virtual void Do(wxDC& dc, double xoffset, double yoffset) = 0; + virtual wxDrawOp *Copy(wxPseudoMetaFile *newImage) = 0; + virtual wxExpr *WriteExpr(wxPseudoMetaFile *image) = 0; + virtual void ReadExpr(wxPseudoMetaFile *image, wxExpr *expr) = 0; + + inline int GetOp() const { return m_op; } + + // Draw an outline using the current operation. By default, return FALSE (not drawn) + virtual bool OnDrawOutline(wxDC& dc, double x, double y, double w, double h, + double oldW, double oldH) { return FALSE; } + + // Get the perimeter point using this data + virtual bool GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3, + double xOffset, double yOffset, + int attachmentMode) + { return FALSE; } + +protected: + int m_op; + +}; + +/* + * Set font, brush, text colour + * + */ + +class wxOpSetGDI: public wxDrawOp +{ + public: + wxOpSetGDI(int theOp, wxPseudoMetaFile *theImage, int theGdiIndex, int theMode = 0); + void Do(wxDC& dc, double xoffset, double yoffset); + wxDrawOp *Copy(wxPseudoMetaFile *newImage); + wxExpr *WriteExpr(wxPseudoMetaFile *image); + void ReadExpr(wxPseudoMetaFile *image, wxExpr *expr); + +public: + int m_mode; + int m_gdiIndex; + wxPseudoMetaFile* m_image; + unsigned char m_r; + unsigned char m_g; + unsigned char m_b; +}; + +/* + * Set/destroy clipping + * + */ + +class wxOpSetClipping: public wxDrawOp +{ +public: + wxOpSetClipping(int theOp, double theX1, double theY1, double theX2, double theY2); + void Do(wxDC& dc, double xoffset, double yoffset); + void Scale(double xScale, double yScale); + void Translate(double x, double y); + wxDrawOp *Copy(wxPseudoMetaFile *newImage); + wxExpr *WriteExpr(wxPseudoMetaFile *image); + void ReadExpr(wxPseudoMetaFile *image, wxExpr *expr); + +public: + double m_x1; + double m_y1; + double m_x2; + double m_y2; +}; + +/* + * Draw line, rectangle, rounded rectangle, ellipse, point, arc, text + * + */ + +class wxOpDraw: public wxDrawOp +{ + public: + wxOpDraw(int theOp, double theX1, double theY1, double theX2, double theY2, + double radius = 0.0, char *s = NULL); + ~wxOpDraw(); + void Do(wxDC& dc, double xoffset, double yoffset); + void Scale(double scaleX, double scaleY); + void Translate(double x, double y); + void Rotate(double x, double y, double theta, double sinTheta, double cosTheta); + wxDrawOp *Copy(wxPseudoMetaFile *newImage); + wxExpr *WriteExpr(wxPseudoMetaFile *image); + void ReadExpr(wxPseudoMetaFile *image, wxExpr *expr); + +public: + double m_x1; + double m_y1; + double m_x2; + double m_y2; + double m_x3; + double m_y3; + double m_radius; + char* m_textString; + +}; + +/* + * Draw polyline, spline, polygon + * + */ + +class wxOpPolyDraw: public wxDrawOp +{ +public: + wxOpPolyDraw(int theOp, int n, wxRealPoint *thePoints); + ~wxOpPolyDraw(); + void Do(wxDC& dc, double xoffset, double yoffset); + void Scale(double scaleX, double scaleY); + void Translate(double x, double y); + void Rotate(double x, double y, double theta, double sinTheta, double cosTheta); + wxDrawOp *Copy(wxPseudoMetaFile *newImage); + wxExpr *WriteExpr(wxPseudoMetaFile *image); + void ReadExpr(wxPseudoMetaFile *image, wxExpr *expr); + + // Draw an outline using the current operation. + virtual bool OnDrawOutline(wxDC& dc, double x, double y, double w, double h, + double oldW, double oldH); + + // Get the perimeter point using this data + bool GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3, + double xOffset, double yOffset, + int attachmentMode); + +public: + wxRealPoint* m_points; + int m_noPoints; + +}; + +#endif + // _OGL_DRAWNP_H_ + + diff --git a/include/wx/ogl/lines.h b/include/wx/ogl/lines.h new file mode 100644 index 0000000000..9619bf75cf --- /dev/null +++ b/include/wx/ogl/lines.h @@ -0,0 +1,296 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: lines.h +// Purpose: wxLineShape +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_LINES_H_ +#define _OGL_LINES_H_ + +#ifdef __GNUG__ +#pragma interface "lines.h" +#endif + +class wxLabelShape; +class wxPseudoMetaFile; +class wxLineControlPoint; +/* + * Arcs with multiple arrowheads + * + */ + +// Types of arrowhead +// (i) Built-in +#define ARROW_HOLLOW_CIRCLE 1 +#define ARROW_FILLED_CIRCLE 2 +#define ARROW_ARROW 3 +#define ARROW_SINGLE_OBLIQUE 4 +#define ARROW_DOUBLE_OBLIQUE 5 +// (ii) Custom +#define ARROW_METAFILE 20 + +// Position of arrow on line +#define ARROW_POSITION_START 0 +#define ARROW_POSITION_END 1 +#define ARROW_POSITION_MIDDLE 2 + +// Line alignment flags +// Vertical by default +#define LINE_ALIGNMENT_HORIZ 1 +#define LINE_ALIGNMENT_VERT 0 +#define LINE_ALIGNMENT_TO_NEXT_HANDLE 2 +#define LINE_ALIGNMENT_NONE 0 + +class wxArrowHead: public wxObject +{ + DECLARE_DYNAMIC_CLASS(wxArrowHead) + + public: + wxArrowHead(WXTYPE type = 0, int end = 0, double size = 0.0, double dist = 0.0, const wxString& name = "", wxPseudoMetaFile *mf = NULL, + long arrowId = -1); + ~wxArrowHead(); + wxArrowHead(wxArrowHead& toCopy); + + inline WXTYPE _GetType() const { return m_arrowType; } + inline int GetPosition() const { return m_arrowEnd; } + inline void SetPosition(int pos) { m_arrowEnd = pos; } + inline double GetXOffset() const { return m_xOffset; } + inline double GetYOffset() const { return m_yOffset; } + inline double GetSpacing() const { return m_spacing; } + inline double GetSize() const { return m_arrowSize; } + inline wxString GetName() const { return m_arrowName; } + inline void SetXOffset(double x) { m_xOffset = x; } + inline void SetYOffset(double y) { m_yOffset = y; } + inline wxPseudoMetaFile *GetMetaFile() const { return m_metaFile; } + inline long GetId() const { return m_id; } + inline int GetArrowEnd() const { return m_arrowEnd; } + inline double GetArrowSize() const { return m_arrowSize; } + void SetSize(double size); + inline void SetSpacing(double sp) { m_spacing = sp; } + + protected: + WXTYPE m_arrowType; + int m_arrowEnd; // Position on line + double m_xOffset; // Distance from arc start or end, w.r.t. point on arrowhead + // nearest start or end. If zero, use default spacing. + double m_yOffset; // vertical offset (w.r.t. a horizontal line). Normally zero. + double m_spacing; // Spacing from the last arrowhead + double m_arrowSize; // Length of arrowhead + wxString m_arrowName; // Name of arrow + bool m_saveToFile; // TRUE if we want to save custom arrowheads to file. + wxPseudoMetaFile* m_metaFile; // Pseudo metafile if this is a custom arrowhead + long m_id; // identifier +}; + +// Line object +class wxLabelShape; +class wxLineShape: public wxShape +{ + DECLARE_DYNAMIC_CLASS(wxLineShape) + + public: + wxLineShape(); + ~wxLineShape(); + + // Called when a connected object has moved, to move the link to + // correct position + // moveControlPoints must be disabled when a control point is being + // dragged. + void OnMoveLink(wxDC& dc, bool moveControlPoints = TRUE); + bool OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display = TRUE); + void OnDraw(wxDC& dc); + void OnDrawContents(wxDC& dc); + void OnDrawControlPoints(wxDC& dc); + void OnEraseControlPoints(wxDC& dc); + void OnErase(wxDC& dc); + virtual bool OnMoveControlPoint(int WXUNUSED(which), double WXUNUSED(x), double WXUNUSED(y)) { return FALSE; } + virtual bool OnMoveMiddleControlPoint(wxDC& dc, wxLineControlPoint* lpt, const wxRealPoint& pt); + virtual bool OnLabelMovePre(wxDC& dc, wxLabelShape* labelShape, double x, double y, double old_x, double old_y, bool display); + void OnDrawOutline(wxDC& dc, double x, double y, double w, double h); + void GetBoundingBoxMin(double *w, double *h); + void FormatText(wxDC& dc, const wxString& s, int regionId = 0); + virtual void SetEnds(double x1, double y1, double x2, double y2); + virtual void GetEnds(double *x1, double *y1, double *x2, double *y2); + inline virtual wxShape *GetFrom() { return m_from; } + inline virtual wxShape *GetTo() { return m_to; } + inline virtual int GetAttachmentFrom() { return m_attachmentFrom; } + inline virtual int GetAttachmentTo() { return m_attachmentTo; } + + virtual void SetFrom(wxShape *object); + virtual void SetTo(wxShape *object); + virtual void DrawArrows(wxDC& dc); + + // Finds the x, y points at the two ends of the line. + // This function can be used by e.g. line-routing routines to + // get the actual points on the two node images where the lines will be drawn + // to/from. + void FindLineEndPoints(double *fromX, double *fromY, double *toX, double *toY); + + // Format one region at this position + void DrawRegion(wxDC& dc, wxShapeRegion *region, double x, double y); + + // Erase one region at this position + void EraseRegion(wxDC& dc, wxShapeRegion *region, double x, double y); + + // Get the reference point for a label. Region x and y + // are offsets from this. + // position is 0 (middle), 1 (start), 2 (end) + void GetLabelPosition(int position, double *x, double *y); + + // Can override this to create a different class of label shape + virtual wxLabelShape* OnCreateLabelShape(wxLineShape *parent = NULL, wxShapeRegion *region = NULL, double w = 0.0, double h = 0.0); + + // Straighten verticals and horizontals + virtual void Straighten(wxDC* dc = NULL); + + // Not implemented + inline void SetMaintainStraightLines(bool flag) { m_maintainStraightLines = flag; } + inline bool GetMaintainStraightLines() const { return m_maintainStraightLines; } + + // Make handle control points + void MakeControlPoints(); + void ResetControlPoints(); + + // Make a given number of control points + virtual void MakeLineControlPoints(int n); + virtual wxNode *InsertLineControlPoint(wxDC* dc); + virtual bool DeleteLineControlPoint(); + virtual void Initialise(); + inline wxList *GetLineControlPoints() { return m_lineControlPoints; } + + // Override dragging behaviour - don't want to be able to drag lines! + 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); + + // Control points ('handles') redirect control to the actual shape, to make it easier + // to override sizing behaviour. + virtual void OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys=0, int attachment = 0); + virtual void OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys=0, int attachment = 0); + virtual void OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys=0, int attachment = 0); + + // Override select, to create/delete temporary label-moving objects + void Select(bool select = TRUE, wxDC* dc = NULL); + + // Set to spline (TRUE) or line (FALSE) + inline void SetSpline(bool spl) { m_isSpline = spl; } + inline bool IsSpline() const { return m_isSpline; } + + void Unlink(); + void SetAttachments(int from_attach, int to_attach); + inline void SetAttachmentFrom(int attach) { m_attachmentFrom = attach; } + inline void SetAttachmentTo(int attach) { m_attachmentTo = attach; } + + bool HitTest(double x, double y, int *attachment, double *distance); + +#ifdef PROLOGIO + // I/O + virtual void WriteAttributes(wxExpr *clause); + virtual void ReadAttributes(wxExpr *clause); +#endif + + virtual void FindNth(wxShape *image, int *nth, int *no_arcs, bool incoming); + + // Find which position we're talking about at this (x, y). + // Returns ARROW_POSITION_START, ARROW_POSITION_MIDDLE, ARROW_POSITION_END + int FindLinePosition(double x, double y); + + // This is really to distinguish between lines and other images. + // For lines, want to pass drag to canvas, since lines tend to prevent + // dragging on a canvas (they get in the way.) + virtual bool Draggable() const { return FALSE; } + + // Does the copying for this object + void Copy(wxShape& copy); + + // Add an arrowhead. + wxArrowHead *AddArrow(WXTYPE type, int end = ARROW_POSITION_END, + double arrowSize = 10.0, double xOffset = 0.0, const wxString& name = "", + wxPseudoMetaFile *mf = NULL, long arrowId = -1); + + // Add an arrowhead in the position indicated by the reference + // list of arrowheads, which contains all legal arrowheads for this + // line, in the correct order. + // E.g. reference list: a b c d e + // Current line list: a d + // Add c, then line list is: a c d + // If no legal arrowhead position, return FALSE. + // Assume reference list is for one end only, since it potentially defines + // the ordering for any one of the 3 positions. So we don't check + // the reference list for arrowhead position. + bool AddArrowOrdered(wxArrowHead *arrow, wxList& referenceList, int end); + + // Delete arrowhead(s) + void ClearArrowsAtPosition(int end = -1); + bool ClearArrow(const wxString& name); + wxArrowHead *FindArrowHead(int position, const wxString& name); + wxArrowHead *FindArrowHead(long arrowId); + bool DeleteArrowHead(int position, const wxString& name); + bool DeleteArrowHead(long arrowId); + void DrawArrow(wxDC& dc, wxArrowHead *arrow, double xOffset, bool proportionalOffset); + inline void SetIgnoreOffsets(bool ignore) { m_ignoreArrowOffsets = ignore; } + inline wxList& GetArrows() const { return (wxList&) m_arcArrows; } + + // Find horizontal width for drawing a line with + // arrows in minimum space. Assume arrows at + // END only + double FindMinimumWidth(); + + // Set alignment flags. ALIGNMENT NOT IMPLEMENTED. + void SetAlignmentOrientation(bool isEnd, bool isHoriz); + void SetAlignmentType(bool isEnd, int alignType); + bool GetAlignmentOrientation(bool isEnd); + int GetAlignmentType(bool isEnd); + + // Find next control point in line after the start/end point + // (depending on whether the node object is at start or end) + wxRealPoint *GetNextControlPoint(wxShape *nodeObject); + inline bool IsEnd(wxShape *nodeObject) const { return (m_to == nodeObject); } + +private: + bool m_erasing; // flag to say whether we're erasing or drawing + // this line (really so metafiles can draw a + // blank rectangle) + bool m_ignoreArrowOffsets; // Don't always want to draw arrowhead offsets + // because they may not work on tool palettes (for example) + bool m_isSpline; + bool m_maintainStraightLines; + +protected: + // Temporary list of line segment orientations + // so we know what direction the line is supposed to be dog-legging + // in. The values are integer: 0 for vertical, 1 for horizontal. + wxList m_lineOrientations; + + // Temporary pointers for start, middle and end label editing objects + // (active only when the line is selected) + wxLabelShape* m_labelObjects[3]; + + // These define the segmented line - not to be confused with temporary control + // points which appear when object is selected (although in this case they'll + // probably be the same) + wxList* m_lineControlPoints; + + double m_arrowSpacing; // Separation between adjacent arrows + + wxShape* m_to; + wxShape* m_from; + + int m_attachmentTo; // Attachment point at one end + int m_attachmentFrom; // Attachment point at other end + + // Alignment flags + int m_alignmentStart; + int m_alignmentEnd; + + wxList m_arcArrows; + +}; + +#endif + // _OGL_LINES_H_ diff --git a/include/wx/ogl/linesp.h b/include/wx/ogl/linesp.h new file mode 100644 index 0000000000..383fe7f554 --- /dev/null +++ b/include/wx/ogl/linesp.h @@ -0,0 +1,89 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: linesp.h +// Purpose: Lines private header file +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_LINESP_H_ +#define _OGL_LINESP_H_ + +#ifdef __GNUG__ +#pragma interface "linesp.h" +#endif + +class wxLineShape; +class wxLineControlPoint: public wxControlPoint +{ + DECLARE_DYNAMIC_CLASS(wxLineControlPoint) + friend class wxLineShape; + public: + + wxLineControlPoint(wxShapeCanvas *the_canvas = NULL, wxShape *object = NULL, double size = 0.0, + double x = 0.0, double y = 0.0, int the_type = 0); + ~wxLineControlPoint(); + + void OnDraw(wxDC& dc); + 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); + + // Obsolete (left-dragging now moves attachment point to new relative position OR new + // attachment id) +#if 0 + void OnDragRight(bool draw, double x, double y, int keys=0, int attachment = 0); + void OnBeginDragRight(double x, double y, int keys=0, int attachment = 0); + void OnEndDragRight(double x, double y, int keys=0, int attachment = 0); +#endif + +public: + + int m_type; + wxRealPoint* m_point; // Line point + wxRealPoint m_originalPos; + +}; + +/* + * Temporary arc label object + */ + +class wxLabelShape: public wxRectangleShape +{ + DECLARE_DYNAMIC_CLASS(wxLabelShape) + + public: + wxLabelShape(wxLineShape *parent = NULL, wxShapeRegion *region = NULL, double w = 0.0, double h = 0.0); + ~wxLabelShape(); + + void OnDraw(wxDC& dc); + void OnDrawContents(wxDC& dc); + 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 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); + bool OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display = TRUE); + +public: + wxLineShape* m_lineShape; + wxShapeRegion* m_shapeRegion; + +}; + +/* + * Get the point on the given line (x1, y1) (x2, y2) + * distance 'length' along from the end, + * returned values in x and y + */ + +void GetPointOnLine(double x1, double y1, double x2, double y2, + double length, double *x, double *y); + +#endif + // _OGL_LINESP_H_ + diff --git a/include/wx/ogl/mfutils.h b/include/wx/ogl/mfutils.h new file mode 100644 index 0000000000..b070e1781d --- /dev/null +++ b/include/wx/ogl/mfutils.h @@ -0,0 +1,211 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mfutils.h +// Purpose: Metafile utilities: reading a placeable metafile independently +// of Windows. +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _MFUTILS_H_ +#define _MFUTILS_H_ + +#ifdef __GNUG__ +#pragma interface "mfutils.h" +#endif + +#include + +#ifndef GetRValue +#define GetRValue(rgb) ((unsigned char)(rgb)) +#define GetGValue(rgb) ((unsigned char)(((int)(rgb)) >> 8)) +#define GetBValue(rgb) ((unsigned char)((rgb)>>16)) +#endif + +/* Metafile Functions */ +/* Win32s/Borland need these macros, although META_SETBKCOLOR is defined */ +#if 1 // !defined(META_SETBKCOLOR) // || defined(WIN32) + +#define META_SETBKCOLOR 0x0201 +#define META_SETBKMODE 0x0102 +#define META_SETMAPMODE 0x0103 +#define META_SETROP2 0x0104 +#define META_SETRELABS 0x0105 +#define META_SETPOLYFILLMODE 0x0106 +#define META_SETSTRETCHBLTMODE 0x0107 +#define META_SETTEXTCHAREXTRA 0x0108 +#define META_SETTEXTCOLOR 0x0209 +#define META_SETTEXTJUSTIFICATION 0x020A +#define META_SETWINDOWORG 0x020B +#define META_SETWINDOWEXT 0x020C +#define META_SETVIEWPORTORG 0x020D +#define META_SETVIEWPORTEXT 0x020E +#define META_OFFSETWINDOWORG 0x020F +#define META_SCALEWINDOWEXT 0x0410 +#define META_OFFSETVIEWPORTORG 0x0211 +#define META_SCALEVIEWPORTEXT 0x0412 +#define META_LINETO 0x0213 +#define META_MOVETO 0x0214 +#define META_EXCLUDECLIPRECT 0x0415 +#define META_INTERSECTCLIPRECT 0x0416 +#define META_ARC 0x0817 +#define META_ELLIPSE 0x0418 +#define META_FLOODFILL 0x0419 +#define META_PIE 0x081A +#define META_RECTANGLE 0x041B +#define META_ROUNDRECT 0x061C +#define META_PATBLT 0x061D +#define META_SAVEDC 0x001E +#define META_SETPIXEL 0x041F +#define META_OFFSETCLIPRGN 0x0220 +#define META_TEXTOUT 0x0521 +#define META_BITBLT 0x0922 +#define META_STRETCHBLT 0x0B23 +#define META_POLYGON 0x0324 +#define META_POLYLINE 0x0325 +#define META_ESCAPE 0x0626 +#define META_RESTOREDC 0x0127 +#define META_FILLREGION 0x0228 +#define META_FRAMEREGION 0x0429 +#define META_INVERTREGION 0x012A +#define META_PAINTREGION 0x012B +#define META_SELECTCLIPREGION 0x012C +#define META_SELECTOBJECT 0x012D +#define META_SETTEXTALIGN 0x012E +#define META_DRAWTEXT 0x062F + +#define META_CHORD 0x0830 +#define META_SETMAPPERFLAGS 0x0231 +#define META_EXTTEXTOUT 0x0a32 +#define META_SETDIBTODEV 0x0d33 +#define META_SELECTPALETTE 0x0234 +#define META_REALIZEPALETTE 0x0035 +#define META_ANIMATEPALETTE 0x0436 +#define META_SETPALENTRIES 0x0037 +#define META_POLYPOLYGON 0x0538 +#define META_RESIZEPALETTE 0x0139 + +#define META_DIBBITBLT 0x0940 +#define META_DIBSTRETCHBLT 0x0b41 +#define META_DIBCREATEPATTERNBRUSH 0x0142 +#define META_STRETCHDIB 0x0f43 + +#define META_EXTFLOODFILL 0x0548 + +#define META_RESETDC 0x014C +#define META_STARTDOC 0x014D +#define META_STARTPAGE 0x004F +#define META_ENDPAGE 0x0050 +#define META_ABORTDOC 0x0052 +#define META_ENDDOC 0x005E + +#define META_DELETEOBJECT 0x01f0 + +#define META_CREATEPALETTE 0x00f7 +#define META_CREATEBRUSH 0x00F8 +#define META_CREATEPATTERNBRUSH 0x01F9 +#define META_CREATEPENINDIRECT 0x02FA +#define META_CREATEFONTINDIRECT 0x02FB +#define META_CREATEBRUSHINDIRECT 0x02FC +#define META_CREATEBITMAPINDIRECT 0x02FD +#define META_CREATEBITMAP 0x06FE +#define META_CREATEREGION 0x06FF + +/* Background Modes */ +#define TRANSPARENT 1 +#define OPAQUE 2 + +/* Pen Styles */ +#define PS_SOLID 0 +#define PS_DASH 1 +#define PS_DOT 2 +#define PS_DASHDOT 3 +#define PS_DASHDOTDOT 4 +#define PS_NULL 5 +#define PS_INSIDEFRAME 6 + +/* PitchAndFamily family values (high 4 bits) */ +/* Win32s/Borland don't need this */ +#ifndef FF_DONTCARE // !defined(__BORLANDC__) && !defined(WIN32) +#define FF_DONTCARE 0x00 +#define FF_ROMAN 0x10 +#define FF_SWISS 0x20 +#define FF_MODERN 0x30 +#define FF_SCRIPT 0x40 +#define FF_DECORATIVE 0x50 +#endif + +/* Brush Styles */ +#define BS_SOLID 0 +#define BS_NULL 1 +#define BS_HOLLOW BS_NULL +#define BS_HATCHED 2 +#define BS_PATTERN 3 +#define BS_INDEXED 4 +#define BS_DIBPATTERN 5 + +/* Hatch Styles */ +#define HS_HORIZONTAL 0 +#define HS_VERTICAL 1 +#define HS_FDIAGONAL 2 +#define HS_BDIAGONAL 3 +#define HS_CROSS 4 +#define HS_DIAGCROSS 5 + +#endif // metafile functions + +class wxMetaRecord: public wxObject +{ + public: + int metaFunction; + long param1; + long param2; + long param3; + long param4; + long param5; + long param6; + long param7; + long param8; + char *stringParam; + wxRealPoint *points; + + wxMetaRecord(int fun) + { + metaFunction = fun; points = NULL; stringParam = NULL; + param1 = 0; + } + ~wxMetaRecord(void); +}; + +class wxXMetaFile: public wxObject +{ + public: + double lastX; + double lastY; + bool ok; + + double left; + double top; + double right; + double bottom; + + wxList metaRecords; + wxList gdiObjects; // List of wxMetaRecord objects created with Create..., + // referenced by position in list by SelectObject + wxXMetaFile(char *file = NULL); + ~wxXMetaFile(void); + + // After this is called, the metafile cannot be used for anything + // since it is now owned by the clipboard. + bool SetClipboard(int width = 0, int height = 0); + + bool Play(wxDC *dc); + inline bool Ok(void) const { return ok; } + bool ReadFile(char *file); +}; + +#endif + // _MFUTILS_H_ diff --git a/include/wx/ogl/misc.h b/include/wx/ogl/misc.h new file mode 100644 index 0000000000..4e6abfb6b2 --- /dev/null +++ b/include/wx/ogl/misc.h @@ -0,0 +1,113 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: misc.h +// Purpose: Miscellaneous utilities for OGL +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_MISC_H_ +#define _OGL_MISC_H_ + +#ifdef __GNUG__ +#pragma interface "misc.h" +#endif + +// List to use when copying objects; may need to associate elements of new objects +// with elements of old objects, e.g. when copying constraint.s +extern wxList oglObjectCopyMapping; + +/* + * TEXT FORMATTING FUNCTIONS + * + */ + +// Centres the given list of wxShapeTextLine strings in the given box +// (changing the positions in situ). Doesn't actually draw into the DC. +void oglCentreText(wxDC& dc, wxList *text, double m_xpos, double m_ypos, + double width, double height, + int formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT); + +// Given a string, returns a list of strings that fit within the given +// width of box. Height is ignored. +wxStringList *oglFormatText(wxDC& dc, const wxString& text, double width, double height, int formatMode = 0); + +// Centres the list of wxShapeTextLine strings, doesn't clip. +// Doesn't actually draw into the DC. +void oglCentreTextNoClipping(wxDC& dc, wxList *text_list, + double m_xpos, double m_ypos, double width, double height); + +// Gets the maximum width and height of the given list of wxShapeTextLines. +void oglGetCentredTextExtent(wxDC& dc, wxList *text_list, + double m_xpos, double m_ypos, double width, double height, + double *actual_width, double *actual_height); + +// Actually draw the preformatted list of wxShapeTextLines. +void oglDrawFormattedText(wxDC& context, wxList *text_list, + double m_xpos, double m_ypos, double width, double height, + int formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT); + +// Give it a list of points, finds the centre. +void oglFindPolylineCentroid(wxList *points, double *x, double *y); + +void oglCheckLineIntersection(double x1, double y1, double x2, double y2, + double x3, double y3, double x4, double y4, + double *ratio1, double *ratio2); + +void oglFindEndForPolyline(double n, double xvec[], double yvec[], + double x1, double y1, double x2, double y2, double *x3, double *y3); + + +void oglFindEndForBox(double width, double height, + double x1, double y1, // Centre of box (possibly) + double x2, double y2, // other end of line + double *x3, double *y3); // End on box edge + +void oglFindEndForCircle(double radius, + double x1, double y1, // Centre of circle + double x2, double y2, // Other end of line + double *x3, double *y3); + +void oglGetArrowPoints(double x1, double y1, double x2, double y2, + double length, double width, + double *tip_x, double *tip_y, + double *side1_x, double *side1_y, + double *side2_x, double *side2_y); + +/* + * Given an ellipse and endpoints of a line, returns the point at which + * the line touches the ellipse in values x4, y4. + * This function assumes that the centre of the ellipse is at x1, y1, and the + * ellipse has a width of a1 and a height of b1. It also assumes you are + * wanting to draw an arc FROM point x2, y2 TOWARDS point x3, y3. + * This function calculates the x,y coordinates of the intersection point of + * the arc with the ellipse. + * Author: Ian Harrison + */ + +void oglDrawArcToEllipse(double x1, double y1, double a1, double b1, double x2, double y2, double x3, double y3, + double *x4, double *y4); + +bool oglRoughlyEqual(double val1, double val2, double tol = 0.00001); + +extern wxFont* g_oglNormalFont; +extern wxPen* g_oglBlackPen; +extern wxPen* g_oglWhiteBackgroundPen; +extern wxPen* g_oglTransparentPen; +extern wxBrush* g_oglWhiteBackgroundBrush; +extern wxPen* g_oglBlackForegroundPen; +extern wxCursor* g_oglBullseyeCursor; + +extern wxFont* oglMatchFont(int point_size); + +extern wxString oglColourToHex(const wxColour& colour); +extern wxColour oglHexToColour(const wxString& hex); +extern void oglDecToHex(unsigned int dec, char *buf); +extern unsigned int oglHexToDec(char* buf); + + +#endif + // _OGL_MISC_H_ diff --git a/include/wx/ogl/ogl.h b/include/wx/ogl/ogl.h new file mode 100644 index 0000000000..a9eb003abe --- /dev/null +++ b/include/wx/ogl/ogl.h @@ -0,0 +1,27 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: ogl.h +// Purpose: OGL main include +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_OGL_H_ +#define _OGL_OGL_H_ + +#include // Basic shapes +#include // Lines and splines +#include // Vertically-divided rectangle +#include // Composite images +#include // wxShapeCanvas for displaying objects +#include // wxDiagram + +// TODO: replace with wxModule implementation +extern void wxOGLInitialize(); +extern void wxOGLCleanUp(); + +#endif + // _OGL_OGL_H_ diff --git a/include/wx/ogl/ogldiag.h b/include/wx/ogl/ogldiag.h new file mode 100644 index 0000000000..e06e1248f4 --- /dev/null +++ b/include/wx/ogl/ogldiag.h @@ -0,0 +1,124 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: ogldiag.h +// Purpose: OGL - wxDiagram class +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _OGL_OGLDIAG_H_ +#define _OGL_OGLDIAG_H_ + +#ifdef __GNUG__ +#pragma interface "ogldiag.h" +#endif + +#include "basic.h" + +class wxDiagram: public wxObject +{ + DECLARE_DYNAMIC_CLASS(wxDiagram) + +public: + + wxDiagram(); + virtual ~wxDiagram(); + + void SetCanvas(wxShapeCanvas *can); + + inline wxShapeCanvas *GetCanvas() const { return m_diagramCanvas; } + + virtual void Redraw(wxDC& dc); + virtual void Clear(wxDC& dc); + virtual void DrawOutline(wxDC& dc, double x1, double y1, double x2, double y2); + + // Add object to end of object list (if addAfter is NULL) + // or just after addAfter. + virtual void AddShape(wxShape *object, wxShape *addAfter = NULL); + + // Add object to front of object list + virtual void InsertShape(wxShape *object); + + void SetSnapToGrid(bool snap); + void SetGridSpacing(double spacing); + inline double GetGridSpacing() const { return m_gridSpacing; } + inline bool GetSnapToGrid() const { return m_snapToGrid; } + void Snap(double *x, double *y); + + inline void SetQuickEditMode(bool qem) { m_quickEditMode = qem; } + inline bool GetQuickEditMode() const { return m_quickEditMode; } + + virtual void RemoveShape(wxShape *object); + virtual void RemoveAllShapes(); + virtual void DeleteAllShapes(); + virtual void ShowAll(bool show); + + // Find a shape by its id + wxShape* FindShape(long id) const; + + inline void SetMouseTolerance(int tol) { m_mouseTolerance = tol; } + inline int GetMouseTolerance() const { return m_mouseTolerance; } + inline wxList *GetShapeList() const { return m_shapeList; } + inline int GetCount() const { return m_shapeList->Number(); } + + // Make sure all text that should be centred, is centred. + void RecentreAll(wxDC& dc); + +#ifdef PROLOGIO + virtual bool SaveFile(const wxString& filename); + virtual bool LoadFile(const wxString& filename); + + virtual void ReadNodes(wxExprDatabase& database); + virtual void ReadLines(wxExprDatabase& database); + virtual void ReadContainerGeometry(wxExprDatabase& database); + + // Allow for modifying file + virtual bool OnDatabaseLoad(wxExprDatabase& db); + virtual bool OnDatabaseSave(wxExprDatabase& db); + virtual bool OnShapeSave(wxExprDatabase& db, wxShape& shape, wxExpr& expr); + virtual bool OnShapeLoad(wxExprDatabase& db, wxShape& shape, wxExpr& expr); + virtual bool OnHeaderSave(wxExprDatabase& db, wxExpr& expr); + virtual bool OnHeaderLoad(wxExprDatabase& db, wxExpr& expr); +#endif + +protected: + wxShapeCanvas* m_diagramCanvas; + bool m_quickEditMode; + bool m_snapToGrid; + double m_gridSpacing; + int m_mouseTolerance; + wxList* m_shapeList; +}; + +class wxLineCrossing: public wxObject +{ +public: + wxLineCrossing() { m_lineShape1 = NULL; m_lineShape2 = NULL; } + wxRealPoint m_pt1; // First line + wxRealPoint m_pt2; + wxRealPoint m_pt3; // Second line + wxRealPoint m_pt4; + wxRealPoint m_intersect; + wxLineShape* m_lineShape1; + wxLineShape* m_lineShape2; +}; + +class wxLineCrossings: public wxObject +{ +public: + wxLineCrossings(); + ~wxLineCrossings(); + + void FindCrossings(wxDiagram& diagram); + void DrawCrossings(wxDiagram& diagram, wxDC& dc); + void ClearCrossings(); + +public: + wxList m_crossings; +}; + +#endif + // _OGL_OGLDIAG_H_ diff --git a/samples/ogl/ogledit/Makefile b/samples/ogl/ogledit/Makefile new file mode 100644 index 0000000000..1ed28860e7 --- /dev/null +++ b/samples/ogl/ogledit/Makefile @@ -0,0 +1,39 @@ +# +# File: Makefile +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: (c) 2000 Julian Smart +# +# Makefile for OGL demo (GTK version) +# +# This makefile requires wxWindows/GTK to be +# installed (possibly using "make install") +# on your system. +# + +CPP = gcc +CC = gcc +WXCONFIG=../../../../wx-config +WXINCLUDE=-I../../../../include +WXLIB=-L../../../../lib + +OBJECTS=ogledit.o palette.o doc.o view.o + +ogledit: $(OBJECTS) + $(CPP) -o ogledit $(OBJECTS) `$(WXCONFIG) --libs` $(WXLIB) -logl + +ogledit.o: ogledit.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c ogledit.cpp + +palette.o: palette.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c palette.cpp + +doc.o: doc.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c doc.cpp + +view.o: view.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c view.cpp + +clean: + rm -f *.o ogledit diff --git a/samples/ogl/ogledit/bitmaps/arrow.bmp b/samples/ogl/ogledit/bitmaps/arrow.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d406ceb64f017d99bcc2d4913aef75135de357a0 GIT binary patch literal 382 zcmb7-I}UJZQ>1WPN=;5qEQ3zc?;o59U+Ka+r!5!mH1Gr)e_0X9zQo7Bn*m`tDP z>tSJ;fdXA9#W(4KsI?;JEJm}1)|8}VswC~|bu-BQ Vombvu=JhAub(#Nm-N`e*_yJ^>eVzaS literal 0 HcmV?d00001 diff --git a/samples/ogl/ogledit/bitmaps/arrow.xpm b/samples/ogl/ogledit/bitmaps/arrow.xpm new file mode 100644 index 0000000000..d3807cbf4e --- /dev/null +++ b/samples/ogl/ogledit/bitmaps/arrow.xpm @@ -0,0 +1,44 @@ +/* XPM */ +static char *arrow_xpm[] = { +/* columns rows colors chars-per-pixel */ +"22 22 16 1", +" c Gray0", +". c #bf0000", +"X c #00bf00", +"o c #bfbf00", +"O c #0000bf", +"+ c #bf00bf", +"@ c #00bfbf", +"# c #c0c0c0", +"$ c #808080", +"% c Red", +"& c Green", +"* c Yellow", +"= c Blue", +"- c Magenta", +"; c Cyan", +": c Gray100", +/* pixels */ +"######################", +"######################", +"######################", +"######################", +"######################", +"####### ##############", +"####### #############", +"####### ############", +"####### ###########", +"####### ##########", +"####### #########", +"####### ########", +"####### #######", +"####### ##########", +"####### # ##########", +"####### ### #########", +"########### #########", +"############ ########", +"############ ########", +"######################", +"######################", +"######################" +}; diff --git a/samples/ogl/ogledit/bitmaps/tool1.bmp b/samples/ogl/ogledit/bitmaps/tool1.bmp new file mode 100644 index 0000000000000000000000000000000000000000..cb1760d2859cd5b32630cb6c294a6c913d4b28f3 GIT binary patch literal 382 zcmZ?rtz%>WgEAng0mNcZ%*en37UzJJQ409!#Op@kUh#ZHNo5<&TT>4iR1ivT=$yRS#8XFECq!-*mgr LV^3-JfBEkPyAH!9 literal 0 HcmV?d00001 diff --git a/samples/ogl/ogledit/bitmaps/tool2.xpm b/samples/ogl/ogledit/bitmaps/tool2.xpm new file mode 100644 index 0000000000..612dbf01bb --- /dev/null +++ b/samples/ogl/ogledit/bitmaps/tool2.xpm @@ -0,0 +1,44 @@ +/* XPM */ +static char *tool2_xpm[] = { +/* columns rows colors chars-per-pixel */ +"22 22 16 1", +" c Gray0", +". c #bf0000", +"X c #00bf00", +"o c #bfbf00", +"O c #0000bf", +"+ c #bf00bf", +"@ c #00bfbf", +"# c #c0c0c0", +"$ c #808080", +"% c Red", +"& c Green", +"* c Yellow", +"= c Blue", +"- c Magenta", +"; c Cyan", +": c Gray100", +/* pixels */ +"######################", +"######################", +"#### #####", +"### ::::::::::::: ####", +"## ::::::::::::::: ###", +"# ::::::::::::::::: ##", +"# ::::::::::::::::: ##", +"# ::::::::::::::::: ##", +"# ::::::::::::::::: ##", +"# ::::::::::::::::: ##", +"# ::::::::::::::::: ##", +"# ::::::::::::::::: ##", +"# ::::::::::::::::: ##", +"# ::::::::::::::::: ##", +"# ::::::::::::::::: ##", +"# ::::::::::::::::: ##", +"## ::::::::::::::: ###", +"### ::::::::::::: ####", +"#### #####", +"######################", +"######################", +"######################" +}; diff --git a/samples/ogl/ogledit/bitmaps/tool3.bmp b/samples/ogl/ogledit/bitmaps/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@Q8CoZa7Pu)am`?}1?Jt#_EJF0 + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#if !wxUSE_DOC_VIEW_ARCHITECTURE +#error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h! +#endif + +#include +#include "ogledit.h" +#include "doc.h" +#include "view.h" + +#if wxUSE_STD_IOSTREAM +#include +#endif + +IMPLEMENT_DYNAMIC_CLASS(DiagramDocument, wxDocument) + +DiagramDocument::DiagramDocument(void) +{ +} + +DiagramDocument::~DiagramDocument(void) +{ +} + +bool DiagramDocument::OnCloseDocument(void) +{ + diagram.DeleteAllShapes(); + return TRUE; +} + +#if wxUSE_STD_IOSTREAM +ostream& DiagramDocument::SaveObject(ostream& stream) +{ + wxDocument::SaveObject(stream); + + char buf[400]; + (void) wxGetTempFileName("diag", buf); + + diagram.SaveFile(buf); + wxTransferFileToStream(buf, stream); + + wxRemoveFile(buf); + + return stream; +} + +istream& DiagramDocument::LoadObject(istream& stream) +{ + wxDocument::LoadObject(stream); + + char buf[400]; + (void) wxGetTempFileName("diag", buf); + + wxTransferStreamToFile(stream, buf); + + diagram.DeleteAllShapes(); + diagram.LoadFile(buf); + wxRemoveFile(buf); + + return stream; +} +#else + +wxOutputStream& DiagramDocument::SaveObject(wxOutputStream& stream) +{ + wxDocument::SaveObject(stream); + char buf[400]; + (void) wxGetTempFileName("diag", buf); + + diagram.SaveFile(buf); + + wxTransferFileToStream(buf, stream); + + wxRemoveFile(buf); + + + return stream; +} + +wxInputStream& DiagramDocument::LoadObject(wxInputStream& stream) +{ + wxDocument::LoadObject(stream); + + + char buf[400]; + (void) wxGetTempFileName("diag", buf); + + wxTransferStreamToFile(stream, buf); + + diagram.DeleteAllShapes(); + diagram.LoadFile(buf); + wxRemoveFile(buf); + + return stream; +} + +#endif + +/* + * Implementation of drawing command + */ + +DiagramCommand::DiagramCommand(char *name, int command, DiagramDocument *ddoc, wxClassInfo *info, double xx, double yy, + bool sel, wxShape *theShape, wxShape *fs, wxShape *ts): + wxCommand(TRUE, name) +{ + doc = ddoc; + cmd = command; + shape = theShape; + fromShape = fs; + toShape = ts; + shapeInfo = info; + shapeBrush = NULL; + shapePen = NULL; + x = xx; + y = yy; + selected = sel; + deleteShape = FALSE; +} + +DiagramCommand::DiagramCommand(char *name, int command, DiagramDocument *ddoc, wxBrush *backgroundColour, wxShape *theShape): + wxCommand(TRUE, name) +{ + doc = ddoc; + cmd = command; + shape = theShape; + fromShape = NULL; + toShape = NULL; + shapeInfo = NULL; + x = 0.0; + y = 0.0; + selected = FALSE; + deleteShape = FALSE; + shapeBrush = backgroundColour; + shapePen = NULL; +} + +DiagramCommand::DiagramCommand(char *name, int command, DiagramDocument *ddoc, const wxString& lab, wxShape *theShape): + wxCommand(TRUE, name) +{ + doc = ddoc; + cmd = command; + shape = theShape; + fromShape = NULL; + toShape = NULL; + shapeInfo = NULL; + x = 0.0; + y = 0.0; + selected = FALSE; + deleteShape = FALSE; + shapeBrush = NULL; + shapePen = NULL; + shapeLabel = lab; +} + +DiagramCommand::~DiagramCommand(void) +{ + if (shape && deleteShape) + { + shape->SetCanvas(NULL); + delete shape; + } +} + +bool DiagramCommand::Do(void) +{ + switch (cmd) + { + case OGLEDIT_CUT: + { + if (shape) + { + deleteShape = TRUE; + + shape->Select(FALSE); + + // Generate commands to explicitly remove each connected line. + RemoveLines(shape); + + doc->GetDiagram()->RemoveShape(shape); + if (shape->IsKindOf(CLASSINFO(wxLineShape))) + { + wxLineShape *lineShape = (wxLineShape *)shape; + fromShape = lineShape->GetFrom(); + toShape = lineShape->GetTo(); + } + shape->Unlink(); + + doc->Modify(TRUE); + doc->UpdateAllViews(); + } + + break; + } + case OGLEDIT_ADD_SHAPE: + { + wxShape *theShape = NULL; + if (shape) + theShape = shape; // Saved from undoing the shape + else + { + theShape = (wxShape *)shapeInfo->CreateObject(); + theShape->AssignNewIds(); + theShape->SetEventHandler(new MyEvtHandler(theShape, theShape, wxString(""))); + theShape->SetCentreResize(FALSE); + theShape->SetPen(wxBLACK_PEN); + theShape->SetBrush(wxCYAN_BRUSH); + + theShape->SetSize(60, 60); + } + doc->GetDiagram()->AddShape(theShape); + theShape->Show(TRUE); + + wxClientDC dc(theShape->GetCanvas()); + theShape->GetCanvas()->PrepareDC(dc); + + theShape->Move(dc, x, y); + + shape = theShape; + deleteShape = FALSE; + + doc->Modify(TRUE); + doc->UpdateAllViews(); + break; + } + case OGLEDIT_ADD_LINE: + { + wxShape *theShape = NULL; + if (shape) + theShape = shape; // Saved from undoing the line + else + { + theShape = (wxShape *)shapeInfo->CreateObject(); + theShape->AssignNewIds(); + theShape->SetEventHandler(new MyEvtHandler(theShape, theShape, wxString(""))); + theShape->SetPen(wxBLACK_PEN); + theShape->SetBrush(wxRED_BRUSH); + + 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); + lineShape->AddArrow(ARROW_ARROW, ARROW_POSITION_END, 10.0, 0.0, "Normal arrowhead"); + } + + doc->GetDiagram()->AddShape(theShape); + + fromShape->AddLine((wxLineShape *)theShape, toShape); + + theShape->Show(TRUE); + + wxClientDC dc(theShape->GetCanvas()); + theShape->GetCanvas()->PrepareDC(dc); + + // It won't get drawn properly unless you move both + // connected images + fromShape->Move(dc, fromShape->GetX(), fromShape->GetY()); + toShape->Move(dc, toShape->GetX(), toShape->GetY()); + + shape = theShape; + deleteShape = FALSE; + + doc->Modify(TRUE); + doc->UpdateAllViews(); + break; + } + case OGLEDIT_CHANGE_BACKGROUND_COLOUR: + { + if (shape) + { + wxClientDC dc(shape->GetCanvas()); + shape->GetCanvas()->PrepareDC(dc); + + wxBrush *oldBrush = shape->GetBrush(); + shape->SetBrush(shapeBrush); + shapeBrush = oldBrush; + shape->Draw(dc); + + doc->Modify(TRUE); + doc->UpdateAllViews(); + } + + break; + } + case OGLEDIT_EDIT_LABEL: + { + if (shape) + { + MyEvtHandler *myHandler = (MyEvtHandler *)shape->GetEventHandler(); + wxString oldLabel(myHandler->label); + myHandler->label = shapeLabel; + shapeLabel = oldLabel; + + wxClientDC dc(shape->GetCanvas()); + shape->GetCanvas()->PrepareDC(dc); + + shape->FormatText(dc, (char*) (const char*) myHandler->label); + shape->Draw(dc); + + doc->Modify(TRUE); + doc->UpdateAllViews(); + } + + break; + } + } + return TRUE; +} + +bool DiagramCommand::Undo(void) +{ + switch (cmd) + { + case OGLEDIT_CUT: + { + if (shape) + { + doc->GetDiagram()->AddShape(shape); + shape->Show(TRUE); + + if (shape->IsKindOf(CLASSINFO(wxLineShape))) + { + wxLineShape *lineShape = (wxLineShape *)shape; + + fromShape->AddLine(lineShape, toShape); + } + if (selected) + shape->Select(TRUE); + + deleteShape = FALSE; + } + doc->Modify(TRUE); + doc->UpdateAllViews(); + break; + } + case OGLEDIT_ADD_SHAPE: + case OGLEDIT_ADD_LINE: + { + if (shape) + { + wxClientDC dc(shape->GetCanvas()); + shape->GetCanvas()->PrepareDC(dc); + + shape->Select(FALSE, &dc); + doc->GetDiagram()->RemoveShape(shape); + shape->Unlink(); + deleteShape = TRUE; + } + doc->Modify(TRUE); + doc->UpdateAllViews(); + break; + } + case OGLEDIT_CHANGE_BACKGROUND_COLOUR: + { + if (shape) + { + wxClientDC dc(shape->GetCanvas()); + shape->GetCanvas()->PrepareDC(dc); + + wxBrush *oldBrush = shape->GetBrush(); + shape->SetBrush(shapeBrush); + shapeBrush = oldBrush; + shape->Draw(dc); + + doc->Modify(TRUE); + doc->UpdateAllViews(); + } + break; + } + case OGLEDIT_EDIT_LABEL: + { + if (shape) + { + MyEvtHandler *myHandler = (MyEvtHandler *)shape->GetEventHandler(); + wxString oldLabel(myHandler->label); + myHandler->label = shapeLabel; + shapeLabel = oldLabel; + + wxClientDC dc(shape->GetCanvas()); + shape->GetCanvas()->PrepareDC(dc); + + shape->FormatText(dc, (char*) (const char*) myHandler->label); + shape->Draw(dc); + + doc->Modify(TRUE); + doc->UpdateAllViews(); + } + + break; + } + } + return TRUE; +} + +// Remove each individual line connected to a shape by sending a command. +void DiagramCommand::RemoveLines(wxShape *shape) +{ + wxNode *node = shape->GetLines().First(); + while (node) + { + wxLineShape *line = (wxLineShape *)node->Data(); + doc->GetCommandProcessor()->Submit(new DiagramCommand("Cut", OGLEDIT_CUT, doc, NULL, 0.0, 0.0, line->Selected(), line)); + + node = shape->GetLines().First(); + } +} + +/* + * MyEvtHandler: an event handler class for all shapes + */ + +void MyEvtHandler::OnLeftClick(double x, double y, int keys, int attachment) +{ + wxClientDC dc(GetShape()->GetCanvas()); + GetShape()->GetCanvas()->PrepareDC(dc); + + if (keys == 0) + { + // Selection is a concept the library knows about + if (GetShape()->Selected()) + { + GetShape()->Select(FALSE, &dc); + GetShape()->GetCanvas()->Redraw(dc); // Redraw because bits of objects will be are missing + } + else + { + // Ensure no other shape is selected, to simplify Undo/Redo code + bool redraw = FALSE; + wxNode *node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First(); + while (node) + { + wxShape *eachShape = (wxShape *)node->Data(); + if (eachShape->GetParent() == NULL) + { + if (eachShape->Selected()) + { + eachShape->Select(FALSE, &dc); + redraw = TRUE; + } + } + node = node->Next(); + } + GetShape()->Select(TRUE, &dc); + if (redraw) + GetShape()->GetCanvas()->Redraw(dc); + } + } + else if (keys & KEY_CTRL) + { + // Do something for CONTROL + } + else + { + wxGetApp().frame->SetStatusText(label); + } +} + +/* + * Implement connection of two shapes by right-dragging between them. + */ + +void MyEvtHandler::OnBeginDragRight(double x, double y, int keys, int attachment) +{ + // Force attachment to be zero for now. Eventually we can deal with + // the actual attachment point, e.g. a rectangle side if attachment mode is on. + attachment = 0; + + wxClientDC dc(GetShape()->GetCanvas()); + GetShape()->GetCanvas()->PrepareDC(dc); + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetLogicalFunction(OGLRBLF); + dc.SetPen(dottedPen); + double xp, yp; + GetShape()->GetAttachmentPosition(attachment, &xp, &yp); + dc.DrawLine((long) xp, (long) yp, (long) x, (long) y); + GetShape()->GetCanvas()->CaptureMouse(); +} + +void MyEvtHandler::OnDragRight(bool draw, double x, double y, int keys, int attachment) +{ + // Force attachment to be zero for now + attachment = 0; + + wxClientDC dc(GetShape()->GetCanvas()); + GetShape()->GetCanvas()->PrepareDC(dc); + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetLogicalFunction(OGLRBLF); + dc.SetPen(dottedPen); + double xp, yp; + GetShape()->GetAttachmentPosition(attachment, &xp, &yp); + dc.DrawLine((long) xp, (long) yp, (long) x, (long) y); +} + +void MyEvtHandler::OnEndDragRight(double x, double y, int keys, int attachment) +{ + GetShape()->GetCanvas()->ReleaseMouse(); + MyCanvas *canvas = (MyCanvas *)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))) + { + canvas->view->GetDocument()->GetCommandProcessor()->Submit( + new DiagramCommand("wxLineShape", OGLEDIT_ADD_LINE, (DiagramDocument *)canvas->view->GetDocument(), CLASSINFO(wxLineShape), + 0.0, 0.0, FALSE, NULL, GetShape(), otherShape)); + } +} + +void MyEvtHandler::OnEndSize(double x, double y) +{ + wxClientDC dc(GetShape()->GetCanvas()); + GetShape()->GetCanvas()->PrepareDC(dc); + + GetShape()->FormatText(dc, (char*) (const char*) label); +} + +/* + * Diagram + */ + +bool MyDiagram::OnShapeSave(wxExprDatabase& db, wxShape& shape, wxExpr& expr) +{ + wxDiagram::OnShapeSave(db, shape, expr); + MyEvtHandler *handler = (MyEvtHandler *)shape.GetEventHandler(); + expr.AddAttributeValueString("label", handler->label); + return TRUE; +} + +bool MyDiagram::OnShapeLoad(wxExprDatabase& db, wxShape& shape, wxExpr& expr) +{ + wxDiagram::OnShapeLoad(db, shape, expr); + char *label = NULL; + expr.AssignAttributeValue("label", &label); + MyEvtHandler *handler = new MyEvtHandler(&shape, &shape, wxString(label)); + shape.SetEventHandler(handler); + + if (label) + delete[] label; + return TRUE; +} + +/* + * New shapes + */ + +IMPLEMENT_DYNAMIC_CLASS(wxRoundedRectangleShape, wxRectangleShape) + +wxRoundedRectangleShape::wxRoundedRectangleShape(double w, double h): + wxRectangleShape(w, h) +{ + // 0.3 of the smaller rectangle dimension + SetCornerRadius((double) -0.3); +} + +IMPLEMENT_DYNAMIC_CLASS(wxDiamondShape, wxPolygonShape) + +wxDiamondShape::wxDiamondShape(double w, double h): + wxPolygonShape() +{ + // wxPolygonShape::SetSize relies on the shape having non-zero + // size initially. + if (w == 0.0) + w = 60.0; + if (h == 0.0) + h = 60.0; + + wxList *thePoints = new wxList; + wxRealPoint *point = new wxRealPoint(0.0, (-h/2.0)); + thePoints->Append((wxObject*) point); + + point = new wxRealPoint((w/2.0), 0.0); + thePoints->Append((wxObject*) point); + + point = new wxRealPoint(0.0, (h/2.0)); + thePoints->Append((wxObject*) point); + + point = new wxRealPoint((-w/2.0), 0.0); + thePoints->Append((wxObject*) point); + + Create(thePoints); +} diff --git a/samples/ogl/ogledit/doc.h b/samples/ogl/ogledit/doc.h new file mode 100644 index 0000000000..09a841d494 --- /dev/null +++ b/samples/ogl/ogledit/doc.h @@ -0,0 +1,182 @@ +///////////////////////////////////////////////////////////////////////////// +// 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 _OGLSAMPLE_DOC_H_ +#define _OGLSAMPLE_DOC_H_ + +#ifdef __GNUG__ +// #pragma interface +#endif + +#include +#include +#include + +#include + +#if wxUSE_STD_IOSTREAM +class ostream; +class istream; +#endif + +/* + * Override a few members for this application + */ + +class MyDiagram: public wxDiagram +{ + public: + MyDiagram(void) {} + bool OnShapeSave(wxExprDatabase& db, wxShape& shape, wxExpr& expr); + bool OnShapeLoad(wxExprDatabase& db, wxShape& shape, wxExpr& expr); +}; + +/* + * A few new shape classes so we have a 1:1 mapping + * between palette symbol and unique class + */ + +class wxRoundedRectangleShape: public wxRectangleShape +{ + DECLARE_DYNAMIC_CLASS(wxRoundedRectangleShape) + private: + public: + wxRoundedRectangleShape(double w = 0.0, double h = 0.0); +}; + +class wxDiamondShape: public wxPolygonShape +{ + DECLARE_DYNAMIC_CLASS(wxDiamondShape) + private: + public: + wxDiamondShape(double w = 0.0, double h = 0.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 MyEvtHandler: public wxShapeEvtHandler +{ + public: + wxString label; + MyEvtHandler(wxShapeEvtHandler *prev = NULL, wxShape *shape = NULL, const wxString& lab = ""):wxShapeEvtHandler(prev, shape) + { + label = lab; + } + ~MyEvtHandler(void) + { + } + void OnLeftClick(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); +}; + +/* + * A diagram document, which contains a diagram. + */ + +class DiagramDocument: public wxDocument +{ + DECLARE_DYNAMIC_CLASS(DiagramDocument) + private: + public: + MyDiagram diagram; + + DiagramDocument(void); + ~DiagramDocument(void); + +#if wxUSE_STD_IOSTREAM + virtual ostream& SaveObject(ostream& stream); + virtual istream& LoadObject(istream& stream); +#else + virtual wxOutputStream& SaveObject(wxOutputStream& stream); + virtual wxInputStream& LoadObject(wxInputStream& stream); +#endif + + inline wxDiagram *GetDiagram() { return &diagram; } + + bool OnCloseDocument(void); +}; + +/* + * Most user interface commands are routed through this, to give us the + * Undo/Redo mechanism. If you add more commands, such as changing the shape colour, + * you will need to add members to 'remember' what the user applied (for 'Do') and what the + * previous state was (for 'Undo'). + * You can have one member for each property to be changed. Assume we also have + * a pointer member wxShape *shape, which is set to the shape being changed. + * Let's assume we're changing the shape colour. Our member for this is shapeColour. + * + * - In 'Do': + * o Set a temporary variable 'temp' to the current colour for 'shape'. + * o Change the colour to the new colour. + * o Set shapeColour to the _old_ colour, 'temp'. + * - In 'Undo': + * o Set a temporary variable 'temp' to the current colour for 'shape'. + * o Change the colour to shapeColour (the old colour). + * o Set shapeColour to 'temp'. + * + * So, as long as we have a pointer to the shape being changed, + * we only need one member variable for each property. + * + * PROBLEM: when an Add shape command is redone, the 'shape' pointer changes. + * Assume, as here, that we keep a pointer to the old shape so we reuse it + * when we recreate. + */ + +class DiagramCommand: public wxCommand +{ + protected: + DiagramDocument *doc; + int cmd; + wxShape *shape; // Pointer to the shape we're acting on + wxShape *fromShape; + wxShape *toShape; + wxClassInfo *shapeInfo; + double x; + double y; + bool selected; + bool deleteShape; + + // Storage for property commands + wxBrush *shapeBrush; + wxPen *shapePen; + wxString shapeLabel; + public: + // Multi-purpose constructor for creating, deleting shapes + DiagramCommand(char *name, int cmd, DiagramDocument *ddoc, wxClassInfo *shapeInfo = NULL, + double x = 0.0, double y = 0.0, bool sel = FALSE, wxShape *theShape = NULL, wxShape *fs = NULL, wxShape *ts = NULL); + + // Property-changing command constructors + DiagramCommand(char *name, int cmd, DiagramDocument *ddoc, wxBrush *backgroundColour, wxShape *theShape); + DiagramCommand(char *name, int cmd, DiagramDocument *ddoc, const wxString& lab, wxShape *theShape); + + ~DiagramCommand(void); + + bool Do(void); + bool Undo(void); + + inline void SetShape(wxShape *s) { shape = s; } + inline wxShape *GetShape(void) { return shape; } + inline wxShape *GetFromShape(void) { return fromShape; } + inline wxShape *GetToShape(void) { return toShape; } + inline wxClassInfo *GetShapeInfo(void) { return shapeInfo; } + inline bool GetSelected(void) { return selected; } + + void RemoveLines(wxShape *shape); +}; + +#endif + // _OGLSAMPLE_DOC_H_ diff --git a/samples/ogl/ogledit/makefile.b32 b/samples/ogl/ogledit/makefile.b32 new file mode 100644 index 0000000000..7ee48625c2 --- /dev/null +++ b/samples/ogl/ogledit/makefile.b32 @@ -0,0 +1,18 @@ +# +# File: makefile.b32 +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: +# +# Makefile : Builds sample for 32-bit BC++ + +WXDIR = $(WXWIN) + +TARGET=ogledit +EXTRALIBS=$(WXDIR)\lib\ogl.lib +EXTRACPPFLAGS=-I$(WXDIR)\utils\ogl\src +OBJECTS = $(TARGET).obj doc.obj view.obj palette.obj + +!include $(WXDIR)\src\makeprog.b32 + diff --git a/samples/ogl/ogledit/makefile.bcc b/samples/ogl/ogledit/makefile.bcc new file mode 100644 index 0000000000..171d966ebd --- /dev/null +++ b/samples/ogl/ogledit/makefile.bcc @@ -0,0 +1,21 @@ +# +# File: makefile.bcc +# Author: Julian Smart +# Created: 1998 +# Updated: +# +# Builds a BC++ 16-bit sample + +!if "$(WXWIN)" == "" +!error You must define the WXWIN variable in autoexec.bat, e.g. WXWIN=c:\wx +!endif + +WXDIR = $(WXWIN) + +TARGET=ogledit +EXTRALIBS=$(WXDIR)\lib\ogl.lib +EXTRACPPFLAGS=-I$(WXDIR)\utils\ogl\src +OBJECTS = $(TARGET).obj doc.obj view.obj palette.obj + +!include $(WXDIR)\src\makeprog.b32 + diff --git a/samples/ogl/ogledit/makefile.dos b/samples/ogl/ogledit/makefile.dos new file mode 100644 index 0000000000..34eb326437 --- /dev/null +++ b/samples/ogl/ogledit/makefile.dos @@ -0,0 +1,103 @@ +# +# File: makefile.dos +# Author: Julian Smart +# Created: 1995 +# Updated: +# Copyright: (c) 1995, AIAI, University of Edinburgh +# +# "%W% %G%" +# +# Makefile : Builds OGLEdit example (MSVC++ 1.5). +# Use FINAL=1 argument to nmake to build final version with no debugging +# info + +WXDIR = $(WXWIN) + +!include $(WXDIR)\src\makemsc.env + +THISDIR = $(WXDIR)\utils\ogl\samples\ogledit +WXLIB = $(WXDIR)\lib\wx.lib + +OGLDIR = $(WXDIR)\utils\ogl +OGLINC = $(OGLDIR)\src +OGLLIB = $(OGLDIR)\lib\ogl.lib + +LIBS=$(WXLIB) $(OGLLIB) oldnames libw llibcew commdlg shell ddeml + +EXTRAFLAGS=/I$(OGLINC) + +OBJECTS = ogledit.obj doc.obj view.obj palette.obj + +all: ogledit.exe + +wx: + cd $(WXDIR)\src\msw + nmake -f makefile.dos + cd $(THISDIR) + +wxclean: + cd $(WXDIR)\src\msw + nmake -f makefile.dos clean + cd $(THISDIR) + +ogl: + cd $(OGLDIR)\src + nmake -f makefile.dos FINAL=$(FINAL) + cd $(THISDIR) + +prologio: + cd $(PROLOGDIR)\src + nmake -f makefile.dos FINAL=$(FINAL) + cd $(THISDIR) + +ogledit.exe: $(WXDIR)\src\msw\dummy.obj $(WXLIB) $(OBJECTS) $(OGLLIB) ogledit.def ogledit.res + link $(LINKFLAGS) @<< +$(WXDIR)\src\msw\dummy.obj $(OBJECTS), +ogledit, +NUL, +$(LIBS), +ogledit.def +; +<< + rc -30 -K ogledit.res + +ogledit.obj: ogledit.h ogledit.$(SRCSUFF) + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +view.obj: view.h view.$(SRCSUFF) + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +doc.obj: doc.h doc.$(SRCSUFF) + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +palette.obj: view.h doc.h ogledit.h palette.$(SRCSUFF) $(DUMMYOBJ) + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +ogledit.res : ogledit.rc $(WXDIR)\include\msw\wx.rc + rc -r /dFAFA_LIB /i$(WXDIR)\contrib\fafa /i$(WXDIR)\include\msw ogledit + +clean: + -erase *.obj + -erase *.exe + -erase *.res + -erase *.map + -erase *.sbr + -erase *.pdb + +cleanogl: + cd $(OGLDIR)\src + nmake -f makefile.dos clean + cd $(THISDIR) + +cleanall: + cd $(OGLDIR)\src + nmake -f makefile.dos clean + cd $(THISDIR) \ No newline at end of file diff --git a/samples/ogl/ogledit/makefile.g95 b/samples/ogl/ogledit/makefile.g95 new file mode 100644 index 0000000000..633e5b88e4 --- /dev/null +++ b/samples/ogl/ogledit/makefile.g95 @@ -0,0 +1,18 @@ +# +# File: makefile.g95 +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: (c) Julian Smart, 1999 +# +# Makefile for wxWindows sample (Cygwin/Mingw32). + +WXDIR = ../../../.. + +TARGET=ogledit +EXTRACPPFLAGS=-I../../src +EXTRALIBS=-logl +OBJECTS = $(TARGET).o doc.o view.o palette.o + +include $(WXDIR)/src/makeprog.g95 + diff --git a/samples/ogl/ogledit/makefile.sc b/samples/ogl/ogledit/makefile.sc new file mode 100644 index 0000000000..03da92bcd0 --- /dev/null +++ b/samples/ogl/ogledit/makefile.sc @@ -0,0 +1,33 @@ +# Symantec C++ makefile for docview example +# NOTE that peripheral libraries are now dealt in main wxWindows makefile. + +WXDIR = $(WXWIN) +include $(WXDIR)\src\makesc.env + +WXLIB = $(WXDIR)\lib\wx.lib +INCDIR = $(WXDIR)\include +MSWINC = $(INCDIR)\msw +BASEINC = $(INCDIR)\base + +INCLUDE=$(BASEINC);$(MSWINC) + +LIBS=$(WXLIB) libw.lib commdlg.lib shell.lib + +OBJECTS=docview.obj view.obj doc.obj + +.$(SRCSUFF).obj: + *$(CC) -c $(CFLAGS) -I$(INCLUDE) $< + +.rc.res: + *$(RC) -r -I$(INCLUDE) $< + +docview.exe: $(OBJECTS) docview.def docview.res + *$(CC) $(LDFLAGS) -o$@ $(OBJECTS) docview.def $(LIBS) + *$(RC) -k docview.res + +clean: + -del *.obj + -del *.exe + -del *.res + -del *.map + -del *.rws diff --git a/samples/ogl/ogledit/makefile.unx b/samples/ogl/ogledit/makefile.unx new file mode 100644 index 0000000000..0038ddc0b4 --- /dev/null +++ b/samples/ogl/ogledit/makefile.unx @@ -0,0 +1,20 @@ +# +# File: makefile.unx +# Author: Julian Smart +# Created: 1998 +# Updated: +# Copyright: (c) 1998 Julian Smart +# +# "%W% %G%" +# +# Makefile for OGLEdit example (UNIX). + +PROGRAM=ogledit + +OBJECTS=$(PROGRAM).o doc.o view.o palette.o + +EXTRACPPFLAGS=-I$(WXDIR)/utils/ogl/src +EXTRALDLIBS=-logl$(GUISUFFIX) + +include ../../../../src/makeprog.env + diff --git a/samples/ogl/ogledit/makefile.vc b/samples/ogl/ogledit/makefile.vc new file mode 100644 index 0000000000..d4c3e723c2 --- /dev/null +++ b/samples/ogl/ogledit/makefile.vc @@ -0,0 +1,95 @@ +# +# File: makefile.vc +# Author: Julian Smart +# Created: 1993 +# Updated: +# Copyright: (c) 1993, AIAI, University of Edinburgh +# +# "%W% %G%" +# +# Makefile : Builds docview example (MS VC++). +# Use FINAL=1 argument to nmake to build final version with no debugging +# info + +# Set WXDIR for your system +WXDIR = $(WXWIN) + +!include $(WXDIR)\src\makevc.env + +THISDIR = $(WXDIR)\utils\ogl\samples\ogledit + +OGLDIR = $(WXDIR)\utils\ogl +OGLINC = $(OGLDIR)\src +OGLLIB = $(WXDIR)\lib\ogl$(LIBEXT).lib + +PROGRAM=ogledit + +EXTRALIBS=$(OGLLIB) +EXTRAINC=/I$(OGLINC) + +OBJECTS = $(PROGRAM).obj doc.obj view.obj palette.obj + +$(PROGRAM): $(PROGRAM).exe + +all: $(PROGRAM).exe + +wx: + cd $(WXDIR)\src\msw + nmake -f makefile.vc FINAL=$(FINAL) + cd $(THISDIR) + +wxclean: + cd $(WXDIR)\src\msw + nmake -f makefile.vc clean + cd $(THISDIR) + +ogl: + cd $(OGLDIR)\src + nmake -f makefile.vc FINAL=$(FINAL) + cd $(THISDIR) + +$(PROGRAM).exe: $(DUMMYOBJ) $(WXLIB) $(OBJECTS) $(OGLLIB) $(PROGRAM).res + $(link) @<< +-out:$(PROGRAM).exe +$(LINKFLAGS) +$(DUMMYOBJ) $(OBJECTS) $(PROGRAM).res +$(LIBS) +<< + +$(PROGRAM).obj: $(PROGRAM).h doc.h view.h palette.h $(PROGRAM).$(SRCSUFF) $(DUMMYOBJ) + $(cc) @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +doc.obj: view.h doc.h doc.$(SRCSUFF) ogledit.h $(DUMMYOBJ) + $(cc) @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +view.obj: view.h doc.h view.$(SRCSUFF) ogledit.h $(DUMMYOBJ) + $(cc) @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +palette.obj: view.h doc.h ogledit.h palette.$(SRCSUFF) $(DUMMYOBJ) + $(cc) @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +$(PROGRAM).res : $(PROGRAM).rc $(WXDIR)\include\wx\msw\wx.rc ogl.ico + $(rc) -r /i$(WXDIR)\include -fo$@ $(PROGRAM).rc + + +cleanogl: + cd $(OGLDIR)\src + nmake -f makefile.vc clean + cd $(THISDIR) + +clean: + -erase *.obj + -erase *.sbr + -erase *.exe + -erase *.res + -erase *.map + -erase *.pdb + diff --git a/samples/ogl/ogledit/makefile.vms b/samples/ogl/ogledit/makefile.vms new file mode 100644 index 0000000000..1a64fc7f30 --- /dev/null +++ b/samples/ogl/ogledit/makefile.vms @@ -0,0 +1,44 @@ +#************************************************************************ +# Makefile for DOCVIEW under VMS +# by Stefan Hammes +# (incomplete) update history: +# 09.06.95 +#************************************************************************ + +#************************************************************************ +# Definition section +# (cave: definitions and includes must begin with ',') +#************************************************************************ + +APPOPTS = +APPDEFS = +APPINCS = + +#************************************************************************ +# Module section +#************************************************************************ + +# Name of main module +MAIN = docview + +# Object modules of the application. +OBJS = docview.obj view.obj doc.obj +OBJLIST =docview.obj,view.obj,doc.obj + +.include [--.src]makevms.env + +# main dependency +$(MAIN).exe : $(OBJS) + $(LINK) $(LINKFLAGS) /exec=$(MAIN).exe $(OBJLIST),$(WXLIB)/lib,$(OPTSFILE)/option + - purge *.exe + +#************************************************************************ +# Header file depedencies following +#************************************************************************ + +docview.$(OBJSUFF) : docview.$(SRCSUFF) docview.h doc.h view.h + +doc.$(OBJSUFF) : doc.$(SRCSUFF) doc.h + +view.$(OBJSUFF) : view.$(SRCSUFF) view.h + diff --git a/samples/ogl/ogledit/makefile.wat b/samples/ogl/ogledit/makefile.wat new file mode 100644 index 0000000000..bafa16f3a5 --- /dev/null +++ b/samples/ogl/ogledit/makefile.wat @@ -0,0 +1,43 @@ +# +# Makefile for WATCOM +# +# Created by D.Chubraev, chubraev@iem.ee.ethz.ch +# 8 Nov 1994 +# + +WXDIR = ..\.. + +!include $(WXDIR)\src\makewat.env + +WXLIB = $(WXDIR)\lib +NAME = docview +LNK = $(name).lnk +OBJS = $(name).obj doc.obj view.obj + +all: $(name).exe + +$(name).exe : $(OBJS) $(name).res $(LNK) $(WXLIB)\wx$(LEVEL).lib + wlink @$(LNK) + $(BINDCOMMAND) $(name).res + +$(name).res : $(name).rc $(WXDIR)\include\msw\wx.rc + $(RC) $(RESFLAGS1) $(name).rc + +$(LNK) : makefile.wat + %create $(LNK) + @%append $(LNK) debug all + @%append $(LNK) system $(LINKOPTION) + @%append $(LNK) $(MINDATA) + @%append $(LNK) $(MAXDATA) + @%append $(LNK) $(STACK) + @%append $(LNK) name $(name) + @%append $(LNK) file $(WXLIB)\wx$(LEVEL).lib + @for %i in ($(EXTRALIBS)) do @%append $(LNK) file %i + @for %i in ($(OBJS)) do @%append $(LNK) file %i + +thing: .SYMBOLIC + echo $(WATLIBDIR) + +clean: .SYMBOLIC + -erase *.obj *.bak *.err *.pch *.lib *.lnk *.res *.exe *.rex + diff --git a/samples/ogl/ogledit/ogl.ico b/samples/ogl/ogledit/ogl.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/samples/ogl/ogledit/ogl.xpm b/samples/ogl/ogledit/ogl.xpm new file mode 100644 index 0000000000..2a8c61e578 --- /dev/null +++ b/samples/ogl/ogledit/ogl.xpm @@ -0,0 +1,45 @@ +/* XPM */ +static char * ogl_xpm[] = { +/* width height ncolors chars_per_pixel */ +"32 32 7 1", +/* colors */ +" s None c None", +". c #000000", +"+ c #000080", +"@ c #ff0000", +"# c #00ff00", +"$ c #00ffff", +"% c #ffffff", +/* pixels */ +"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", +"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", +"%............%%%%%%........%%%%%", +"%.@@@@@@@@@@.%%%%..$$$$$$$$..%%%", +"%.@@@@@@@@@@.%%%.$$$$$$$$$$$$.%%", +"%.@@@@@@@@@@.+++.$$$$$$$$$$$$.%%", +"%.@@@@@@@@@@.+++.$$$$$$$$$$$$.%%", +"%.@@@@@@@@@@.%%%.$$$$$$$$$$$$.%%", +"%.@@@@@@@@@@.%%%%..$$$$$$$$..%%%", +"%............%%%%%.........%%%%%", +"%%%%%%++%%%%%%%%%%%%%%++%%%%%%%%", +"%%%%%%++%%%%%%%%%%%%%%++%%%%%%%%", +"%%%%%%++%%%%%%%%%%%%%%++%%%%%%%%", +"%%%%%%++%%%%%%%%%%%%%%++%%%%%%%%", +"%%%%%%++%%%%%%%%%%%%%%++%%%%%%%%", +"%%%%%%++%%%%%%%%%%%%%%++%%%%%%%%", +"%%%%%%+.%%%%%%%%%%%%%%++%%%%%%%%", +"%%%%%%.+.%%%%%%%%%%%%.++..%%%%%%", +"%%%%%.+++.%%%%%%%%%..#####..%%%%", +"%%%%.+++++.%%%%%%%.#########.%%%", +"%%%.+++++++.%%%%%%.#########.%%%", +"%%.+++++++++.%%%%.###########.%%", +"%.+++++++++++.++++###########.%%", +"%%.+++++++++.+++++###########.%%", +"%%%.+++++++.%%%%%%.#########.%%%", +"%%%%.+++++.%%%%%%%.#########.%%%", +"%%%%%.+++.%%%%%%%%%..#####..%%%%", +"%%%%%%.+.%%%%%%%%%%%%.....%%%%%%", +"%%%%%%%.%%%%%%%%%%%%%%%%%%%%%%%%", +"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", +"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", +"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"}; diff --git a/samples/ogl/ogledit/ogledit.cpp b/samples/ogl/ogledit/ogledit.cpp new file mode 100644 index 0000000000..87f19e6e85 --- /dev/null +++ b/samples/ogl/ogledit/ogledit.cpp @@ -0,0 +1,213 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: ogledit.cpp +// Purpose: OGLEdit sample app +// 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 + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#if !wxUSE_DOC_VIEW_ARCHITECTURE +#error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h! +#endif + +#include "ogledit.h" +#include "palette.h" +#include "doc.h" +#include "view.h" + +#if defined(__WXGTK__) || defined(__WXMOTIF__) +#include "ogl.xpm" +#endif + +// A macro needed for some compilers (AIX) that need 'main' to be defined +// in the application itself. +IMPLEMENT_APP(MyApp) + +MyApp::MyApp(void) +{ + frame = NULL; + myDocManager= NULL; +} + +// The `main program' equivalent, creating the windows and returning the +// main frame +bool MyApp::OnInit(void) +{ + wxOGLInitialize(); + + //// Create a document manager + myDocManager = new wxDocManager; + + //// Create a template relating drawing documents to their views + (void) new wxDocTemplate(myDocManager, "Diagram", "*.dia", "", "dia", "Diagram Doc", "Diagram View", + CLASSINFO(DiagramDocument), CLASSINFO(DiagramView)); + + // If we've only got one window, we only get to edit + // one document at a time. + myDocManager->SetMaxDocsOpen(1); + + //// Create the main frame window + frame = new MyFrame(myDocManager, NULL, "OGLEdit Demo", wxPoint(0, 0), wxSize(500, 400), wxDEFAULT_FRAME_STYLE); + + //// Give it an icon + frame->SetIcon(wxICON(ogl)); + + //// Make a menubar + wxMenu *file_menu = new wxMenu; + wxMenu *edit_menu = NULL; + + file_menu->Append(wxID_NEW, "&New..."); + file_menu->Append(wxID_OPEN, "&Open..."); + + file_menu->Append(wxID_CLOSE, "&Close"); + file_menu->Append(wxID_SAVE, "&Save"); + file_menu->Append(wxID_SAVEAS, "Save &As..."); + file_menu->AppendSeparator(); + file_menu->Append(wxID_PRINT, "&Print..."); + file_menu->Append(wxID_PRINT_SETUP, "Print &Setup..."); + file_menu->Append(wxID_PREVIEW, "Print Pre&view"); + + edit_menu = new wxMenu; + edit_menu->Append(wxID_UNDO, "&Undo"); + edit_menu->Append(wxID_REDO, "&Redo"); + edit_menu->AppendSeparator(); + edit_menu->Append(OGLEDIT_CUT, "&Cut"); + edit_menu->AppendSeparator(); + edit_menu->Append(OGLEDIT_CHANGE_BACKGROUND_COLOUR, "Change &background colour"); + edit_menu->Append(OGLEDIT_EDIT_LABEL, "Edit &label"); + + frame->editMenu = edit_menu; + + file_menu->AppendSeparator(); + file_menu->Append(wxID_EXIT, "E&xit"); + + // A nice touch: a history of files visited. Use this menu. + myDocManager->FileHistoryUseMenu(file_menu); + + wxMenu *help_menu = new wxMenu; + help_menu->Append(OGLEDIT_ABOUT, "&About"); + + wxMenuBar *menu_bar = new wxMenuBar; + + menu_bar->Append(file_menu, "&File"); + if (edit_menu) + menu_bar->Append(edit_menu, "&Edit"); + menu_bar->Append(help_menu, "&Help"); + + frame->canvas = frame->CreateCanvas(NULL, frame); + frame->palette = wxGetApp().CreatePalette(frame); + myDocManager->CreateDocument("", wxDOC_NEW); + + //// Associate the menu bar with the frame + frame->SetMenuBar(menu_bar); + + frame->CreateStatusBar(1); + + frame->Centre(wxBOTH); + frame->Show(TRUE); + + return TRUE; +} + +int MyApp::OnExit(void) +{ + wxOGLCleanUp(); + delete myDocManager; + return 0; +} + +/* + * This is the top-level window of the application. + */ + +IMPLEMENT_CLASS(MyFrame, wxDocParentFrame) + +BEGIN_EVENT_TABLE(MyFrame, wxDocParentFrame) + EVT_MENU(OGLEDIT_ABOUT, MyFrame::OnAbout) + EVT_SIZE(MyFrame::OnSize) + EVT_CLOSE(MyFrame::OnCloseWindow) +END_EVENT_TABLE() + +MyFrame::MyFrame(wxDocManager *manager, wxFrame *frame, const wxString& title, + const wxPoint& pos, const wxSize& size, long type): + wxDocParentFrame(manager, frame, -1, title, pos, size, type) +{ + canvas = NULL; + palette = NULL; + editMenu = NULL; +} + +void MyFrame::OnSize(wxSizeEvent& event) +{ + if (canvas && palette) + { + int cw, ch; + GetClientSize(&cw, &ch); + int paletteX = 0; + int paletteY = 0; + int paletteW = 30; + int paletteH = ch; + int canvasX = paletteX + paletteW; + int canvasY = 0; + int canvasW = cw - paletteW; + int canvasH = ch; + + palette->SetSize(paletteX, paletteY, paletteW, paletteH); + canvas->SetSize(canvasX, canvasY, canvasW, canvasH); + } +} + +void MyFrame::OnCloseWindow(wxCloseEvent& event) +{ + wxDocParentFrame::OnCloseWindow(event); + if (!event.GetVeto()) + { + wxOGLCleanUp(); + } +} + +// Intercept menu commands +void MyFrame::OnAbout(wxCommandEvent& event) +{ + (void)wxMessageBox("OGLEdit Demo\nTo draw a shape, select a shape on the toolbar and left-click on the canvas.\nTo draw a line, right-drag between shapes.\nFor further details, see the OGL manual.\n (c) Julian Smart 1996", "About OGLEdit"); +} + +// Creates a canvas. Called by OnInit as a child of the main window +MyCanvas *MyFrame::CreateCanvas(wxView *view, wxFrame *parent) +{ + int width, height; + parent->GetClientSize(&width, &height); + + // Non-retained canvas + MyCanvas *canvas = new MyCanvas(view, parent, -1, wxPoint(0, 0), wxSize(width, height), 0); + canvas->SetCursor(wxCursor(wxCURSOR_HAND)); + + // Give it scrollbars + canvas->SetScrollbars(20, 20, 50, 50); + + return canvas; +} + +MyFrame *GetMainFrame(void) +{ + return wxGetApp().frame; +} + diff --git a/samples/ogl/ogledit/ogledit.def b/samples/ogl/ogledit/ogledit.def new file mode 100644 index 0000000000..d587ce5556 --- /dev/null +++ b/samples/ogl/ogledit/ogledit.def @@ -0,0 +1,8 @@ +NAME OGLEdit +DESCRIPTION 'OGL Editor Sample' +EXETYPE WINDOWS +STUB 'WINSTUB.EXE' +CODE PRELOAD MOVEABLE DISCARDABLE +DATA PRELOAD MOVEABLE MULTIPLE +HEAPSIZE 1024 +STACKSIZE 8192 diff --git a/samples/ogl/ogledit/ogledit.h b/samples/ogl/ogledit/ogledit.h new file mode 100644 index 0000000000..62dfb9bced --- /dev/null +++ b/samples/ogl/ogledit/ogledit.h @@ -0,0 +1,77 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: ogledit.h +// Purpose: OGL sample +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +// #pragma interface +#endif + +#ifndef _OGLSAMPLE_OGLEDIT_H_ +#define _OGLSAMPLE_OGLEDIT_H_ + +#include + +// Define a new application +class MyFrame; +class EditorToolPalette; +class MyApp: public wxApp +{ + public: + MyFrame *frame; + wxDocManager* myDocManager; + + MyApp(void); + bool OnInit(void); + int OnExit(void); + + // Palette stuff + EditorToolPalette *CreatePalette(wxFrame *parent); +}; + +DECLARE_APP(MyApp) + +// Define a new frame +class MyCanvas; +class MyFrame: public wxDocParentFrame +{ + DECLARE_CLASS(MyFrame) + public: + wxMenu *editMenu; + + MyCanvas *canvas; + EditorToolPalette *palette; + + MyFrame(wxDocManager *manager, wxFrame *parent, const wxString& title, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_FRAME_STYLE); + + MyCanvas *CreateCanvas(wxView *view, wxFrame *parent); + void OnSize(wxSizeEvent& event); + void OnCloseWindow(wxCloseEvent& event); + void OnAbout(wxCommandEvent& event); + +DECLARE_EVENT_TABLE() +}; + +extern MyFrame *GetMainFrame(void); + +// Menu/undo/redo commands + +#define OGLEDIT_CUT 1 +#define OGLEDIT_ADD_SHAPE 2 +#define OGLEDIT_ADD_LINE 3 +#define OGLEDIT_EDIT_LABEL 4 +#define OGLEDIT_CHANGE_BACKGROUND_COLOUR 5 + +#define OGLEDIT_ABOUT 100 + +#endif + // _OGLSAMPLE_OGLEDIT_H_ diff --git a/samples/ogl/ogledit/ogledit.rc b/samples/ogl/ogledit/ogledit.rc new file mode 100644 index 0000000000..046f0c6f45 --- /dev/null +++ b/samples/ogl/ogledit/ogledit.rc @@ -0,0 +1,10 @@ +ogl ICON ogl.ico + +TOOL1 BITMAP "bitmaps/tool1.bmp" +TOOL2 BITMAP "bitmaps/tool2.bmp" +TOOL3 BITMAP "bitmaps/tool3.bmp" +TOOL4 BITMAP "bitmaps/tool4.bmp" +ARROWTOOL BITMAP "bitmaps/arrow.bmp" + +#include "wx/msw/wx.rc" + diff --git a/samples/ogl/ogledit/palette.cpp b/samples/ogl/ogledit/palette.cpp new file mode 100644 index 0000000000..84348c5982 --- /dev/null +++ b/samples/ogl/ogledit/palette.cpp @@ -0,0 +1,121 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: palette.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 + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#include +#include +#include + +#include "doc.h" +#include "view.h" +#include "ogledit.h" +#include "palette.h" + +// Include pixmaps +#if defined(__WXGTK__) || defined(__WXMOTIF__) +#include "bitmaps/arrow.xpm" +#include "bitmaps/tool1.xpm" +#include "bitmaps/tool2.xpm" +#include "bitmaps/tool3.xpm" +#include "bitmaps/tool4.xpm" +#endif + +/* + * Object editor tool palette + * + */ + +EditorToolPalette::EditorToolPalette(wxWindow* parent, const wxPoint& pos, const wxSize& size, + long style): + TOOLPALETTECLASS(parent, -1, pos, size, style) +{ + currentlySelected = -1; + +#if 1 // ndef __WXGTK__ + SetMaxRowsCols(1000, 1); +#endif +} + +bool EditorToolPalette::OnLeftClick(int toolIndex, bool toggled) +{ + // BEGIN mutual exclusivity code + if (toggled && (currentlySelected != -1) && (toolIndex != currentlySelected)) + ToggleTool(currentlySelected, FALSE); + + if (toggled) + currentlySelected = toolIndex; + else if (currentlySelected == toolIndex) + currentlySelected = -1; + // END mutual exclusivity code + + return TRUE; +} + +void EditorToolPalette::OnMouseEnter(int toolIndex) +{ +} + +void EditorToolPalette::SetSize(int x, int y, int width, int height, int sizeFlags) +{ + TOOLPALETTECLASS::SetSize(x, y, width, height, sizeFlags); +} + +EditorToolPalette *MyApp::CreatePalette(wxFrame *parent) +{ + // Load palette bitmaps +#ifdef __WXMSW__ + wxBitmap PaletteTool1("TOOL1"); + wxBitmap PaletteTool2("TOOL2"); + wxBitmap PaletteTool3("TOOL3"); + wxBitmap PaletteTool4("TOOL4"); + wxBitmap PaletteArrow("ARROWTOOL"); +#elif defined(__WXGTK__) || defined(__WXMOTIF__) + wxBitmap PaletteTool1(tool1_xpm); + wxBitmap PaletteTool2(tool2_xpm); + wxBitmap PaletteTool3(tool3_xpm); + wxBitmap PaletteTool4(tool4_xpm); + wxBitmap PaletteArrow(arrow_xpm); +#endif + + EditorToolPalette *palette = new EditorToolPalette(parent, wxPoint(0, 0), wxSize(-1, -1), wxTB_HORIZONTAL); + + palette->SetMargins(2, 2); + palette->SetToolBitmapSize(wxSize(22, 22)); + + palette->AddTool(PALETTE_ARROW, PaletteArrow, wxNullBitmap, TRUE, 0, -1, NULL, "Pointer"); + palette->AddTool(PALETTE_TOOL1, PaletteTool1, wxNullBitmap, TRUE, 0, -1, NULL, "Tool 1"); + palette->AddTool(PALETTE_TOOL2, PaletteTool2, wxNullBitmap, TRUE, 0, -1, NULL, "Tool 2"); + palette->AddTool(PALETTE_TOOL3, PaletteTool3, wxNullBitmap, TRUE, 0, -1, NULL, "Tool 3"); + palette->AddTool(PALETTE_TOOL4, PaletteTool4, wxNullBitmap, TRUE, 0, -1, NULL, "Tool 4"); + + palette->Realize(); + + palette->ToggleTool(PALETTE_ARROW, TRUE); + palette->currentlySelected = PALETTE_ARROW; + return palette; +} + diff --git a/samples/ogl/ogledit/palette.h b/samples/ogl/ogledit/palette.h new file mode 100644 index 0000000000..2e9102f7db --- /dev/null +++ b/samples/ogl/ogledit/palette.h @@ -0,0 +1,66 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: palette.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 _OGLSAMPLE_PALETTE_H_ +#define _OGLSAMPLE_PALETTE_H_ + +#ifdef __GNUG__ +// #pragma interface +#endif + +#include +#include +#if 0 // def __WXGTK__ +#include +#else +#include +#endif + +/* + * 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. +#if 0 // def __WXGTK__ +#define TOOLPALETTECLASS wxToolBar +#else +#define TOOLPALETTECLASS wxToolBarSimple +#endif + +class EditorToolPalette: public TOOLPALETTECLASS +{ + public: + int currentlySelected; + + EditorToolPalette(wxWindow *parent, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTB_VERTICAL); + bool OnLeftClick(int toolIndex, bool toggled); + void OnMouseEnter(int toolIndex); + void SetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); +}; + +#define PALETTE_TOOL1 1 +#define PALETTE_TOOL2 2 +#define PALETTE_TOOL3 3 +#define PALETTE_TOOL4 4 +#define PALETTE_TOOL5 5 +#define PALETTE_TOOL6 6 +#define PALETTE_TOOL7 7 +#define PALETTE_TOOL8 8 +#define PALETTE_TOOL9 9 +#define PALETTE_ARROW 10 + +#endif + // _OGLSAMPLE_PALETTE_H_ diff --git a/samples/ogl/ogledit/view.cpp b/samples/ogl/ogledit/view.cpp new file mode 100644 index 0000000000..0d8e58232b --- /dev/null +++ b/samples/ogl/ogledit/view.cpp @@ -0,0 +1,337 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: view.cpp +// Purpose: Implements view functionality in OGLEdit +// 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 + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#if !wxUSE_DOC_VIEW_ARCHITECTURE +#error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h! +#endif + +#include "ogledit.h" +#include "doc.h" +#include "view.h" +#include "palette.h" + +IMPLEMENT_DYNAMIC_CLASS(DiagramView, wxView) + +BEGIN_EVENT_TABLE(DiagramView, wxView) + EVT_MENU(OGLEDIT_CUT, DiagramView::OnCut) + EVT_MENU(OGLEDIT_CHANGE_BACKGROUND_COLOUR, DiagramView::OnChangeBackgroundColour) + EVT_MENU(OGLEDIT_EDIT_LABEL, DiagramView::OnEditLabel) +END_EVENT_TABLE() + +// What to do when a view is created. Creates actual +// windows for displaying the view. +bool DiagramView::OnCreate(wxDocument *doc, long flags) +{ + frame = GetMainFrame(); + canvas = GetMainFrame()->canvas; + canvas->view = this; + + SetFrame(frame); + Activate(TRUE); + + // Initialize the edit menu Undo and Redo items + doc->GetCommandProcessor()->SetEditMenu(((MyFrame *)frame)->editMenu); + doc->GetCommandProcessor()->Initialize(); + + wxShapeCanvas *shapeCanvas = (wxShapeCanvas *)canvas; + DiagramDocument *diagramDoc = (DiagramDocument *)doc; + shapeCanvas->SetDiagram(diagramDoc->GetDiagram()); + diagramDoc->GetDiagram()->SetCanvas(shapeCanvas); + + return TRUE; +} + +#define CENTER FALSE // Place the drawing to the center of the page + + +// Sneakily gets used for default print/preview +// as well as drawing on the screen. +void DiagramView::OnDraw(wxDC *dc) +{ + + /* You might use THIS code if you were scaling + * graphics of known size to fit on the page. + */ + int w, h; + + // We need to adjust for the graphic size, a formula will be added + float maxX = 900; + float maxY = 700; + // A better way of find the maxium values would be to search through + // the linked list + + // Let's have at least 10 device units margin + float marginX = 10; + float marginY = 10; + + // Add the margin to the graphic size + maxX += (2 * marginX); + maxY += (2 * marginY); + + // Get the size of the DC in pixels + dc->GetSize (&w, &h); + + // Calculate a suitable scaling factor + float scaleX = (float) (w / maxX); + float scaleY = (float) (h / maxY); + + // Use x or y scaling factor, whichever fits on the DC + float actualScale = wxMin (scaleX, scaleY); + + float posX, posY; + // Calculate the position on the DC for centring the graphic + if (CENTER == TRUE) // center the drawing + { + posX = (float) ((w - (200 * actualScale)) / 2.0); + posY = (float) ((h - (200 * actualScale)) / 2.0); + } + else // Use defined presets + { + posX = 10; + posY = 35; + } + + + // Set the scale and origin + dc->SetUserScale (actualScale, actualScale); + dc->SetDeviceOrigin ((long) posX, (long) posY); + + // This part was added to preform the print preview and printing functions + + dc->BeginDrawing(); // Allows optimization of drawing code under MS Windows. + wxDiagram *diagram_p=((DiagramDocument*)GetDocument())->GetDiagram(); // Get the current diagram + if (diagram_p->GetShapeList()) + { + wxCursor *old_cursor = NULL; + wxNode *current = diagram_p->GetShapeList()->First(); + + while (current) // Loop through the entire list of shapes + { + wxShape *object = (wxShape *)current->Data(); + if (!object->GetParent()) + { + object->Draw(* dc); // Draw the shape onto our printing dc + } + current = current->Next(); // Procede to the next shape in the list + } + } + dc->EndDrawing(); // Allows optimization of drawing code under MS Windows. +} + +void DiagramView::OnUpdate(wxView *sender, wxObject *hint) +{ + if (canvas) + canvas->Refresh(); +} + +// Clean up windows used for displaying the view. +bool DiagramView::OnClose(bool deleteWindow) +{ + if (!GetDocument()->Close()) + return FALSE; + + DiagramDocument *diagramDoc = (DiagramDocument *)GetDocument(); + diagramDoc->GetDiagram()->SetCanvas(NULL); + + canvas->Clear(); + canvas->SetDiagram(NULL); + canvas->view = NULL; + canvas = NULL; + + wxString s = wxTheApp->GetAppName(); + if (frame) + frame->SetTitle(s); + + SetFrame(NULL); + + Activate(FALSE); + + return TRUE; +} + +wxShape *DiagramView::FindSelectedShape(void) +{ + DiagramDocument *doc = (DiagramDocument *)GetDocument(); + wxShape *theShape = NULL; + wxNode *node = doc->GetDiagram()->GetShapeList()->First(); + while (node) + { + wxShape *eachShape = (wxShape *)node->Data(); + if ((eachShape->GetParent() == NULL) && eachShape->Selected()) + { + theShape = eachShape; + node = NULL; + } + else node = node->Next(); + } + return theShape; +} + +void DiagramView::OnCut(wxCommandEvent& event) +{ + DiagramDocument *doc = (DiagramDocument *)GetDocument(); + + wxShape *theShape = FindSelectedShape(); + if (theShape) + doc->GetCommandProcessor()->Submit(new DiagramCommand("Cut", OGLEDIT_CUT, doc, NULL, 0.0, 0.0, TRUE, theShape)); +} + +void DiagramView::OnChangeBackgroundColour(wxCommandEvent& event) +{ + DiagramDocument *doc = (DiagramDocument *)GetDocument(); + + wxShape *theShape = FindSelectedShape(); + if (theShape) + { + wxColourData data; + data.SetChooseFull(TRUE); + data.SetColour(theShape->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(); + + if (theBrush) + doc->GetCommandProcessor()->Submit(new DiagramCommand("Change colour", OGLEDIT_CHANGE_BACKGROUND_COLOUR, doc, + theBrush, theShape)); + } +} + +void DiagramView::OnEditLabel(wxCommandEvent& event) +{ + wxShape *theShape = FindSelectedShape(); + if (theShape) + { + wxString newLabel = wxGetTextFromUser("Enter new label", "Shape Label", ((MyEvtHandler *)theShape->GetEventHandler())->label); + GetDocument()->GetCommandProcessor()->Submit(new DiagramCommand("Edit label", OGLEDIT_EDIT_LABEL, (DiagramDocument*) GetDocument(), newLabel, theShape)); + } +} + + +/* + * Window implementations + */ + +BEGIN_EVENT_TABLE(MyCanvas, wxShapeCanvas) + EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent) + EVT_PAINT(MyCanvas::OnPaint) +END_EVENT_TABLE() + +// Define a constructor for my canvas +MyCanvas::MyCanvas(wxView *v, wxWindow *parent, wxWindowID id, const wxPoint& pos, + const wxSize& size, long style): + wxShapeCanvas(parent, id, pos, size, style) +{ + SetBackgroundColour(*wxWHITE); + view = v; +} + +MyCanvas::~MyCanvas(void) +{ +} + +void MyCanvas::OnLeftClick(double x, double y, int keys) +{ + EditorToolPalette *palette = wxGetApp().frame->palette; + wxClassInfo *info = NULL; + switch (palette->currentlySelected) + { + case PALETTE_TOOL1: + { + info = CLASSINFO(wxRectangleShape); + break; + } + case PALETTE_TOOL2: + { + info = CLASSINFO(wxRoundedRectangleShape); + break; + } + case PALETTE_TOOL3: + { + info = CLASSINFO(wxEllipseShape); + break; + } + case PALETTE_TOOL4: + { + info = CLASSINFO(wxDiamondShape); + break; + } + default: + break; + } + if (info) + { + view->GetDocument()->GetCommandProcessor()->Submit(new DiagramCommand(info->GetClassName(), OGLEDIT_ADD_SHAPE, (DiagramDocument *)view->GetDocument(), info, + x, y)); + } +} + +void MyCanvas::OnRightClick(double x, double y, int keys) +{ +} + +void MyCanvas::OnDragLeft(bool draw, double x, double y, int keys) +{ +} + +void MyCanvas::OnBeginDragLeft(double x, double y, int keys) +{ +} + +void MyCanvas::OnEndDragLeft(double x, double y, int keys) +{ +} + +void MyCanvas::OnDragRight(bool draw, double x, double y, int keys) +{ +} + +void MyCanvas::OnBeginDragRight(double x, double y, int keys) +{ +} + +void MyCanvas::OnEndDragRight(double x, double y, int keys) +{ +} + +void MyCanvas::OnMouseEvent(wxMouseEvent& event) +{ + wxShapeCanvas::OnMouseEvent(event); +} + +void MyCanvas::OnPaint(wxPaintEvent& event) +{ +// if (GetDiagram()) + wxShapeCanvas::OnPaint(event); +} diff --git a/samples/ogl/ogledit/view.h b/samples/ogl/ogledit/view.h new file mode 100644 index 0000000000..1498574447 --- /dev/null +++ b/samples/ogl/ogledit/view.h @@ -0,0 +1,79 @@ +///////////////////////////////////////////////////////////////////////////// +// 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 _OGLSAMPLE_VIEW_H_ +#define _OGLSAMPLE_VIEW_H_ + +#ifdef __GNUG__ +// #pragma interface "view.h" +#endif + +#include "doc.h" +#include + +class MyCanvas: public wxShapeCanvas +{ +// DECLARE_DYNAMIC_CLASS(wxShapeCanvas) + protected: + public: + wxView *view; + + MyCanvas(wxView *view, wxWindow *parent = NULL, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxRETAINED); + ~MyCanvas(void); + + 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); + +DECLARE_EVENT_TABLE() +}; + +class DiagramView: public wxView +{ + DECLARE_DYNAMIC_CLASS(DiagramView) + private: + public: + wxFrame *frame; + MyCanvas *canvas; + + DiagramView(void) { canvas = NULL; frame = NULL; }; + ~DiagramView(void) {}; + + bool OnCreate(wxDocument *doc, long flags); + void OnDraw(wxDC *dc); + void OnUpdate(wxView *sender, wxObject *hint = NULL); + bool OnClose(bool deleteWindow = TRUE); + + wxShape *FindSelectedShape(void); + +// void OnMenuCommand(int cmd); + + void OnCut(wxCommandEvent& event); + void OnChangeBackgroundColour(wxCommandEvent& event); + void OnEditLabel(wxCommandEvent& event); + +DECLARE_EVENT_TABLE() +}; + +#endif + // _OGLSAMPLE_VIEW_H_ diff --git a/samples/ogl/studio/Makefile b/samples/ogl/studio/Makefile new file mode 100644 index 0000000000..a576d543ce --- /dev/null +++ b/samples/ogl/studio/Makefile @@ -0,0 +1,57 @@ +# +# File: Makefile +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: (c) 2000 Julian Smart +# +# Makefile for OGL demo (GTK version) +# +# This makefile requires wxWindows/GTK to be +# installed (possibly using "make install") +# on your system. +# + +CPP = gcc +CC = gcc +WXCONFIG=../../../../wx-config +WXINCLUDE=-I../../../../include +WXLIB=-L../../../../lib + +OBJECTS=studio.o cspalette.o csprint.o dialogs.o doc.o mainfrm.o project.o shapes.o symbols.o view.o + +studio: $(OBJECTS) + $(CPP) -o studio $(OBJECTS) `$(WXCONFIG) --libs` $(WXLIB) -logl + +studio.o: studio.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c studio.cpp + +cspalette.o: cspalette.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c cspalette.cpp + +doc.o: doc.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c doc.cpp + +view.o: view.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c view.cpp + +dialogs.o: dialogs.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c dialogs.cpp + +mainfrm.o: mainfrm.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c mainfrm.cpp + +project.o: project.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c project.cpp + +shapes.o: shapes.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c shapes.cpp + +symbols.o: symbols.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c symbols.cpp + +csprint.o: csprint.cpp + $(CPP) `$(WXCONFIG) --cflags` -I../../src $(WXINCLUDE) -c csprint.cpp + +clean: + rm -f *.o studio diff --git a/samples/ogl/studio/cspalette.cpp b/samples/ogl/studio/cspalette.cpp new file mode 100644 index 0000000000..50c5aee777 --- /dev/null +++ b/samples/ogl/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 + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#include +#include +#include + +#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/samples/ogl/studio/cspalette.h b/samples/ogl/studio/cspalette.h new file mode 100644 index 0000000000..67a8e63740 --- /dev/null +++ b/samples/ogl/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 +#include +#include + +/* + * 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/samples/ogl/studio/csprint.cpp b/samples/ogl/studio/csprint.cpp new file mode 100644 index 0000000000..6bf5dad26e --- /dev/null +++ b/samples/ogl/studio/csprint.cpp @@ -0,0 +1,320 @@ +///////////////////////////////////////////////////////////////////////////// +// 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 + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include +#include + +#ifdef __WXMSW__ +#include +#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 0 // TODO: replace this code (wxEnhMetaFile doesn't have SetClipboard) + if (mf) + { + // Copy the metafile to the clipboard + // Allow a small margin + bool success = mf->SetClipboard((int)(mfDC.MaxX() + 15), (int)(mfDC.MaxY() + 15)); + } +#endif + + // 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/samples/ogl/studio/dialogs.cpp b/samples/ogl/studio/dialogs.cpp new file mode 100644 index 0000000000..9fef6d120f --- /dev/null +++ b/samples/ogl/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 + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include +#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/samples/ogl/studio/dialogs.h b/samples/ogl/studio/dialogs.h new file mode 100644 index 0000000000..4a97f8fc75 --- /dev/null +++ b/samples/ogl/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 +#include + +/* + * 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/samples/ogl/studio/doc.cpp b/samples/ogl/studio/doc.cpp new file mode 100644 index 0000000000..ea8cb82eb7 --- /dev/null +++ b/samples/ogl/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 + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#include "studio.h" +#include "doc.h" +#include "view.h" +#include + +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/samples/ogl/studio/doc.h b/samples/ogl/studio/doc.h new file mode 100644 index 0000000000..4e77abc4c0 --- /dev/null +++ b/samples/ogl/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 +#include +#include + +#include +#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/samples/ogl/studio/mainfrm.cpp b/samples/ogl/studio/mainfrm.cpp new file mode 100644 index 0000000000..c1d856c301 --- /dev/null +++ b/samples/ogl/studio/mainfrm.cpp @@ -0,0 +1,276 @@ +///////////////////////////////////////////////////////////////////////////// +// 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) +{ + wxDocMDIParentFrame::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); + +#if defined(__WXMSW__) && defined(__WIN95__) + // Need to do something else to get it to refresh properly + // when a client frame is first displayed; moving the client + // window doesn't cause the proper refresh. Just refreshing the + // client doesn't work (presumably because it's clipping the + // children). + // FIXED in wxWindows, by intercepting wxMDIClientWindow::DoSetSize + // and checking if the position has changed, before redrawing the + // child windows. +#if 0 + wxMDIChildFrame* childFrame = GetActiveChild(); + if (childFrame) + { + HWND hWnd = (HWND) childFrame->GetHWND(); + ::RedrawWindow(hWnd, NULL, NULL, RDW_FRAME|RDW_ALLCHILDREN|RDW_INVALIDATE ); + + } +#endif +#endif + } +} + +// 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/samples/ogl/studio/mainfrm.h b/samples/ogl/studio/mainfrm.h new file mode 100644 index 0000000000..9200fc2c4c --- /dev/null +++ b/samples/ogl/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 + +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/samples/ogl/studio/makefile.b32 b/samples/ogl/studio/makefile.b32 new file mode 100644 index 0000000000..292366caa1 --- /dev/null +++ b/samples/ogl/studio/makefile.b32 @@ -0,0 +1,19 @@ +# +# File: makefile.b32 +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: +# +# Makefile : Builds sample for 32-bit BC++ + +WXDIR = $(WXWIN) + +TARGET=studio +EXTRALIBS=$(WXDIR)\lib\ogl.lib +EXTRACPPFLAGS=-I$(WXDIR)\utils\ogl\src +OBJECTS = $(TARGET).obj doc.obj shapes.obj symbols.obj view.obj cspalette.obj\ + mainfrm.obj project.obj dialogs.obj csprint.obj + +!include $(WXDIR)\src\makeprog.b32 + diff --git a/samples/ogl/studio/makefile.bcc b/samples/ogl/studio/makefile.bcc new file mode 100644 index 0000000000..11f514391a --- /dev/null +++ b/samples/ogl/studio/makefile.bcc @@ -0,0 +1,22 @@ +# +# File: makefile.bcc +# Author: Julian Smart +# Created: 1998 +# Updated: +# +# Builds a BC++ 16-bit sample + +!if "$(WXWIN)" == "" +!error You must define the WXWIN variable in autoexec.bat, e.g. WXWIN=c:\wx +!endif + +WXDIR = $(WXWIN) + +TARGET=studio +EXTRALIBS=$(WXDIR)\lib\ogl.lib +EXTRACPPFLAGS=-I$(WXDIR)\utils\ogl\src +OBJECTS = $(TARGET).obj doc.obj shapes.obj symbols.obj view.obj cspalette.obj\ + mainfrm.obj project.obj dialogs.obj csprint.obj + +!include $(WXDIR)\src\makeprog.b32 + diff --git a/samples/ogl/studio/makefile.g95 b/samples/ogl/studio/makefile.g95 new file mode 100644 index 0000000000..2da54a18a9 --- /dev/null +++ b/samples/ogl/studio/makefile.g95 @@ -0,0 +1,19 @@ +# +# File: makefile.g95 +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: (c) Julian Smart, 1999 +# +# Makefile for wxWindows sample (Cygwin/Mingw32). + +WXDIR = ../../../.. + +TARGET=studio +EXTRACPPFLAGS=-I../../src +EXTRALIBS=-logl +OBJECTS = $(TARGET).o doc.o shapes.o symbols.o view.o cspalette.o\ + mainfrm.o project.o dialogs.o csprint.o + +include $(WXDIR)/src/makeprog.g95 + diff --git a/samples/ogl/studio/makefile.unx b/samples/ogl/studio/makefile.unx new file mode 100644 index 0000000000..5fca57a097 --- /dev/null +++ b/samples/ogl/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 -I./bitmaps +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/samples/ogl/studio/makefile.vc b/samples/ogl/studio/makefile.vc new file mode 100644 index 0000000000..b88314a836 --- /dev/null +++ b/samples/ogl/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$(LIBEXT).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: 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/samples/ogl/studio/manual/alignb.bmp b/samples/ogl/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-OD*JU>wjJEKHuH!bxvFW literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/manual/alignl.bmp b/samples/ogl/studio/manual/alignl.bmp new file mode 100644 index 0000000000000000000000000000000000000000..30471101b16de3328c3d7a9ddbb74c95669b30c1 GIT binary patch literal 238 zcmaKju@QhU3fPl58tp)=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/samples/ogl/studio/manual/alignt.bmp b/samples/ogl/studio/manual/alignt.bmp new file mode 100644 index 0000000000000000000000000000000000000000..4505cbab566385942c0912c245668a2567a6e4a9 GIT binary patch literal 238 zcmaKkF%Ez*3|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/samples/ogl/studio/manual/arrow.bmp b/samples/ogl/studio/manual/arrow.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d406ceb64f017d99bcc2d4913aef75135de357a0 GIT binary patch literal 382 zcmb7-I}UJZQ>1WPN=;5qEQ3zc?;o59U+Ka+r!5!mH1Gr)e_0X9zQo7Bn*m`tDP z>tSJ;fdXA9#W(4KsI?;JEJm}1)|8}VswC~|bu-BQ Vombvu=JhAub(#Nm-N`e*_yJ^>eVzaS literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/manual/back.gif b/samples/ogl/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>t<(Iwfoo literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/manual/bitmap1.bmp b/samples/ogl/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_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/samples/ogl/studio/manual/bullet.bmp b/samples/ogl/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/samples/ogl/studio/manual/contents.gif b/samples/ogl/studio/manual/contents.gif new file mode 100644 index 0000000000000000000000000000000000000000..3dddfa3dd5f0c652e8b27cd6c29e1fdd49ced5a8 GIT binary patch literal 231 zcmVG0Pz3-zrVld=jU&4Z(9HWEC2ui06_p40008OjE||y?GK}z zO&EZ)-n{z{a)K3v=81;mmA0S4Fj_r^UyThZDG{h6k9m zHI_(7spd!5_$SH6m{tjiv)Cz3AyzP{vxy7<$~OeTT!c7JQf6T89- z%?kmn<${;(P#uFN<0A#FuUo(qgT{&F@ekspii W=d@ZzPG(Cb=QBs}_=7thzxV(viB<;y literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/manual/copysize.bmp b/samples/ogl/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/samples/ogl/studio/manual/cut.bmp b/samples/ogl/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?H9GSB752pV-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/samples/ogl/studio/manual/forward.gif b/samples/ogl/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/samples/ogl/studio/manual/help.bmp b/samples/ogl/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^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/samples/ogl/studio/manual/helpcs.bmp b/samples/ogl/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;%kg8Fsb(=J`dZ5!;MsyQTV&Nwu@o7(Ri`byve-X0yz0?`b73&zHji5? LZQ&!hb;r)SF8kLTs=5{{JE?DUYEK&^#0pxo{w%L C5KP+u literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/manual/linearrow.bmp b/samples/ogl/studio/manual/linearrow.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1fd21fb08ac4a0d07a8b724700eb40c11a276698 GIT binary patch literal 238 zcmZWjF%p0<2#a^_%H$V(hr5qq5yw8QFY*gDG6I3Fl3%1*4rLQI&+z};Dt zvxK4mOq3!avqY_xnuFF8tz|{`6V literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/manual/new.bmp b/samples/ogl/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)Xt4Pkz>06 literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/manual/newpoint.bmp b/samples/ogl/studio/manual/newpoint.bmp new file mode 100644 index 0000000000000000000000000000000000000000..cb4f267afca22039f403ed5f92a6c6a0c2978131 GIT binary patch literal 238 zcma)!u@QhU33XfhEigttvWi5y9eoOs=CC3b9qGo0X{5tYu+ z6rVX0MdGNGG?Z4YHQWb1j(YbFQXV14f9QQ2&YA$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/samples/ogl/studio/manual/paste.bmp b/samples/ogl/studio/manual/paste.bmp new file mode 100644 index 0000000000000000000000000000000000000000..564f514e0df7225f0a7adbe8457b41af537813bd GIT binary patch literal 238 zcmZvVF%Ci@5Jbns$83OZ*I;# co}I%%@f6>ra3+S=gC69}eM%GII+SAI4J;x>B>(^b literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/manual/pointsize.bmp b/samples/ogl/studio/manual/pointsize.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8a01c8a42cb9b3fbf9ee79d816a47b25854e198e GIT binary patch literal 538 zcmb7Au?+$-47^83Up@^D6EFuoyL^Sei#zC8fejD65ZOCR73UEWUIx<7#oaybN_(mxf(YQ>q^B0_@L(-7P5{5=wE(UG1 zg|}0&MNk_>yk5{|^cpaBdDhJ5+g}>OA0e;r?=_jw^IP+%oq<&onUne$ K8%jRLmaY#<=_kbi literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/manual/preview.bmp b/samples/ogl/studio/manual/preview.bmp new file mode 100644 index 0000000000000000000000000000000000000000..da1f4dbc4be6c2dd8fb9d7cb71cc48a4a7c139ca GIT binary patch literal 238 zcmZvVu?@p83pv2yNo4mlT?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/samples/ogl/studio/manual/print.bmp b/samples/ogl/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|VizM>j+f}Fx~Q7! zgtHKM7yg3|DAD^Sp<0YF#C}+nSj(MC$5#Ss27*aN<{l9dJQ3^NitoWUKaQYXHtaK{cvyw!_%p*Ri9bz(b-vmXx}r)(2faSYV3`7rsq)3!X>4ws(){6V0MX5FKAjcylGXqN-n#XsS=YhW0WogZT{L^_i_GT%*k@+ph E1NJ~MtpET3 literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/manual/straight.bmp b/samples/ogl/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/samples/ogl/studio/manual/studio.hpj b/samples/ogl/studio/manual/studio.hpj new file mode 100644 index 0000000000..8e6d98315a --- /dev/null +++ b/samples/ogl/studio/manual/studio.hpj @@ -0,0 +1,23 @@ +[OPTIONS] +BMROOT=. ; Assume that bitmaps are where the source is +TITLE=OGL Studio +CONTENTS=Contents +; COMPRESS=12 Hall Zeck ; Max compression, but needs lots of memory +COMPRESS=8 Zeck +LCID=0x809 0x0 0x0 ;English (British) +HLP=.\studio.hlp + +[WINDOWS] +Main="",(553,102,400,600),20736,(r14876671),(r12632256),f3 + +[FILES] +studio.rtf + +[CONFIG] +CreateButton("Up", "&Up", "JumpId(`studio.hlp', `Contents')") +BrowseButtons() + +[MAP] + +[BITMAPS] + diff --git a/samples/ogl/studio/manual/studio.tex b/samples/ogl/studio/manual/studio.tex new file mode 100644 index 0000000000..ab4d897258 --- /dev/null +++ b/samples/ogl/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/samples/ogl/studio/manual/tex2rtf.ini b/samples/ogl/studio/manual/tex2rtf.ini new file mode 100644 index 0000000000..f44fc89982 --- /dev/null +++ b/samples/ogl/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/samples/ogl/studio/manual/texttool.bmp b/samples/ogl/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/samples/ogl/studio/manual/tick.bmp b/samples/ogl/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{bqVO)bKZHuqJq2P$o+ Qrwbl?Kzn<_G@1WzKlk4xlmGw# literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/manual/toback.bmp b/samples/ogl/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 zmJIC1PUWgEAng0mNcZ%*en37UzJJQ409!#Op@kUh#ZHNo5<&TT>4iR1ivT=$yRS#8XFECq!-*mgr LV^3-JfBEkPyAH!9 literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/manual/tool3.bmp b/samples/ogl/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@Q8CoZa7Pu)am`?}1?Jt#_EJF0JQ3!n}6e%=pgD_<}*2+Yz5YBOr`1t>vyt3|(LMK@8j3+#3B&Dlo ygm>;xkr%gtCeAWZlgxpoy|ZDMRPr_m>p rx}08pS4?)u<%PWJQ30?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/samples/ogl/studio/manual/zoom.bmp b/samples/ogl/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>znEycvemKkNI}0Pw~TiO-DW7%DYa#ul)#>K;C|YTDSvGP;$%i literal 0 HcmV?d00001 diff --git a/samples/ogl/studio/project.cpp b/samples/ogl/studio/project.cpp new file mode 100644 index 0000000000..a6298d698e --- /dev/null +++ b/samples/ogl/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/samples/ogl/studio/project.h b/samples/ogl/studio/project.h new file mode 100644 index 0000000000..b52ae259ef --- /dev/null +++ b/samples/ogl/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 +#include + +/* + * 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/samples/ogl/studio/shapes.cpp b/samples/ogl/studio/shapes.cpp new file mode 100644 index 0000000000..7bf02edb5c --- /dev/null +++ b/samples/ogl/studio/shapes.cpp @@ -0,0 +1,1194 @@ +///////////////////////////////////////////////////////////////////////////// +// 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 + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#if !wxUSE_DOC_VIEW_ARCHITECTURE +#error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h! +#endif + +#include + +#include "studio.h" +#include "doc.h" +#include "shapes.h" +#include "view.h" +#include +#include +#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(OGLRBLF); + 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(OGLRBLF); + 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(OGLRBLF); + + 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(OGLRBLF); + + 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; + } +} + +BEGIN_EVENT_TABLE(ShapeEditMenu, wxMenu) + EVT_COMMAND_RANGE(1, 65000, wxEVT_COMMAND_MENU_SELECTED, ShapeEditMenu::OnCommand) +END_EVENT_TABLE() + +void ShapeEditMenu::OnCommand(wxCommandEvent& event) +{ + studioShapeEditProc(*this, event); +} + diff --git a/samples/ogl/studio/shapes.h b/samples/ogl/studio/shapes.h new file mode 100644 index 0000000000..fa183b46bb --- /dev/null +++ b/samples/ogl/studio/shapes.h @@ -0,0 +1,268 @@ +///////////////////////////////////////////////////////////////////////////// +// 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 +#include +#include + +#include +#include +#include +#include + +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; +}; + +class ShapeEditMenu: public wxMenu +{ +public: + ShapeEditMenu() {} + + void OnCommand(wxCommandEvent& event); + +DECLARE_EVENT_TABLE() +}; + +extern void studioShapeEditProc(wxMenu& menu, wxCommandEvent& event); + +#endif + // _STUDIO_SHAPES_H_ diff --git a/samples/ogl/studio/studio.cpp b/samples/ogl/studio/studio.cpp new file mode 100644 index 0000000000..d8ca7a8890 --- /dev/null +++ b/samples/ogl/studio/studio.cpp @@ -0,0 +1,506 @@ +///////////////////////////////////////////////////////////////////////////// +// 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" + +#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 ShapeEditMenu; + 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), wxSUNKEN_BORDER); + + 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", (long) m_mainFramePos.x); + config.Write("mainY", (long) m_mainFramePos.y); + config.Write("mainWidth", (long) m_mainFrameSize.x); + config.Write("mainHeight", (long) m_mainFrameSize.y); + config.Write("gridStyle", (long) m_gridStyle); + config.Write("gridSpacing", (long) m_gridSpacing); + + m_docManager->FileHistorySave(config); + + return TRUE; +} + diff --git a/samples/ogl/studio/studio.h b/samples/ogl/studio/studio.h new file mode 100644 index 0000000000..0104a16456 --- /dev/null +++ b/samples/ogl/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 +#include + +#include +#include +#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/samples/ogl/studio/studio.ico b/samples/ogl/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/samples/ogl/studio/studio.rc b/samples/ogl/studio/studio.rc new file mode 100644 index 0000000000..70a7a9c9e4 --- /dev/null +++ b/samples/ogl/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/samples/ogl/studio/studio.xpm b/samples/ogl/studio/studio.xpm new file mode 100644 index 0000000000..cd5b1cbc14 --- /dev/null +++ b/samples/ogl/studio/studio.xpm @@ -0,0 +1,44 @@ +/* XPM */ +static char *studio_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/samples/ogl/studio/studio_resources.h b/samples/ogl/studio/studio_resources.h new file mode 100644 index 0000000000..92a49c0f36 --- /dev/null +++ b/samples/ogl/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/samples/ogl/studio/studio_resources.wxr b/samples/ogl/studio/studio_resources.wxr new file mode 100644 index 0000000000..51c9521bd5 --- /dev/null +++ b/samples/ogl/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/samples/ogl/studio/symbols.cpp b/samples/ogl/studio/symbols.cpp new file mode 100644 index 0000000000..6a422c0702 --- /dev/null +++ b/samples/ogl/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 + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#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.SelectObject(*newBitmap); + memDC.SetUserScale(scaleFactor, scaleFactor); + + 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/samples/ogl/studio/symbols.h b/samples/ogl/studio/symbols.h new file mode 100644 index 0000000000..390fea9a96 --- /dev/null +++ b/samples/ogl/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 +#include +#include + +#include + +/* + * 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/samples/ogl/studio/view.cpp b/samples/ogl/studio/view.cpp new file mode 100644 index 0000000000..6a66902f5a --- /dev/null +++ b/samples/ogl/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 + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#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 +#include + +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(OGLRBLF); + 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(OGLRBLF); + 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/samples/ogl/studio/view.h b/samples/ogl/studio/view.h new file mode 100644 index 0000000000..11cb3aeb1e --- /dev/null +++ b/samples/ogl/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 + +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/src/ogl/Makefile.in b/src/ogl/Makefile.in new file mode 100644 index 0000000000..1edfe19d0f --- /dev/null +++ b/src/ogl/Makefile.in @@ -0,0 +1,13 @@ +# + +top_builddir = ../.. + +VPATH= $(top_srcdir)/ogl + +LIBTARGET=$(top_builddir)/lib/libogl + +OBJECTS=basic.o bmpshape.o composit.o divided.o lines.o misc.o \ + basic2.o canvas.o constrnt.o drawn.o mfutils.o ogldiag.o + + +include $(top_builddir)/src/makelib.env diff --git a/src/ogl/basic.cpp b/src/ogl/basic.cpp new file mode 100644 index 0000000000..2d53683a94 --- /dev/null +++ b/src/ogl/basic.cpp @@ -0,0 +1,3274 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: basic.cpp +// Purpose: Basic OGL classes +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "basic.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#if wxUSE_IOSTREAMH +#include +#else +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// Control point types +// Rectangle and most other shapes +#define CONTROL_POINT_VERTICAL 1 +#define CONTROL_POINT_HORIZONTAL 2 +#define CONTROL_POINT_DIAGONAL 3 + +// Line +#define CONTROL_POINT_ENDPOINT_TO 4 +#define CONTROL_POINT_ENDPOINT_FROM 5 +#define CONTROL_POINT_LINE 6 + +IMPLEMENT_DYNAMIC_CLASS(wxShapeTextLine, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxAttachmentPoint, wxObject) + +wxShapeTextLine::wxShapeTextLine(double the_x, double the_y, const wxString& the_line) +{ + m_x = the_x; m_y = the_y; m_line = the_line; +} + +wxShapeTextLine::~wxShapeTextLine() +{ +} + +IMPLEMENT_ABSTRACT_CLASS(wxShapeEvtHandler, wxObject) + +wxShapeEvtHandler::wxShapeEvtHandler(wxShapeEvtHandler *prev, wxShape *shape) +{ + m_previousHandler = prev; + m_handlerShape = shape; +} + +wxShapeEvtHandler::~wxShapeEvtHandler() +{ +} + +// Creates a copy of this event handler. +wxShapeEvtHandler* wxShapeEvtHandler::CreateNewCopy() +{ + wxShapeEvtHandler* newObject = (wxShapeEvtHandler*) GetClassInfo()->CreateObject(); + + wxASSERT( (newObject != NULL) ); + wxASSERT( (newObject->IsKindOf(CLASSINFO(wxShapeEvtHandler))) ); + + newObject->m_previousHandler = newObject; + + CopyData(*newObject); + + return newObject; +} + + +void wxShapeEvtHandler::OnDelete() +{ + if (this != GetShape()) + delete this; +} + +void wxShapeEvtHandler::OnDraw(wxDC& dc) +{ + if (m_previousHandler) + m_previousHandler->OnDraw(dc); +} + +void wxShapeEvtHandler::OnMoveLinks(wxDC& dc) +{ + if (m_previousHandler) + m_previousHandler->OnMoveLinks(dc); +} + +void wxShapeEvtHandler::OnMoveLink(wxDC& dc, bool moveControlPoints) +{ + if (m_previousHandler) + m_previousHandler->OnMoveLink(dc, moveControlPoints); +} + +void wxShapeEvtHandler::OnDrawContents(wxDC& dc) +{ + if (m_previousHandler) + m_previousHandler->OnDrawContents(dc); +} + +void wxShapeEvtHandler::OnDrawBranches(wxDC& dc, bool erase) +{ + if (m_previousHandler) + m_previousHandler->OnDrawBranches(dc, erase); +} + +void wxShapeEvtHandler::OnSize(double x, double y) +{ + if (m_previousHandler) + m_previousHandler->OnSize(x, y); +} + +bool wxShapeEvtHandler::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display) +{ + if (m_previousHandler) + return m_previousHandler->OnMovePre(dc, x, y, old_x, old_y, display); + else + return TRUE; +} + +void wxShapeEvtHandler::OnMovePost(wxDC& dc, double x, double y, double old_x, double old_y, bool display) +{ + if (m_previousHandler) + m_previousHandler->OnMovePost(dc, x, y, old_x, old_y, display); +} + +void wxShapeEvtHandler::OnErase(wxDC& dc) +{ + if (m_previousHandler) + m_previousHandler->OnErase(dc); +} + +void wxShapeEvtHandler::OnEraseContents(wxDC& dc) +{ + if (m_previousHandler) + m_previousHandler->OnEraseContents(dc); +} + +void wxShapeEvtHandler::OnHighlight(wxDC& dc) +{ + if (m_previousHandler) + m_previousHandler->OnHighlight(dc); +} + +void wxShapeEvtHandler::OnLeftClick(double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnLeftClick(x, y, keys, attachment); +} + +void wxShapeEvtHandler::OnLeftDoubleClick(double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnLeftDoubleClick(x, y, keys, attachment); +} + +void wxShapeEvtHandler::OnRightClick(double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnRightClick(x, y, keys, attachment); +} + +void wxShapeEvtHandler::OnDragLeft(bool draw, double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnDragLeft(draw, x, y, keys, attachment); +} + +void wxShapeEvtHandler::OnBeginDragLeft(double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnBeginDragLeft(x, y, keys, attachment); +} + +void wxShapeEvtHandler::OnEndDragLeft(double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnEndDragLeft(x, y, keys, attachment); +} + +void wxShapeEvtHandler::OnDragRight(bool draw, double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnDragRight(draw, x, y, keys, attachment); +} + +void wxShapeEvtHandler::OnBeginDragRight(double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnBeginDragRight(x, y, keys, attachment); +} + +void wxShapeEvtHandler::OnEndDragRight(double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnEndDragRight(x, y, keys, attachment); +} + +// Control points ('handles') redirect control to the actual shape, to make it easier +// to override sizing behaviour. +void wxShapeEvtHandler::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnSizingDragLeft(pt, draw, x, y, keys, attachment); +} + +void wxShapeEvtHandler::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnSizingBeginDragLeft(pt, x, y, keys, attachment); +} + +void wxShapeEvtHandler::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnSizingEndDragLeft(pt, x, y, keys, attachment); +} + +void wxShapeEvtHandler::OnDrawOutline(wxDC& dc, double x, double y, double w, double h) +{ + if (m_previousHandler) + m_previousHandler->OnDrawOutline(dc, x, y, w, h); +} + +void wxShapeEvtHandler::OnDrawControlPoints(wxDC& dc) +{ + if (m_previousHandler) + m_previousHandler->OnDrawControlPoints(dc); +} + +void wxShapeEvtHandler::OnEraseControlPoints(wxDC& dc) +{ + if (m_previousHandler) + m_previousHandler->OnEraseControlPoints(dc); +} + +// Can override this to prevent or intercept line reordering. +void wxShapeEvtHandler::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering) +{ + if (m_previousHandler) + m_previousHandler->OnChangeAttachment(attachment, line, ordering); +} + +IMPLEMENT_ABSTRACT_CLASS(wxShape, wxShapeEvtHandler) + +wxShape::wxShape(wxShapeCanvas *can) +{ + m_eventHandler = this; + SetShape(this); + m_id = 0; + m_formatted = FALSE; + m_canvas = can; + m_xpos = 0.0; m_ypos = 0.0; + m_pen = g_oglBlackPen; + m_brush = wxWHITE_BRUSH; + m_font = g_oglNormalFont; + m_textColour = wxBLACK; + m_textColourName = "BLACK"; + m_visible = FALSE; + m_clientData = NULL; + m_selected = FALSE; + m_attachmentMode = ATTACHMENT_MODE_NONE; + m_spaceAttachments = TRUE; + m_disableLabel = FALSE; + m_fixedWidth = FALSE; + m_fixedHeight = FALSE; + m_drawHandles = TRUE; + m_sensitivity = OP_ALL; + m_draggable = TRUE; + m_parent = NULL; + m_formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT; + m_shadowMode = SHADOW_NONE; + m_shadowOffsetX = 6; + m_shadowOffsetY = 6; + m_shadowBrush = wxBLACK_BRUSH; + m_textMarginX = 5; + m_textMarginY = 5; + m_regionName = "0"; + m_centreResize = TRUE; + m_maintainAspectRatio = FALSE; + m_highlighted = FALSE; + m_rotation = 0.0; + m_branchNeckLength = 10; + m_branchStemLength = 10; + m_branchSpacing = 10; + m_branchStyle = BRANCHING_ATTACHMENT_NORMAL; + + // Set up a default region. Much of the above will be put into + // the region eventually (the duplication is for compatibility) + wxShapeRegion *region = new wxShapeRegion; + m_regions.Append(region); + region->SetName("0"); + region->SetFont(g_oglNormalFont); + region->SetFormatMode(FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT); + region->SetColour("BLACK"); +} + +wxShape::~wxShape() +{ + if (m_parent) + m_parent->GetChildren().DeleteObject(this); + + ClearText(); + ClearRegions(); + ClearAttachments(); + + if (m_canvas) + m_canvas->RemoveShape(this); + + GetEventHandler()->OnDelete(); +} + +void wxShape::SetHighlight(bool hi, bool recurse) +{ + m_highlighted = hi; + if (recurse) + { + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->SetHighlight(hi, recurse); + node = node->Next(); + } + } +} + +void wxShape::SetSensitivityFilter(int sens, bool recursive) +{ + if (sens & OP_DRAG_LEFT) + m_draggable = TRUE; + else + m_draggable = FALSE; + + m_sensitivity = sens; + if (recursive) + { + wxNode *node = m_children.First(); + while (node) + { + wxShape *obj = (wxShape *)node->Data(); + obj->SetSensitivityFilter(sens, TRUE); + node = node->Next(); + } + } +} + +void wxShape::SetDraggable(bool drag, bool recursive) +{ + m_draggable = drag; + if (m_draggable) + m_sensitivity |= OP_DRAG_LEFT; + else + if (m_sensitivity & OP_DRAG_LEFT) + m_sensitivity = m_sensitivity - OP_DRAG_LEFT; + + if (recursive) + { + wxNode *node = m_children.First(); + while (node) + { + wxShape *obj = (wxShape *)node->Data(); + obj->SetDraggable(drag, TRUE); + node = node->Next(); + } + } +} + +void wxShape::SetDrawHandles(bool drawH) +{ + m_drawHandles = drawH; + wxNode *node = m_children.First(); + while (node) + { + wxShape *obj = (wxShape *)node->Data(); + obj->SetDrawHandles(drawH); + node = node->Next(); + } +} + +void wxShape::SetShadowMode(int mode, bool redraw) +{ + if (redraw && GetCanvas()) + { + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + Erase(dc); + + m_shadowMode = mode; + + Draw(dc); + } + else + { + m_shadowMode = mode; + } +} + +void wxShape::SetCanvas(wxShapeCanvas *theCanvas) +{ + m_canvas = theCanvas; + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->SetCanvas(theCanvas); + node = node->Next(); + } +} + +void wxShape::AddToCanvas(wxShapeCanvas *theCanvas, wxShape *addAfter) +{ + theCanvas->AddShape(this, addAfter); + wxNode *node = m_children.First(); + wxShape *lastImage = this; + while (node) + { + wxShape *object = (wxShape *)node->Data(); + object->AddToCanvas(theCanvas, lastImage); + lastImage = object; + + node = node->Next(); + } +} + +// Insert at front of canvas +void wxShape::InsertInCanvas(wxShapeCanvas *theCanvas) +{ + theCanvas->InsertShape(this); + wxNode *node = m_children.First(); + wxShape *lastImage = this; + while (node) + { + wxShape *object = (wxShape *)node->Data(); + object->AddToCanvas(theCanvas, lastImage); + lastImage = object; + + node = node->Next(); + } +} + +void wxShape::RemoveFromCanvas(wxShapeCanvas *theCanvas) +{ + if (Selected()) + Select(FALSE); + theCanvas->RemoveShape(this); + wxNode *node = m_children.First(); + while (node) + { + wxShape *object = (wxShape *)node->Data(); + object->RemoveFromCanvas(theCanvas); + + node = node->Next(); + } +} + +void wxShape::ClearAttachments() +{ + wxNode *node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + delete point; + node = node->Next(); + } + m_attachmentPoints.Clear(); +} + +void wxShape::ClearText(int regionId) +{ + if (regionId == 0) + { + m_text.DeleteContents(TRUE); + m_text.Clear(); + m_text.DeleteContents(FALSE); + } + wxNode *node = m_regions.Nth(regionId); + if (!node) + return; + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + region->ClearText(); +} + +void wxShape::ClearRegions() +{ + wxNode *node = m_regions.First(); + while (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + wxNode *next = node->Next(); + delete region; + delete node; + node = next; + } +} + +void wxShape::AddRegion(wxShapeRegion *region) +{ + m_regions.Append(region); +} + +void wxShape::SetDefaultRegionSize() +{ + wxNode *node = m_regions.First(); + if (!node) return; + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + double w, h; + GetBoundingBoxMin(&w, &h); + region->SetSize(w, h); +} + +bool wxShape::HitTest(double x, double y, int *attachment, double *distance) +{ +// if (!sensitive) +// return FALSE; + + double width = 0.0, height = 0.0; + GetBoundingBoxMin(&width, &height); + if (fabs(width) < 4.0) width = 4.0; + if (fabs(height) < 4.0) height = 4.0; + + width += (double)4.0; height += (double)4.0; // Allowance for inaccurate mousing + + double left = (double)(m_xpos - (width/2.0)); + double top = (double)(m_ypos - (height/2.0)); + double right = (double)(m_xpos + (width/2.0)); + double bottom = (double)(m_ypos + (height/2.0)); + + int nearest_attachment = 0; + + // If within the bounding box, check the attachment points + // within the object. + + if (x >= left && x <= right && y >= top && y <= bottom) + { + int n = GetNumberOfAttachments(); + double nearest = 999999.0; + + // GetAttachmentPosition[Edge] takes a logical attachment position, + // i.e. if it's rotated through 90%, position 0 is East-facing. + + for (int i = 0; i < n; i++) + { + double xp, yp; + if (GetAttachmentPositionEdge(i, &xp, &yp)) + { + double l = (double)sqrt(((xp - x) * (xp - x)) + + ((yp - y) * (yp - y))); + + if (l < nearest) + { + nearest = l; + nearest_attachment = i; + } + } + } + *attachment = nearest_attachment; + *distance = nearest; + return TRUE; + } + else return FALSE; +} + +// Format a text string according to the region size, adding +// strings with positions to region text list + +static bool GraphicsInSizeToContents = FALSE; // Infinite recursion elimination +void wxShape::FormatText(wxDC& dc, const wxString& s, int i) +{ + double w, h; + ClearText(i); + + if (m_regions.Number() < 1) + return; + wxNode *node = m_regions.Nth(i); + if (!node) + return; + + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + region->SetText(s); + dc.SetFont(* region->GetFont()); + + region->GetSize(&w, &h); + + wxStringList *stringList = oglFormatText(dc, s, (w-5), (h-5), region->GetFormatMode()); + node = stringList->First(); + while (node) + { + char *s = (char *)node->Data(); + wxShapeTextLine *line = new wxShapeTextLine(0.0, 0.0, s); + region->GetFormattedText().Append((wxObject *)line); + node = node->Next(); + } + delete stringList; + double actualW = w; + double actualH = h; + // Don't try to resize an object with more than one image (this case should be dealt + // with by overriden handlers) + if ((region->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS) && + (region->GetFormattedText().Number() > 0) && + (m_regions.Number() == 1) && !GraphicsInSizeToContents) + { + oglGetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH); + if ((actualW+m_textMarginX != w ) || (actualH+m_textMarginY != h)) + { + // If we are a descendant of a composite, must make sure the composite gets + // resized properly + wxShape *topAncestor = GetTopAncestor(); + + if (topAncestor != this) + { + // Make sure we don't recurse infinitely + GraphicsInSizeToContents = TRUE; + + wxCompositeShape *composite = (wxCompositeShape *)topAncestor; + composite->Erase(dc); + SetSize(actualW+m_textMarginX, actualH+m_textMarginY); + Move(dc, m_xpos, m_ypos); + composite->CalculateSize(); + if (composite->Selected()) + { + composite->DeleteControlPoints(& dc); + composite->MakeControlPoints(); + composite->MakeMandatoryControlPoints(); + } + // Where infinite recursion might happen if we didn't stop it + composite->Draw(dc); + + GraphicsInSizeToContents = FALSE; + } + else + { + Erase(dc); + SetSize(actualW+m_textMarginX, actualH+m_textMarginY); + Move(dc, m_xpos, m_ypos); + } + SetSize(actualW+m_textMarginX, actualH+m_textMarginY); + Move(dc, m_xpos, m_ypos); + EraseContents(dc); + } + } + oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW, actualH, region->GetFormatMode()); + m_formatted = TRUE; +} + +void wxShape::Recentre(wxDC& dc) +{ + double w, h; + GetBoundingBoxMin(&w, &h); + + int noRegions = m_regions.Number(); + for (int i = 0; i < noRegions; i++) + { + wxNode *node = m_regions.Nth(i); + if (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, region->GetFormatMode()); + } + } +} + +bool wxShape::GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3) +{ + return FALSE; +} + +void wxShape::SetPen(wxPen *the_pen) +{ + m_pen = the_pen; +} + +void wxShape::SetBrush(wxBrush *the_brush) +{ + m_brush = the_brush; +} + +// Get the top-most (non-division) ancestor, or self +wxShape *wxShape::GetTopAncestor() +{ + if (!GetParent()) + return this; + + if (GetParent()->IsKindOf(CLASSINFO(wxDivisionShape))) + return this; + else return GetParent()->GetTopAncestor(); +} + +/* + * Region functions + * + */ +void wxShape::SetFont(wxFont *the_font, int regionId) +{ + m_font = the_font; + wxNode *node = m_regions.Nth(regionId); + if (!node) + return; + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + region->SetFont(the_font); +} + +wxFont *wxShape::GetFont(int n) const +{ + wxNode *node = m_regions.Nth(n); + if (!node) + return NULL; + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + return region->GetFont(); +} + +void wxShape::SetFormatMode(int mode, int regionId) +{ + wxNode *node = m_regions.Nth(regionId); + if (!node) + return; + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + region->SetFormatMode(mode); +} + +int wxShape::GetFormatMode(int regionId) const +{ + wxNode *node = m_regions.Nth(regionId); + if (!node) + return 0; + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + return region->GetFormatMode(); +} + +void wxShape::SetTextColour(const wxString& the_colour, int regionId) +{ + wxColour *wxcolour = wxTheColourDatabase->FindColour(the_colour); + m_textColour = wxcolour; + m_textColourName = the_colour; + + wxNode *node = m_regions.Nth(regionId); + if (!node) + return; + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + region->SetColour(the_colour); +} + +wxString wxShape::GetTextColour(int regionId) const +{ + wxNode *node = m_regions.Nth(regionId); + if (!node) + return wxString(""); + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + return region->GetColour(); +} + +void wxShape::SetRegionName(const wxString& name, int regionId) +{ + wxNode *node = m_regions.Nth(regionId); + if (!node) + return; + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + region->SetName(name); +} + +wxString wxShape::GetRegionName(int regionId) +{ + wxNode *node = m_regions.Nth(regionId); + if (!node) + return wxString(""); + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + return region->GetName(); +} + +int wxShape::GetRegionId(const wxString& name) +{ + wxNode *node = m_regions.First(); + int i = 0; + while (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + if (region->GetName() == name) + return i; + node = node->Next(); + i ++; + } + return -1; +} + +// Name all m_regions in all subimages recursively. +void wxShape::NameRegions(const wxString& parentName) +{ + int n = GetNumberOfTextRegions(); + char buf[100]; + for (int i = 0; i < n; i++) + { + if (parentName.Length() > 0) + sprintf(buf, "%s.%d", (const char*) parentName, i); + else + sprintf(buf, "%d", i); + SetRegionName(buf, i); + } + wxNode *node = m_children.First(); + int j = 0; + while (node) + { + wxShape *child = (wxShape *)node->Data(); + if (parentName.Length() > 0) + sprintf(buf, "%s.%d", (const char*) parentName, j); + else + sprintf(buf, "%d", j); + child->NameRegions(buf); + node = node->Next(); + j ++; + } +} + +// Get a region by name, possibly looking recursively into composites. +wxShape *wxShape::FindRegion(const wxString& name, int *regionId) +{ + int id = GetRegionId(name); + if (id > -1) + { + *regionId = id; + return this; + } + + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + wxShape *actualImage = child->FindRegion(name, regionId); + if (actualImage) + return actualImage; + node = node->Next(); + } + return NULL; +} + +// Finds all region names for this image (composite or simple). +// Supply empty string list. +void wxShape::FindRegionNames(wxStringList& list) +{ + int n = GetNumberOfTextRegions(); + for (int i = 0; i < n; i++) + { + wxString name(GetRegionName(i)); + list.Add((const char*) name); + } + + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->FindRegionNames(list); + node = node->Next(); + } +} + +void wxShape::AssignNewIds() +{ +// if (m_id == 0) + m_id = wxNewId(); + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->AssignNewIds(); + node = node->Next(); + } +} + +void wxShape::OnDraw(wxDC& dc) +{ +} + +void wxShape::OnMoveLinks(wxDC& dc) +{ + // Want to set the ends of all attached links + // to point to/from this object + + wxNode *current = m_lines.First(); + while (current) + { + wxLineShape *line = (wxLineShape *)current->Data(); + line->GetEventHandler()->OnMoveLink(dc); + current = current->Next(); + } +} + + +void wxShape::OnDrawContents(wxDC& dc) +{ + double bound_x, bound_y; + GetBoundingBoxMin(&bound_x, &bound_y); + if (m_regions.Number() < 1) return; + + if (m_pen) dc.SetPen(* m_pen); + + wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data(); + if (region->GetFont()) dc.SetFont(* region->GetFont()); + + dc.SetTextForeground(* (region->GetActualColourObject())); + dc.SetBackgroundMode(wxTRANSPARENT); + if (!m_formatted) + { + oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode()); + m_formatted = TRUE; + } + if (!GetDisableLabel()) + { + oglDrawFormattedText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode()); + } +} + +void wxShape::DrawContents(wxDC& dc) +{ + GetEventHandler()->OnDrawContents(dc); +} + +void wxShape::OnSize(double x, double y) +{ +} + +bool wxShape::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display) +{ + return TRUE; +} + +void wxShape::OnMovePost(wxDC& dc, double x, double y, double old_x, double old_y, bool display) +{ +} + +void wxShape::OnErase(wxDC& dc) +{ + if (!m_visible) + return; + + // Erase links + wxNode *current = m_lines.First(); + while (current) + { + wxLineShape *line = (wxLineShape *)current->Data(); + line->GetEventHandler()->OnErase(dc); + current = current->Next(); + } + GetEventHandler()->OnEraseContents(dc); +} + +void wxShape::OnEraseContents(wxDC& dc) +{ + if (!m_visible) + return; + + double maxX, maxY, minX, minY; + double xp = GetX(); + double yp = GetY(); + GetBoundingBoxMin(&minX, &minY); + GetBoundingBoxMax(&maxX, &maxY); + double topLeftX = (double)(xp - (maxX / 2.0) - 2.0); + double topLeftY = (double)(yp - (maxY / 2.0) - 2.0); + + int penWidth = 0; + if (m_pen) + penWidth = m_pen->GetWidth(); + + dc.SetPen(* g_oglWhiteBackgroundPen); + dc.SetBrush(* g_oglWhiteBackgroundBrush); + dc.DrawRectangle(WXROUND(topLeftX - penWidth), WXROUND(topLeftY - penWidth), + WXROUND(maxX + penWidth*2.0 + 4.0), WXROUND(maxY + penWidth*2.0 + 4.0)); +} + +void wxShape::EraseLinks(wxDC& dc, int attachment, bool recurse) +{ + if (!m_visible) + return; + + wxNode *current = m_lines.First(); + while (current) + { + wxLineShape *line = (wxLineShape *)current->Data(); + if (attachment == -1 || ((line->GetTo() == this && line->GetAttachmentTo() == attachment) || + (line->GetFrom() == this && line->GetAttachmentFrom() == attachment))) + line->GetEventHandler()->OnErase(dc); + current = current->Next(); + } + if (recurse) + { + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->EraseLinks(dc, attachment, recurse); + node = node->Next(); + } + } +} + +void wxShape::DrawLinks(wxDC& dc, int attachment, bool recurse) +{ + if (!m_visible) + return; + + wxNode *current = m_lines.First(); + while (current) + { + wxLineShape *line = (wxLineShape *)current->Data(); + if (attachment == -1 || + (line->GetTo() == this && line->GetAttachmentTo() == attachment) || + (line->GetFrom() == this && line->GetAttachmentFrom() == attachment)) + line->Draw(dc); + current = current->Next(); + } + if (recurse) + { + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->DrawLinks(dc, attachment, recurse); + node = node->Next(); + } + } +} + +// Returns TRUE if pt1 <= pt2 in the sense that one point comes before another on an +// edge of the shape. +// attachmentPoint is the attachment point (= side) in question. + +// This is the default, rectangular implementation. +bool wxShape::AttachmentSortTest(int attachmentPoint, const wxRealPoint& pt1, const wxRealPoint& pt2) +{ + int physicalAttachment = LogicalToPhysicalAttachment(attachmentPoint); + switch (physicalAttachment) + { + case 0: + case 2: + { + return (pt1.x <= pt2.x) ; + break; + } + case 1: + case 3: + { + return (pt1.y <= pt2.y) ; + break; + } + } + + return FALSE; +} + +bool wxShape::MoveLineToNewAttachment(wxDC& dc, wxLineShape *to_move, + double x, double y) +{ + if (GetAttachmentMode() == ATTACHMENT_MODE_NONE) + return FALSE; + + int newAttachment, oldAttachment; + double distance; + + // Is (x, y) on this object? If so, find the new attachment point + // the user has moved the point to + bool hit = HitTest(x, y, &newAttachment, &distance); + if (!hit) + return FALSE; + + EraseLinks(dc); + + if (to_move->GetTo() == this) + oldAttachment = to_move->GetAttachmentTo(); + else + oldAttachment = to_move->GetAttachmentFrom(); + + // The links in a new ordering. + wxList newOrdering; + + // First, add all links to the new list. + wxNode *node = m_lines.First(); + while (node) + { + newOrdering.Append(node->Data()); + node = node->Next(); + } + + // Delete the line object from the list of links; we're going to move + // it to another position in the list + newOrdering.DeleteObject(to_move); + + double old_x = (double) -99999.9; + double old_y = (double) -99999.9; + + node = newOrdering.First(); + bool found = FALSE; + + while (!found && node) + { + wxLineShape *line = (wxLineShape *)node->Data(); + if ((line->GetTo() == this && oldAttachment == line->GetAttachmentTo()) || + (line->GetFrom() == this && oldAttachment == line->GetAttachmentFrom())) + { + double startX, startY, endX, endY; + double xp, yp; + line->GetEnds(&startX, &startY, &endX, &endY); + if (line->GetTo() == this) + { + xp = endX; + yp = endY; + } else + { + xp = startX; + yp = startY; + } + + wxRealPoint thisPoint(xp, yp); + wxRealPoint lastPoint(old_x, old_y); + wxRealPoint newPoint(x, y); + + if (AttachmentSortTest(newAttachment, newPoint, thisPoint) && AttachmentSortTest(newAttachment, lastPoint, newPoint)) + { + found = TRUE; + newOrdering.Insert(node, to_move); + } + + old_x = xp; + old_y = yp; + } + node = node->Next(); + } + + if (!found) + newOrdering.Append(to_move); + + GetEventHandler()->OnChangeAttachment(newAttachment, to_move, newOrdering); + + return TRUE; +} + +void wxShape::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering) +{ + if (line->GetTo() == this) + line->SetAttachmentTo(attachment); + else + line->SetAttachmentFrom(attachment); + + ApplyAttachmentOrdering(ordering); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + MoveLinks(dc); + + if (!GetCanvas()->GetQuickEditMode()) GetCanvas()->Redraw(dc); +} + +// Reorders the lines according to the given list. +void wxShape::ApplyAttachmentOrdering(wxList& linesToSort) +{ + // This is a temporary store of all the lines. + wxList linesStore; + + wxNode *node = m_lines.First(); + while (node) + { + wxLineShape *line = (wxLineShape *)node->Data(); + linesStore.Append(line); + node = node->Next();; + } + + m_lines.Clear(); + + node = linesToSort.First(); + while (node) + { + wxLineShape *line = (wxLineShape *)node->Data(); + if (linesStore.Member(line)) + { + // Done this one + linesStore.DeleteObject(line); + m_lines.Append(line); + } + node = node->Next(); + } + + // Now add any lines that haven't been listed in linesToSort. + node = linesStore.First(); + while (node) + { + wxLineShape *line = (wxLineShape *)node->Data(); + m_lines.Append(line); + node = node->Next(); + } +} + +// Reorders the lines coming into the node image at this attachment +// position, in the order in which they appear in linesToSort. +// Any remaining lines not in the list will be added to the end. +void wxShape::SortLines(int attachment, wxList& linesToSort) +{ + // This is a temporary store of all the lines at this attachment + // point. We'll tick them off as we've processed them. + wxList linesAtThisAttachment; + + wxNode *node = m_lines.First(); + while (node) + { + wxLineShape *line = (wxLineShape *)node->Data(); + wxNode *next = node->Next(); + if ((line->GetTo() == this && line->GetAttachmentTo() == attachment) || + (line->GetFrom() == this && line->GetAttachmentFrom() == attachment)) + { + linesAtThisAttachment.Append(line); + delete node; + node = next; + } + else node = node->Next(); + } + + node = linesToSort.First(); + while (node) + { + wxLineShape *line = (wxLineShape *)node->Data(); + if (linesAtThisAttachment.Member(line)) + { + // Done this one + linesAtThisAttachment.DeleteObject(line); + m_lines.Append(line); + } + node = node->Next(); + } + + // Now add any lines that haven't been listed in linesToSort. + node = linesAtThisAttachment.First(); + while (node) + { + wxLineShape *line = (wxLineShape *)node->Data(); + m_lines.Append(line); + node = node->Next(); + } +} + +void wxShape::OnHighlight(wxDC& dc) +{ +} + +void wxShape::OnLeftClick(double x, double y, int keys, int attachment) +{ + if ((m_sensitivity & OP_CLICK_LEFT) != OP_CLICK_LEFT) + { + attachment = 0; + double dist; + if (m_parent) + { + m_parent->HitTest(x, y, &attachment, &dist); + m_parent->GetEventHandler()->OnLeftClick(x, y, keys, attachment); + } + return; + } +} + +void wxShape::OnRightClick(double x, double y, int keys, int attachment) +{ + if ((m_sensitivity & OP_CLICK_RIGHT) != OP_CLICK_RIGHT) + { + attachment = 0; + double dist; + if (m_parent) + { + m_parent->HitTest(x, y, &attachment, &dist); + m_parent->GetEventHandler()->OnRightClick(x, y, keys, attachment); + } + return; + } +} + +double DragOffsetX = 0.0; +double DragOffsetY = 0.0; + +void wxShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment) +{ + if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT) + { + attachment = 0; + double dist; + if (m_parent) + { + m_parent->HitTest(x, y, &attachment, &dist); + m_parent->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment); + } + return; + } + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + dc.SetLogicalFunction(OGLRBLF); + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetPen(dottedPen); + dc.SetBrush(* wxTRANSPARENT_BRUSH); + + double xx, yy; + xx = x + DragOffsetX; + yy = y + DragOffsetY; + + m_canvas->Snap(&xx, &yy); +// m_xpos = xx; m_ypos = yy; + double w, h; + GetBoundingBoxMax(&w, &h); + GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h); +} + +void wxShape::OnBeginDragLeft(double x, double y, int keys, int attachment) +{ + if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT) + { + attachment = 0; + double dist; + if (m_parent) + { + m_parent->HitTest(x, y, &attachment, &dist); + m_parent->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment); + } + return; + } + + DragOffsetX = m_xpos - x; + DragOffsetY = m_ypos - y; + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + // New policy: don't erase shape until end of drag. +// Erase(dc); + + double xx, yy; + xx = x + DragOffsetX; + yy = y + DragOffsetY; + m_canvas->Snap(&xx, &yy); +// m_xpos = xx; m_ypos = yy; + dc.SetLogicalFunction(OGLRBLF); + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetPen(dottedPen); + dc.SetBrush((* wxTRANSPARENT_BRUSH)); + + double w, h; + GetBoundingBoxMax(&w, &h); + GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h); + m_canvas->CaptureMouse(); +} + +void wxShape::OnEndDragLeft(double x, double y, int keys, int attachment) +{ + m_canvas->ReleaseMouse(); + if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT) + { + attachment = 0; + double dist; + if (m_parent) + { + m_parent->HitTest(x, y, &attachment, &dist); + m_parent->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment); + } + return; + } + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + dc.SetLogicalFunction(wxCOPY); + + double xx = x + DragOffsetX; + double yy = y + DragOffsetY; + m_canvas->Snap(&xx, &yy); +// canvas->Snap(&m_xpos, &m_ypos); + + // New policy: erase shape at end of drag. + Erase(dc); + + Move(dc, xx, yy); + if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc); +} + +void wxShape::OnDragRight(bool draw, double x, double y, int keys, int attachment) +{ + if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT) + { + attachment = 0; + double dist; + if (m_parent) + { + m_parent->HitTest(x, y, &attachment, &dist); + m_parent->GetEventHandler()->OnDragRight(draw, x, y, keys, attachment); + } + return; + } +} + +void wxShape::OnBeginDragRight(double x, double y, int keys, int attachment) +{ + if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT) + { + attachment = 0; + double dist; + if (m_parent) + { + m_parent->HitTest(x, y, &attachment, &dist); + m_parent->GetEventHandler()->OnBeginDragRight(x, y, keys, attachment); + } + return; + } +} + +void wxShape::OnEndDragRight(double x, double y, int keys, int attachment) +{ + if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT) + { + attachment = 0; + double dist; + if (m_parent) + { + m_parent->HitTest(x, y, &attachment, &dist); + m_parent->GetEventHandler()->OnEndDragRight(x, y, keys, attachment); + } + return; + } +} + +void wxShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h) +{ + double top_left_x = (double)(x - w/2.0); + double top_left_y = (double)(y - h/2.0); + double top_right_x = (double)(top_left_x + w); + double top_right_y = (double)top_left_y; + double bottom_left_x = (double)top_left_x; + double bottom_left_y = (double)(top_left_y + h); + double bottom_right_x = (double)top_right_x; + double bottom_right_y = (double)bottom_left_y; + + wxPoint points[5]; + points[0].x = WXROUND(top_left_x); points[0].y = WXROUND(top_left_y); + points[1].x = WXROUND(top_right_x); points[1].y = WXROUND(top_right_y); + points[2].x = WXROUND(bottom_right_x); points[2].y = WXROUND(bottom_right_y); + points[3].x = WXROUND(bottom_left_x); points[3].y = WXROUND(bottom_left_y); + points[4].x = WXROUND(top_left_x); points[4].y = WXROUND(top_left_y); + + dc.DrawLines(5, points); +} + +void wxShape::Attach(wxShapeCanvas *can) +{ + m_canvas = can; +} + +void wxShape::Detach() +{ + m_canvas = NULL; +} + +void wxShape::Move(wxDC& dc, double x, double y, bool display) +{ + double old_x = m_xpos; + double old_y = m_ypos; + + if (!GetEventHandler()->OnMovePre(dc, x, y, old_x, old_y, display)) + { +// m_xpos = old_x; +// m_ypos = old_y; + return; + } + + m_xpos = x; m_ypos = y; + + ResetControlPoints(); + + if (display) + Draw(dc); + + MoveLinks(dc); + + GetEventHandler()->OnMovePost(dc, x, y, old_x, old_y, display); +} + +void wxShape::MoveLinks(wxDC& dc) +{ + GetEventHandler()->OnMoveLinks(dc); +} + + +void wxShape::Draw(wxDC& dc) +{ + if (m_visible) + { + GetEventHandler()->OnDraw(dc); + GetEventHandler()->OnDrawContents(dc); + GetEventHandler()->OnDrawControlPoints(dc); + GetEventHandler()->OnDrawBranches(dc); + } +} + +void wxShape::Flash() +{ + if (GetCanvas()) + { + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + dc.SetLogicalFunction(OGLRBLF); + Draw(dc); + dc.SetLogicalFunction(wxCOPY); + Draw(dc); + } +} + +void wxShape::Show(bool show) +{ + m_visible = show; + wxNode *node = m_children.First(); + while (node) + { + wxShape *image = (wxShape *)node->Data(); + image->Show(show); + node = node->Next(); + } +} + +void wxShape::Erase(wxDC& dc) +{ + GetEventHandler()->OnErase(dc); + GetEventHandler()->OnEraseControlPoints(dc); + GetEventHandler()->OnDrawBranches(dc, TRUE); +} + +void wxShape::EraseContents(wxDC& dc) +{ + GetEventHandler()->OnEraseContents(dc); +} + +void wxShape::AddText(const wxString& string) +{ + wxNode *node = m_regions.First(); + if (!node) + return; + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + region->ClearText(); + wxShapeTextLine *new_line = + new wxShapeTextLine(0.0, 0.0, string); + region->GetFormattedText().Append(new_line); + + m_formatted = FALSE; +} + +void wxShape::SetSize(double x, double y, bool recursive) +{ + SetAttachmentSize(x, y); + SetDefaultRegionSize(); +} + +void wxShape::SetAttachmentSize(double w, double h) +{ + double scaleX; + double scaleY; + double width, height; + GetBoundingBoxMin(&width, &height); + if (width == 0.0) + scaleX = 1.0; + else scaleX = w/width; + if (height == 0.0) + scaleY = 1.0; + else scaleY = h/height; + + wxNode *node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + point->m_x = (double)(point->m_x * scaleX); + point->m_y = (double)(point->m_y * scaleY); + node = node->Next(); + } +} + +// Add line FROM this object +void wxShape::AddLine(wxLineShape *line, wxShape *other, + int attachFrom, int attachTo, + // The line ordering + int positionFrom, int positionTo) +{ + if (positionFrom == -1) + { + if (!m_lines.Member(line)) + m_lines.Append(line); + } + else + { + // Don't preserve old ordering if we have new ordering instructions + m_lines.DeleteObject(line); + if (positionFrom < m_lines.Number()) + { + wxNode* node = m_lines.Nth(positionFrom); + m_lines.Insert(node, line); + } + else + m_lines.Append(line); + } + + if (positionTo == -1) + { + if (!other->m_lines.Member(line)) + other->m_lines.Append(line); + } + else + { + // Don't preserve old ordering if we have new ordering instructions + other->m_lines.DeleteObject(line); + if (positionTo < other->m_lines.Number()) + { + wxNode* node = other->m_lines.Nth(positionTo); + other->m_lines.Insert(node, line); + } + else + other->m_lines.Append(line); + } +#if 0 + // Wrong: doesn't preserve ordering of shape already linked + m_lines.DeleteObject(line); + other->m_lines.DeleteObject(line); + + if (positionFrom == -1) + m_lines.Append(line); + else + { + if (positionFrom < m_lines.Number()) + { + wxNode* node = m_lines.Nth(positionFrom); + m_lines.Insert(node, line); + } + else + m_lines.Append(line); + } + + if (positionTo == -1) + other->m_lines.Append(line); + else + { + if (positionTo < other->m_lines.Number()) + { + wxNode* node = other->m_lines.Nth(positionTo); + other->m_lines.Insert(node, line); + } + else + other->m_lines.Append(line); + } +#endif + + line->SetFrom(this); + line->SetTo(other); + line->SetAttachments(attachFrom, attachTo); +} + +void wxShape::RemoveLine(wxLineShape *line) +{ + if (line->GetFrom() == this) + line->GetTo()->m_lines.DeleteObject(line); + else + line->GetFrom()->m_lines.DeleteObject(line); + + m_lines.DeleteObject(line); +} + +#ifdef PROLOGIO +void wxShape::WriteAttributes(wxExpr *clause) +{ + clause->AddAttributeValueString("type", GetClassInfo()->GetClassName()); + clause->AddAttributeValue("id", m_id); + + if (m_pen) + { + int penWidth = m_pen->GetWidth(); + int penStyle = m_pen->GetStyle(); + if (penWidth != 1) + clause->AddAttributeValue("pen_width", (long)penWidth); + if (penStyle != wxSOLID) + clause->AddAttributeValue("pen_style", (long)penStyle); + + wxString penColour = wxTheColourDatabase->FindName(m_pen->GetColour()); + if (penColour == "") + { + wxString hex(oglColourToHex(m_pen->GetColour())); + hex = wxString("#") + hex; + clause->AddAttributeValueString("pen_colour", hex); + } + else if (penColour != "BLACK") + clause->AddAttributeValueString("pen_colour", penColour); + } + + if (m_brush) + { + wxString brushColour = wxTheColourDatabase->FindName(m_brush->GetColour()); + + if (brushColour == "") + { + wxString hex(oglColourToHex(m_brush->GetColour())); + hex = wxString("#") + hex; + clause->AddAttributeValueString("brush_colour", hex); + } + else if (brushColour != "WHITE") + clause->AddAttributeValueString("brush_colour", brushColour); + + if (m_brush->GetStyle() != wxSOLID) + clause->AddAttributeValue("brush_style", (long)m_brush->GetStyle()); + } + + // Output line ids + + int n_lines = m_lines.Number(); + if (n_lines > 0) + { + wxExpr *list = new wxExpr(wxExprList); + wxNode *node = m_lines.First(); + while (node) + { + wxShape *line = (wxShape *)node->Data(); + wxExpr *id_expr = new wxExpr(line->GetId()); + list->Append(id_expr); + node = node->Next(); + } + clause->AddAttributeValue("arcs", list); + } + + // Miscellaneous members + if (m_attachmentMode != 0) + clause->AddAttributeValue("use_attachments", (long)m_attachmentMode); + if (m_sensitivity != OP_ALL) + clause->AddAttributeValue("sensitivity", (long)m_sensitivity); + if (!m_spaceAttachments) + clause->AddAttributeValue("space_attachments", (long)m_spaceAttachments); + if (m_fixedWidth) + clause->AddAttributeValue("fixed_width", (long)m_fixedWidth); + if (m_fixedHeight) + clause->AddAttributeValue("fixed_height", (long)m_fixedHeight); + if (m_shadowMode != SHADOW_NONE) + clause->AddAttributeValue("shadow_mode", (long)m_shadowMode); + if (m_centreResize != TRUE) + clause->AddAttributeValue("centre_resize", (long)0); + clause->AddAttributeValue("maintain_aspect_ratio", (long) m_maintainAspectRatio); + if (m_highlighted != FALSE) + clause->AddAttributeValue("hilite", (long)m_highlighted); + + if (m_parent) // For composite objects + clause->AddAttributeValue("parent", (long)m_parent->GetId()); + + if (m_rotation != 0.0) + clause->AddAttributeValue("rotation", m_rotation); + + if (!this->IsKindOf(CLASSINFO(wxLineShape))) + { + clause->AddAttributeValue("neck_length", (long) m_branchNeckLength); + clause->AddAttributeValue("stem_length", (long) m_branchStemLength); + clause->AddAttributeValue("branch_spacing", (long) m_branchSpacing); + clause->AddAttributeValue("branch_style", (long) m_branchStyle); + } + + // Write user-defined attachment points, if any + if (m_attachmentPoints.Number() > 0) + { + wxExpr *attachmentList = new wxExpr(wxExprList); + wxNode *node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + wxExpr *pointExpr = new wxExpr(wxExprList); + pointExpr->Append(new wxExpr((long)point->m_id)); + pointExpr->Append(new wxExpr(point->m_x)); + pointExpr->Append(new wxExpr(point->m_y)); + attachmentList->Append(pointExpr); + node = node->Next(); + } + clause->AddAttributeValue("user_attachments", attachmentList); + } + + // Write text regions + WriteRegions(clause); +} + +void wxShape::WriteRegions(wxExpr *clause) +{ + // Output regions as region1 = (...), region2 = (...), etc + // and formatted text as text1 = (...), text2 = (...) etc. + int regionNo = 1; + char regionNameBuf[20]; + char textNameBuf[20]; + wxNode *node = m_regions.First(); + while (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + sprintf(regionNameBuf, "region%d", regionNo); + sprintf(textNameBuf, "text%d", regionNo); + + // Original text and region attributes: + // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY + // formatMode fontSize fontFamily fontStyle fontWeight textColour) + wxExpr *regionExpr = new wxExpr(wxExprList); + regionExpr->Append(new wxExpr(wxExprString, region->m_regionName)); + regionExpr->Append(new wxExpr(wxExprString, region->m_regionText)); + + regionExpr->Append(new wxExpr(region->m_x)); + regionExpr->Append(new wxExpr(region->m_y)); + regionExpr->Append(new wxExpr(region->GetWidth())); + regionExpr->Append(new wxExpr(region->GetHeight())); + + regionExpr->Append(new wxExpr(region->m_minWidth)); + regionExpr->Append(new wxExpr(region->m_minHeight)); + regionExpr->Append(new wxExpr(region->m_regionProportionX)); + regionExpr->Append(new wxExpr(region->m_regionProportionY)); + + regionExpr->Append(new wxExpr((long)region->m_formatMode)); + + regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetPointSize() : 10))); + regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetFamily() : wxDEFAULT))); + regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetStyle() : wxDEFAULT))); + regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetWeight() : wxNORMAL))); + regionExpr->Append(new wxExpr(wxExprString, region->m_textColour)); + + // New members for pen colour/style + regionExpr->Append(new wxExpr(wxExprString, region->m_penColour)); + regionExpr->Append(new wxExpr((long)region->m_penStyle)); + + // Formatted text: + // text1 = ((x y string) (x y string) ...) + wxExpr *textExpr = new wxExpr(wxExprList); + + wxNode *textNode = region->m_formattedText.First(); + while (textNode) + { + wxShapeTextLine *line = (wxShapeTextLine *)textNode->Data(); + wxExpr *list2 = new wxExpr(wxExprList); + list2->Append(new wxExpr(line->GetX())); + list2->Append(new wxExpr(line->GetY())); + list2->Append(new wxExpr(wxExprString, line->GetText())); + textExpr->Append(list2); + textNode = textNode->Next(); + } + + // Now add both attributes to the clause + clause->AddAttributeValue(regionNameBuf, regionExpr); + clause->AddAttributeValue(textNameBuf, textExpr); + + node = node->Next(); + regionNo ++; + } +} + +void wxShape::ReadAttributes(wxExpr *clause) +{ + clause->GetAttributeValue("id", m_id); + wxRegisterId(m_id); + + clause->GetAttributeValue("x", m_xpos); + clause->GetAttributeValue("y", m_ypos); + + // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.) + ClearText(); + wxExpr *strings = clause->AttributeValue("text"); + if (strings && strings->Type() == wxExprList) + { + m_formatted = TRUE; // Assume text is formatted unless we prove otherwise + wxExpr *node = strings->value.first; + while (node) + { + wxExpr *string_expr = node; + double the_x = 0.0; + double the_y = 0.0; + wxString the_string(""); + + // string_expr can either be a string, or a list of + // 3 elements: x, y, and string. + if (string_expr->Type() == wxExprString) + { + the_string = string_expr->StringValue(); + m_formatted = FALSE; + } + else if (string_expr->Type() == wxExprList) + { + wxExpr *first = string_expr->value.first; + wxExpr *second = first ? first->next : (wxExpr*) NULL; + wxExpr *third = second ? second->next : (wxExpr*) NULL; + + if (first && second && third && + (first->Type() == wxExprReal || first->Type() == wxExprInteger) && + (second->Type() == wxExprReal || second->Type() == wxExprInteger) && + third->Type() == wxExprString) + { + if (first->Type() == wxExprReal) + the_x = first->RealValue(); + else the_x = (double)first->IntegerValue(); + + if (second->Type() == wxExprReal) + the_y = second->RealValue(); + else the_y = (double)second->IntegerValue(); + + the_string = third->StringValue(); + } + } + wxShapeTextLine *line = + new wxShapeTextLine(the_x, the_y, (char*) (const char*) the_string); + m_text.Append(line); + + node = node->next; + } + } + + wxString pen_string = ""; + wxString brush_string = ""; + int pen_width = 1; + int pen_style = wxSOLID; + int brush_style = wxSOLID; + m_attachmentMode = ATTACHMENT_MODE_NONE; + + clause->GetAttributeValue("pen_colour", pen_string); + clause->GetAttributeValue("text_colour", m_textColourName); + + SetTextColour(m_textColourName); + + clause->GetAttributeValue("region_name", m_regionName); + + clause->GetAttributeValue("brush_colour", brush_string); + clause->GetAttributeValue("pen_width", pen_width); + clause->GetAttributeValue("pen_style", pen_style); + clause->GetAttributeValue("brush_style", brush_style); + + int iVal = (int) m_attachmentMode; + clause->GetAttributeValue("use_attachments", iVal); + m_attachmentMode = iVal; + + clause->GetAttributeValue("sensitivity", m_sensitivity); + + iVal = (int) m_spaceAttachments; + clause->GetAttributeValue("space_attachments", iVal); + m_spaceAttachments = (iVal != 0); + + iVal = (int) m_fixedWidth; + clause->GetAttributeValue("fixed_width", iVal); + m_fixedWidth = (iVal != 0); + + iVal = (int) m_fixedHeight; + clause->GetAttributeValue("fixed_height", iVal); + m_fixedHeight = (iVal != 0); + + clause->GetAttributeValue("format_mode", m_formatMode); + clause->GetAttributeValue("shadow_mode", m_shadowMode); + + iVal = m_branchNeckLength; + clause->GetAttributeValue("neck_length", iVal); + m_branchNeckLength = iVal; + + iVal = m_branchStemLength; + clause->GetAttributeValue("stem_length", iVal); + m_branchStemLength = iVal; + + iVal = m_branchSpacing; + clause->GetAttributeValue("branch_spacing", iVal); + m_branchSpacing = iVal; + + clause->GetAttributeValue("branch_style", m_branchStyle); + + iVal = (int) m_centreResize; + clause->GetAttributeValue("centre_resize", iVal); + m_centreResize = (iVal != 0); + + iVal = (int) m_maintainAspectRatio; + clause->GetAttributeValue("maintain_aspect_ratio", iVal); + m_maintainAspectRatio = (iVal != 0); + + iVal = (int) m_highlighted; + clause->GetAttributeValue("hilite", iVal); + m_highlighted = (iVal != 0); + + clause->GetAttributeValue("rotation", m_rotation); + + if (pen_string == "") + pen_string = "BLACK"; + if (brush_string == "") + brush_string = "WHITE"; + + if (pen_string.GetChar(0) == '#') + { + wxColour col(oglHexToColour(pen_string.After('#'))); + m_pen = wxThePenList->FindOrCreatePen(col, pen_width, pen_style); + } + else + m_pen = wxThePenList->FindOrCreatePen(pen_string, pen_width, pen_style); + + if (!m_pen) + m_pen = wxBLACK_PEN; + + if (brush_string.GetChar(0) == '#') + { + wxColour col(oglHexToColour(brush_string.After('#'))); + m_brush = wxTheBrushList->FindOrCreateBrush(col, brush_style); + } + else + m_brush = wxTheBrushList->FindOrCreateBrush(brush_string, brush_style); + + if (!m_brush) + m_brush = wxWHITE_BRUSH; + + int point_size = 10; + clause->GetAttributeValue("point_size", point_size); + SetFont(oglMatchFont(point_size)); + + // Read user-defined attachment points, if any + wxExpr *attachmentList = clause->AttributeValue("user_attachments"); + if (attachmentList) + { + wxExpr *pointExpr = attachmentList->GetFirst(); + while (pointExpr) + { + wxExpr *idExpr = pointExpr->Nth(0); + wxExpr *xExpr = pointExpr->Nth(1); + wxExpr *yExpr = pointExpr->Nth(2); + if (idExpr && xExpr && yExpr) + { + wxAttachmentPoint *point = new wxAttachmentPoint; + point->m_id = (int)idExpr->IntegerValue(); + point->m_x = xExpr->RealValue(); + point->m_y = yExpr->RealValue(); + m_attachmentPoints.Append((wxObject *)point); + } + pointExpr = pointExpr->GetNext(); + } + } + + // Read text regions + ReadRegions(clause); +} + +void wxShape::ReadRegions(wxExpr *clause) +{ + ClearRegions(); + + // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY + // formatMode fontSize fontFamily fontStyle fontWeight textColour) + int regionNo = 1; + char regionNameBuf[20]; + char textNameBuf[20]; + + wxExpr *regionExpr = NULL; + wxExpr *textExpr = NULL; + sprintf(regionNameBuf, "region%d", regionNo); + sprintf(textNameBuf, "text%d", regionNo); + + m_formatted = TRUE; // Assume text is formatted unless we prove otherwise + + while ((regionExpr = clause->AttributeValue(regionNameBuf))) + { + /* + * Get the region information + * + */ + + wxString regionName(""); + wxString regionText(""); + double x = 0.0; + double y = 0.0; + double width = 0.0; + double height = 0.0; + double minWidth = 5.0; + double minHeight = 5.0; + double m_regionProportionX = -1.0; + double m_regionProportionY = -1.0; + int formatMode = FORMAT_NONE; + int fontSize = 10; + int fontFamily = wxSWISS; + int fontStyle = wxNORMAL; + int fontWeight = wxNORMAL; + wxString regionTextColour(""); + wxString penColour(""); + int penStyle = wxSOLID; + + if (regionExpr->Type() == wxExprList) + { + wxExpr *nameExpr = regionExpr->Nth(0); + wxExpr *textExpr = regionExpr->Nth(1); + wxExpr *xExpr = regionExpr->Nth(2); + wxExpr *yExpr = regionExpr->Nth(3); + wxExpr *widthExpr = regionExpr->Nth(4); + wxExpr *heightExpr = regionExpr->Nth(5); + wxExpr *minWidthExpr = regionExpr->Nth(6); + wxExpr *minHeightExpr = regionExpr->Nth(7); + wxExpr *propXExpr = regionExpr->Nth(8); + wxExpr *propYExpr = regionExpr->Nth(9); + wxExpr *formatExpr = regionExpr->Nth(10); + wxExpr *sizeExpr = regionExpr->Nth(11); + wxExpr *familyExpr = regionExpr->Nth(12); + wxExpr *styleExpr = regionExpr->Nth(13); + wxExpr *weightExpr = regionExpr->Nth(14); + wxExpr *colourExpr = regionExpr->Nth(15); + wxExpr *penColourExpr = regionExpr->Nth(16); + wxExpr *penStyleExpr = regionExpr->Nth(17); + + regionName = nameExpr->StringValue(); + regionText = textExpr->StringValue(); + + x = xExpr->RealValue(); + y = yExpr->RealValue(); + + width = widthExpr->RealValue(); + height = heightExpr->RealValue(); + + minWidth = minWidthExpr->RealValue(); + minHeight = minHeightExpr->RealValue(); + + m_regionProportionX = propXExpr->RealValue(); + m_regionProportionY = propYExpr->RealValue(); + + formatMode = (int) formatExpr->IntegerValue(); + fontSize = (int)sizeExpr->IntegerValue(); + fontFamily = (int)familyExpr->IntegerValue(); + fontStyle = (int)styleExpr->IntegerValue(); + fontWeight = (int)weightExpr->IntegerValue(); + + if (colourExpr) + { + regionTextColour = colourExpr->StringValue(); + } + else + regionTextColour = "BLACK"; + + if (penColourExpr) + penColour = penColourExpr->StringValue(); + if (penStyleExpr) + penStyle = (int)penStyleExpr->IntegerValue(); + } + wxFont *font = wxTheFontList->FindOrCreateFont(fontSize, fontFamily, fontStyle, fontWeight); + + wxShapeRegion *region = new wxShapeRegion; + region->SetProportions(m_regionProportionX, m_regionProportionY); + region->SetFont(font); + region->SetSize(width, height); + region->SetPosition(x, y); + region->SetMinSize(minWidth, minHeight); + region->SetFormatMode(formatMode); + region->SetPenStyle(penStyle); + if (penColour != "") + region->SetPenColour(penColour); + + region->m_textColour = regionTextColour; + region->m_regionText = regionText; + region->m_regionName = regionName; + + m_regions.Append(region); + + /* + * Get the formatted text strings + * + */ + textExpr = clause->AttributeValue(textNameBuf); + if (textExpr && (textExpr->Type() == wxExprList)) + { + wxExpr *node = textExpr->value.first; + while (node) + { + wxExpr *string_expr = node; + double the_x = 0.0; + double the_y = 0.0; + wxString the_string(""); + + // string_expr can either be a string, or a list of + // 3 elements: x, y, and string. + if (string_expr->Type() == wxExprString) + { + the_string = string_expr->StringValue(); + m_formatted = FALSE; + } + else if (string_expr->Type() == wxExprList) + { + wxExpr *first = string_expr->value.first; + wxExpr *second = first ? first->next : (wxExpr*) NULL; + wxExpr *third = second ? second->next : (wxExpr*) NULL; + + if (first && second && third && + (first->Type() == wxExprReal || first->Type() == wxExprInteger) && + (second->Type() == wxExprReal || second->Type() == wxExprInteger) && + third->Type() == wxExprString) + { + if (first->Type() == wxExprReal) + the_x = first->RealValue(); + else the_x = (double)first->IntegerValue(); + + if (second->Type() == wxExprReal) + the_y = second->RealValue(); + else the_y = (double)second->IntegerValue(); + + the_string = third->StringValue(); + } + } + if (the_string) + { + wxShapeTextLine *line = + new wxShapeTextLine(the_x, the_y, (char*) (const char*) the_string); + region->m_formattedText.Append(line); + } + node = node->next; + } + } + + regionNo ++; + sprintf(regionNameBuf, "region%d", regionNo); + sprintf(textNameBuf, "text%d", regionNo); + } + + // Compatibility: check for no regions (old file). + // Lines and divided rectangles must deal with this compatibility + // theirselves. Composites _may_ not have any regions anyway. + if ((m_regions.Number() == 0) && + !this->IsKindOf(CLASSINFO(wxLineShape)) && !this->IsKindOf(CLASSINFO(wxDividedShape)) && + !this->IsKindOf(CLASSINFO(wxCompositeShape))) + { + wxShapeRegion *newRegion = new wxShapeRegion; + newRegion->SetName("0"); + m_regions.Append((wxObject *)newRegion); + if (m_text.Number() > 0) + { + newRegion->ClearText(); + wxNode *node = m_text.First(); + while (node) + { + wxShapeTextLine *textLine = (wxShapeTextLine *)node->Data(); + wxNode *next = node->Next(); + newRegion->GetFormattedText().Append((wxObject *)textLine); + delete node; + node = next; + } + } + } +} + +#endif + +void wxShape::Copy(wxShape& copy) +{ + copy.m_id = m_id; + copy.m_xpos = m_xpos; + copy.m_ypos = m_ypos; + copy.m_pen = m_pen; + copy.m_brush = m_brush; + copy.m_textColour = m_textColour; + copy.m_centreResize = m_centreResize; + copy.m_maintainAspectRatio = m_maintainAspectRatio; + copy.m_attachmentMode = m_attachmentMode; + copy.m_spaceAttachments = m_spaceAttachments; + copy.m_highlighted = m_highlighted; + copy.m_rotation = m_rotation; + copy.m_textColourName = m_textColourName; + copy.m_regionName = m_regionName; + + copy.m_sensitivity = m_sensitivity; + copy.m_draggable = m_draggable; + copy.m_fixedWidth = m_fixedWidth; + copy.m_fixedHeight = m_fixedHeight; + copy.m_formatMode = m_formatMode; + copy.m_drawHandles = m_drawHandles; + + copy.m_visible = m_visible; + copy.m_shadowMode = m_shadowMode; + copy.m_shadowOffsetX = m_shadowOffsetX; + copy.m_shadowOffsetY = m_shadowOffsetY; + copy.m_shadowBrush = m_shadowBrush; + + copy.m_branchNeckLength = m_branchNeckLength; + copy.m_branchStemLength = m_branchStemLength; + copy.m_branchSpacing = m_branchSpacing; + + // Copy text regions + copy.ClearRegions(); + wxNode *node = m_regions.First(); + while (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + wxShapeRegion *newRegion = new wxShapeRegion(*region); + copy.m_regions.Append(newRegion); + node = node->Next(); + } + + // Copy attachments + copy.ClearAttachments(); + node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + wxAttachmentPoint *newPoint = new wxAttachmentPoint; + newPoint->m_id = point->m_id; + newPoint->m_x = point->m_x; + newPoint->m_y = point->m_y; + copy.m_attachmentPoints.Append((wxObject *)newPoint); + node = node->Next(); + } + + // Copy lines + copy.m_lines.Clear(); + node = m_lines.First(); + while (node) + { + wxLineShape* line = (wxLineShape*) node->Data(); + copy.m_lines.Append(line); + node = node->Next(); + } +} + +// Create and return a new, fully copied object. +wxShape *wxShape::CreateNewCopy(bool resetMapping, bool recompute) +{ + if (resetMapping) + oglObjectCopyMapping.Clear(); + + wxShape* newObject = (wxShape*) GetClassInfo()->CreateObject(); + + wxASSERT( (newObject != NULL) ); + wxASSERT( (newObject->IsKindOf(CLASSINFO(wxShape))) ); + + Copy(*newObject); + + if (GetEventHandler() != this) + { + wxShapeEvtHandler* newHandler = GetEventHandler()->CreateNewCopy(); + newObject->SetEventHandler(newHandler); + newObject->SetPreviousHandler(NULL); + newHandler->SetPreviousHandler(newObject); + newHandler->SetShape(newObject); + } + + if (recompute) + newObject->Recompute(); + return newObject; +} + +// Does the copying for this object, including copying event +// handler data if any. Calls the virtual Copy function. +void wxShape::CopyWithHandler(wxShape& copy) +{ + Copy(copy); + + if (GetEventHandler() != this) + { + wxASSERT( copy.GetEventHandler() != NULL ); + wxASSERT( copy.GetEventHandler() != (©) ); + wxASSERT( GetEventHandler()->GetClassInfo() == copy.GetEventHandler()->GetClassInfo() ); + GetEventHandler()->CopyData(* (copy.GetEventHandler())); + } +} + + +// Default - make 6 control points +void wxShape::MakeControlPoints() +{ + double maxX, maxY, minX, minY; + + GetBoundingBoxMax(&maxX, &maxY); + GetBoundingBoxMin(&minX, &minY); + + double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2); + double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2); + + // Offsets from main object + double top = (double)(- (heightMin / 2.0)); + double bottom = (double)(heightMin / 2.0 + (maxY - minY)); + double left = (double)(- (widthMin / 2.0)); + double right = (double)(widthMin / 2.0 + (maxX - minX)); + + wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top, + CONTROL_POINT_DIAGONAL); + m_canvas->AddShape(control); + m_controlPoints.Append(control); + + control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, top, + CONTROL_POINT_VERTICAL); + m_canvas->AddShape(control); + m_controlPoints.Append(control); + + control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, top, + CONTROL_POINT_DIAGONAL); + m_canvas->AddShape(control); + m_controlPoints.Append(control); + + control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, 0, + CONTROL_POINT_HORIZONTAL); + m_canvas->AddShape(control); + m_controlPoints.Append(control); + + control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, bottom, + CONTROL_POINT_DIAGONAL); + m_canvas->AddShape(control); + m_controlPoints.Append(control); + + control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, bottom, + CONTROL_POINT_VERTICAL); + m_canvas->AddShape(control); + m_controlPoints.Append(control); + + control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, bottom, + CONTROL_POINT_DIAGONAL); + m_canvas->AddShape(control); + m_controlPoints.Append(control); + + control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, 0, + CONTROL_POINT_HORIZONTAL); + m_canvas->AddShape(control); + m_controlPoints.Append(control); + +} + +void wxShape::MakeMandatoryControlPoints() +{ + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->MakeMandatoryControlPoints(); + node = node->Next(); + } +} + +void wxShape::ResetMandatoryControlPoints() +{ + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->ResetMandatoryControlPoints(); + node = node->Next(); + } +} + +void wxShape::ResetControlPoints() +{ + ResetMandatoryControlPoints(); + + if (m_controlPoints.Number() < 1) + return; + + double maxX, maxY, minX, minY; + + GetBoundingBoxMax(&maxX, &maxY); + GetBoundingBoxMin(&minX, &minY); + + double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2); + double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2); + + // Offsets from main object + double top = (double)(- (heightMin / 2.0)); + double bottom = (double)(heightMin / 2.0 + (maxY - minY)); + double left = (double)(- (widthMin / 2.0)); + double right = (double)(widthMin / 2.0 + (maxX - minX)); + + wxNode *node = m_controlPoints.First(); + wxControlPoint *control = (wxControlPoint *)node->Data(); + control->m_xoffset = left; control->m_yoffset = top; + + node = node->Next(); control = (wxControlPoint *)node->Data(); + control->m_xoffset = 0; control->m_yoffset = top; + + node = node->Next(); control = (wxControlPoint *)node->Data(); + control->m_xoffset = right; control->m_yoffset = top; + + node = node->Next(); control = (wxControlPoint *)node->Data(); + control->m_xoffset = right; control->m_yoffset = 0; + + node = node->Next(); control = (wxControlPoint *)node->Data(); + control->m_xoffset = right; control->m_yoffset = bottom; + + node = node->Next(); control = (wxControlPoint *)node->Data(); + control->m_xoffset = 0; control->m_yoffset = bottom; + + node = node->Next(); control = (wxControlPoint *)node->Data(); + control->m_xoffset = left; control->m_yoffset = bottom; + + node = node->Next(); control = (wxControlPoint *)node->Data(); + control->m_xoffset = left; control->m_yoffset = 0; +} + +void wxShape::DeleteControlPoints(wxDC *dc) +{ + wxNode *node = m_controlPoints.First(); + while (node) + { + wxControlPoint *control = (wxControlPoint *)node->Data(); + if (dc) + control->GetEventHandler()->OnErase(*dc); + m_canvas->RemoveShape(control); + delete control; + delete node; + node = m_controlPoints.First(); + } + // Children of divisions are contained objects, + // so stop here + if (!IsKindOf(CLASSINFO(wxDivisionShape))) + { + node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->DeleteControlPoints(dc); + node = node->Next(); + } + } +} + +void wxShape::OnDrawControlPoints(wxDC& dc) +{ + if (!m_drawHandles) + return; + + dc.SetBrush(* wxBLACK_BRUSH); + dc.SetPen(* wxBLACK_PEN); + + wxNode *node = m_controlPoints.First(); + while (node) + { + wxControlPoint *control = (wxControlPoint *)node->Data(); + control->Draw(dc); + node = node->Next(); + } + // Children of divisions are contained objects, + // so stop here. + // This test bypasses the type facility for speed + // (critical when drawing) + if (!IsKindOf(CLASSINFO(wxDivisionShape))) + { + node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->GetEventHandler()->OnDrawControlPoints(dc); + node = node->Next(); + } + } +} + +void wxShape::OnEraseControlPoints(wxDC& dc) +{ + wxNode *node = m_controlPoints.First(); + while (node) + { + wxControlPoint *control = (wxControlPoint *)node->Data(); + control->Erase(dc); + node = node->Next(); + } + if (!IsKindOf(CLASSINFO(wxDivisionShape))) + { + node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->GetEventHandler()->OnEraseControlPoints(dc); + node = node->Next(); + } + } +} + +void wxShape::Select(bool select, wxDC* dc) +{ + m_selected = select; + if (select) + { + MakeControlPoints(); + // Children of divisions are contained objects, + // so stop here + if (!IsKindOf(CLASSINFO(wxDivisionShape))) + { + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->MakeMandatoryControlPoints(); + node = node->Next(); + } + } + if (dc) + GetEventHandler()->OnDrawControlPoints(*dc); + } + if (!select) + { + DeleteControlPoints(dc); + if (!IsKindOf(CLASSINFO(wxDivisionShape))) + { + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + child->DeleteControlPoints(dc); + node = node->Next(); + } + } + } +} + +bool wxShape::Selected() const +{ + return m_selected; +} + +bool wxShape::AncestorSelected() const +{ + if (m_selected) return TRUE; + if (!GetParent()) + return FALSE; + else + return GetParent()->AncestorSelected(); +} + +int wxShape::GetNumberOfAttachments() const +{ + // Should return the MAXIMUM attachment point id here, + // so higher-level functions can iterate through all attachments, + // even if they're not contiguous. + if (m_attachmentPoints.Number() == 0) + return 4; + else + { + int maxN = 3; + wxNode *node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + if (point->m_id > maxN) + maxN = point->m_id; + node = node->Next(); + } + return maxN+1;; + } +} + +bool wxShape::AttachmentIsValid(int attachment) const +{ + if (m_attachmentPoints.Number() == 0) + { + return ((attachment >= 0) && (attachment < 4)) ; + } + + wxNode *node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + if (point->m_id == attachment) + return TRUE; + node = node->Next(); + } + return FALSE; +} + +bool wxShape::GetAttachmentPosition(int attachment, double *x, double *y, + int nth, int no_arcs, wxLineShape *line) +{ + if (m_attachmentMode == ATTACHMENT_MODE_NONE) + { + *x = m_xpos; *y = m_ypos; + return TRUE; + } + else if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING) + { + wxRealPoint pt, stemPt; + GetBranchingAttachmentPoint(attachment, nth, pt, stemPt); + *x = pt.x; + *y = pt.y; + return TRUE; + } + else if (m_attachmentMode == ATTACHMENT_MODE_EDGE) + { + if (m_attachmentPoints.Number() > 0) + { + wxNode *node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + if (point->m_id == attachment) + { + *x = (double)(m_xpos + point->m_x); + *y = (double)(m_ypos + point->m_y); + return TRUE; + } + node = node->Next(); + } + *x = m_xpos; *y = m_ypos; + return FALSE; + } + else + { + // Assume is rectangular + double w, h; + GetBoundingBoxMax(&w, &h); + double top = (double)(m_ypos + h/2.0); + double bottom = (double)(m_ypos - h/2.0); + double left = (double)(m_xpos - w/2.0); + double right = (double)(m_xpos + w/2.0); + + bool isEnd = (line && line->IsEnd(this)); + + int physicalAttachment = LogicalToPhysicalAttachment(attachment); + + // Simplified code + switch (physicalAttachment) + { + case 0: + { + wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(right, bottom), + nth, no_arcs, line); + + *x = pt.x; *y = pt.y; + break; + } + case 1: + { + wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(right, bottom), wxRealPoint(right, top), + nth, no_arcs, line); + + *x = pt.x; *y = pt.y; + break; + } + case 2: + { + wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, top), wxRealPoint(right, top), + nth, no_arcs, line); + + *x = pt.x; *y = pt.y; + break; + } + case 3: + { + wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(left, top), + nth, no_arcs, line); + + *x = pt.x; *y = pt.y; + break; + } + default: + { + return FALSE; + break; + } + } + return TRUE; + } + } + return FALSE; +} + +void wxShape::GetBoundingBoxMax(double *w, double *h) +{ + double ww, hh; + GetBoundingBoxMin(&ww, &hh); + if (m_shadowMode != SHADOW_NONE) + { + ww += m_shadowOffsetX; + hh += m_shadowOffsetY; + } + *w = ww; + *h = hh; +} + +// Returns TRUE if image is a descendant of this composite +bool wxShape::HasDescendant(wxShape *image) +{ + if (image == this) + return TRUE; + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + bool ans = child->HasDescendant(image); + if (ans) + return TRUE; + node = node->Next(); + } + return FALSE; +} + +// Clears points from a list of wxRealPoints, and clears list +void wxShape::ClearPointList(wxList& list) +{ + wxNode* node = list.First(); + while (node) + { + wxRealPoint* pt = (wxRealPoint*) node->Data(); + delete pt; + + node = node->Next(); + } + list.Clear(); +} + +// Assuming the attachment lies along a vertical or horizontal line, +// calculate the position on that point. +wxRealPoint wxShape::CalcSimpleAttachment(const wxRealPoint& pt1, const wxRealPoint& pt2, + int nth, int noArcs, wxLineShape* line) +{ + bool isEnd = (line && line->IsEnd(this)); + + // Are we horizontal or vertical? + bool isHorizontal = (oglRoughlyEqual(pt1.y, pt2.y) == TRUE); + + double x, y; + + if (isHorizontal) + { + wxRealPoint firstPoint, secondPoint; + if (pt1.x > pt2.x) + { + firstPoint = pt2; + secondPoint = pt1; + } + else + { + firstPoint = pt1; + secondPoint = pt2; + } + + if (m_spaceAttachments) + { + if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE)) + { + // Align line according to the next handle along + wxRealPoint *point = line->GetNextControlPoint(this); + if (point->x < firstPoint.x) + x = firstPoint.x; + else if (point->x > secondPoint.x) + x = secondPoint.x; + else + x = point->x; + } + else + x = firstPoint.x + (nth + 1)*(secondPoint.x - firstPoint.x)/(noArcs + 1); + } + else x = (secondPoint.x - firstPoint.x)/2.0; // Midpoint + + y = pt1.y; + } + else + { + wxASSERT( oglRoughlyEqual(pt1.x, pt2.x) == TRUE ); + + wxRealPoint firstPoint, secondPoint; + if (pt1.y > pt2.y) + { + firstPoint = pt2; + secondPoint = pt1; + } + else + { + firstPoint = pt1; + secondPoint = pt2; + } + + if (m_spaceAttachments) + { + if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE)) + { + // Align line according to the next handle along + wxRealPoint *point = line->GetNextControlPoint(this); + if (point->y < firstPoint.y) + y = firstPoint.y; + else if (point->y > secondPoint.y) + y = secondPoint.y; + else + y = point->y; + } + else + y = firstPoint.y + (nth + 1)*(secondPoint.y - firstPoint.y)/(noArcs + 1); + } + else y = (secondPoint.y - firstPoint.y)/2.0; // Midpoint + + x = pt1.x; + } + + return wxRealPoint(x, y); +} + +// Return the zero-based position in m_lines of line. +int wxShape::GetLinePosition(wxLineShape* line) +{ + int i = 0; + for (i = 0; i < m_lines.Number(); i++) + if ((wxLineShape*) (m_lines.Nth(i)->Data()) == line) + return i; + + return 0; +} + +// +// |________| +// | <- root +// | <- neck +// shoulder1 ->---------<- shoulder2 +// | | | | | +// <- branching attachment point N-1 + +// This function gets information about where branching connections go. +// Returns FALSE if there are no lines at this attachment. +bool wxShape::GetBranchingAttachmentInfo(int attachment, wxRealPoint& root, wxRealPoint& neck, + wxRealPoint& shoulder1, wxRealPoint& shoulder2) +{ + int physicalAttachment = LogicalToPhysicalAttachment(attachment); + + // Number of lines at this attachment. + int lineCount = GetAttachmentLineCount(attachment); + + if (lineCount == 0) + return FALSE; + + int totalBranchLength = m_branchSpacing * (lineCount - 1); + + root = GetBranchingAttachmentRoot(attachment); + + // Assume that we have attachment points 0 to 3: top, right, bottom, left. + switch (physicalAttachment) + { + case 0: + { + neck.x = GetX(); + neck.y = root.y - m_branchNeckLength; + + shoulder1.x = root.x - (totalBranchLength/2.0) ; + shoulder2.x = root.x + (totalBranchLength/2.0) ; + + shoulder1.y = neck.y; + shoulder2.y = neck.y; + break; + } + case 1: + { + neck.x = root.x + m_branchNeckLength; + neck.y = root.y; + + shoulder1.x = neck.x ; + shoulder2.x = neck.x ; + + shoulder1.y = neck.y - (totalBranchLength/2.0) ; + shoulder2.y = neck.y + (totalBranchLength/2.0) ; + break; + } + case 2: + { + neck.x = GetX(); + neck.y = root.y + m_branchNeckLength; + + shoulder1.x = root.x - (totalBranchLength/2.0) ; + shoulder2.x = root.x + (totalBranchLength/2.0) ; + + shoulder1.y = neck.y; + shoulder2.y = neck.y; + break; + } + case 3: + { + neck.x = root.x - m_branchNeckLength; + neck.y = root.y ; + + shoulder1.x = neck.x ; + shoulder2.x = neck.x ; + + shoulder1.y = neck.y - (totalBranchLength/2.0) ; + shoulder2.y = neck.y + (totalBranchLength/2.0) ; + break; + } + default: + { + wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentInfo." ); + break; + } + } + return TRUE; +} + +// n is the number of the adjoining line, from 0 to N-1 where N is the number of lines +// at this attachment point. +// Get the attachment point where the arc joins the stem, and also the point where the +// the stem meets the shoulder. +bool wxShape::GetBranchingAttachmentPoint(int attachment, int n, wxRealPoint& pt, wxRealPoint& stemPt) +{ + int physicalAttachment = LogicalToPhysicalAttachment(attachment); + + wxRealPoint root, neck, shoulder1, shoulder2; + GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2); + + // Assume that we have attachment points 0 to 3: top, right, bottom, left. + switch (physicalAttachment) + { + case 0: + { + pt.y = neck.y - m_branchStemLength; + pt.x = shoulder1.x + n*m_branchSpacing; + + stemPt.x = pt.x; + stemPt.y = neck.y; + break; + } + case 2: + { + pt.y = neck.y + m_branchStemLength; + pt.x = shoulder1.x + n*m_branchSpacing; + + stemPt.x = pt.x; + stemPt.y = neck.y; + break; + } + case 1: + { + pt.x = neck.x + m_branchStemLength; + pt.y = shoulder1.y + n*m_branchSpacing; + + stemPt.x = neck.x; + stemPt.y = pt.y; + break; + } + case 3: + { + pt.x = neck.x - m_branchStemLength; + pt.y = shoulder1.y + n*m_branchSpacing; + + stemPt.x = neck.x; + stemPt.y = pt.y; + break; + } + default: + { + wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentPoint." ); + break; + } + } + + return TRUE; +} + +// Get the number of lines at this attachment position. +int wxShape::GetAttachmentLineCount(int attachment) const +{ + int count = 0; + wxNode* node = m_lines.First(); + while (node) + { + wxLineShape* lineShape = (wxLineShape*) node->Data(); + if ((lineShape->GetFrom() == this) && (lineShape->GetAttachmentFrom() == attachment)) + count ++; + else if ((lineShape->GetTo() == this) && (lineShape->GetAttachmentTo() == attachment)) + count ++; + + node = node->Next(); + } + return count; +} + +// This function gets the root point at the given attachment. +wxRealPoint wxShape::GetBranchingAttachmentRoot(int attachment) +{ + int physicalAttachment = LogicalToPhysicalAttachment(attachment); + + wxRealPoint root; + + double width, height; + GetBoundingBoxMax(& width, & height); + + // Assume that we have attachment points 0 to 3: top, right, bottom, left. + switch (physicalAttachment) + { + case 0: + { + root.x = GetX() ; + root.y = GetY() - height/2.0; + break; + } + case 1: + { + root.x = GetX() + width/2.0; + root.y = GetY() ; + break; + } + case 2: + { + root.x = GetX() ; + root.y = GetY() + height/2.0; + break; + } + case 3: + { + root.x = GetX() - width/2.0; + root.y = GetY() ; + break; + } + default: + { + wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentRoot." ); + break; + } + } + return root; +} + +// Draw or erase the branches (not the actual arcs though) +void wxShape::OnDrawBranches(wxDC& dc, int attachment, bool erase) +{ + int count = GetAttachmentLineCount(attachment); + if (count == 0) + return; + + wxRealPoint root, neck, shoulder1, shoulder2; + GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2); + + if (erase) + { + dc.SetPen(*wxWHITE_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + } + else + { + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxBLACK_BRUSH); + } + + // Draw neck + dc.DrawLine((long) root.x, (long) root.y, (long) neck.x, (long) neck.y); + + if (count > 1) + { + // Draw shoulder-to-shoulder line + dc.DrawLine((long) shoulder1.x, (long) shoulder1.y, (long) shoulder2.x, (long) shoulder2.y); + } + // Draw all the little branches + int i; + for (i = 0; i < count; i++) + { + wxRealPoint pt, stemPt; + GetBranchingAttachmentPoint(attachment, i, pt, stemPt); + dc.DrawLine((long) stemPt.x, (long) stemPt.y, (long) pt.x, (long) pt.y); + + if ((GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB) && (count > 1)) + { + long blobSize=6; +// dc.DrawEllipse((long) (stemPt.x + 0.5 - (blobSize/2.0)), (long) (stemPt.y + 0.5 - (blobSize/2.0)), blobSize, blobSize); + dc.DrawEllipse((long) (stemPt.x - (blobSize/2.0)), (long) (stemPt.y - (blobSize/2.0)), blobSize, blobSize); + } + } +} + +// Draw or erase the branches (not the actual arcs though) +void wxShape::OnDrawBranches(wxDC& dc, bool erase) +{ + if (m_attachmentMode != ATTACHMENT_MODE_BRANCHING) + return; + + int count = GetNumberOfAttachments(); + int i; + for (i = 0; i < count; i++) + OnDrawBranches(dc, i, erase); +} + +// Only get the attachment position at the _edge_ of the shape, ignoring +// branching mode. This is used e.g. to indicate the edge of interest, not the point +// on the attachment branch. +bool wxShape::GetAttachmentPositionEdge(int attachment, double *x, double *y, + int nth, int no_arcs, wxLineShape *line) +{ + int oldMode = m_attachmentMode; + + // Calculate as if to edge, not branch + if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING) + m_attachmentMode = ATTACHMENT_MODE_EDGE; + bool success = GetAttachmentPosition(attachment, x, y, nth, no_arcs, line); + m_attachmentMode = oldMode; + + return success; +} + +// Rotate the standard attachment point from physical (0 is always North) +// to logical (0 -> 1 if rotated by 90 degrees) +int wxShape::PhysicalToLogicalAttachment(int physicalAttachment) const +{ + const double pi = 3.1415926535897932384626433832795 ; + int i; + if (oglRoughlyEqual(GetRotation(), 0.0)) + { + i = physicalAttachment; + } + else if (oglRoughlyEqual(GetRotation(), (pi/2.0))) + { + i = physicalAttachment - 1; + } + else if (oglRoughlyEqual(GetRotation(), pi)) + { + i = physicalAttachment - 2; + } + else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0))) + { + i = physicalAttachment - 3; + } + else + // Can't handle -- assume the same. + return physicalAttachment; + + if (i < 0) + i += 4; + + return i; +} + +// Rotate the standard attachment point from logical +// to physical (0 is always North) +int wxShape::LogicalToPhysicalAttachment(int logicalAttachment) const +{ + const double pi = 3.1415926535897932384626433832795 ; + int i; + if (oglRoughlyEqual(GetRotation(), 0.0)) + { + i = logicalAttachment; + } + else if (oglRoughlyEqual(GetRotation(), (pi/2.0))) + { + i = logicalAttachment + 1; + } + else if (oglRoughlyEqual(GetRotation(), pi)) + { + i = logicalAttachment + 2; + } + else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0))) + { + i = logicalAttachment + 3; + } + else + // Can't handle -- assume the same. + return logicalAttachment; + + if (i > 3) + i -= 4; + + return i; +} + +void wxShape::Rotate(double WXUNUSED(x), double WXUNUSED(y), double theta) +{ + const double pi = 3.1415926535897932384626433832795 ; + m_rotation = theta; + if (m_rotation < 0.0) + { + m_rotation += 2*pi; + } + else if (m_rotation > 2*pi) + { + m_rotation -= 2*pi; + } +} + diff --git a/src/ogl/basic2.cpp b/src/ogl/basic2.cpp new file mode 100644 index 0000000000..7a65d7097c --- /dev/null +++ b/src/ogl/basic2.cpp @@ -0,0 +1,1902 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: basic2.cpp +// Purpose: Basic OGL classes (2) +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "basicp.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#if wxUSE_IOSTREAMH +#include +#else +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// Control point types +// Rectangle and most other shapes +#define CONTROL_POINT_VERTICAL 1 +#define CONTROL_POINT_HORIZONTAL 2 +#define CONTROL_POINT_DIAGONAL 3 + +// Line +#define CONTROL_POINT_ENDPOINT_TO 4 +#define CONTROL_POINT_ENDPOINT_FROM 5 +#define CONTROL_POINT_LINE 6 + +// Two stage construction: need to call Create +IMPLEMENT_DYNAMIC_CLASS(wxPolygonShape, wxShape) + +wxPolygonShape::wxPolygonShape() +{ + m_points = NULL; + m_originalPoints = NULL; +} + +void wxPolygonShape::Create(wxList *the_points) +{ + ClearPoints(); + + m_originalPoints = the_points; + + // Duplicate the list of points + m_points = new wxList; + + wxNode *node = the_points->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxRealPoint *new_point = new wxRealPoint(point->x, point->y); + m_points->Append((wxObject*) new_point); + node = node->Next(); + } + CalculateBoundingBox(); + m_originalWidth = m_boundWidth; + m_originalHeight = m_boundHeight; + SetDefaultRegionSize(); +} + +wxPolygonShape::~wxPolygonShape() +{ + ClearPoints(); +} + +void wxPolygonShape::ClearPoints() +{ + if (m_points) + { + wxNode *node = m_points->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + delete point; + delete node; + node = m_points->First(); + } + delete m_points; + m_points = NULL; + } + if (m_originalPoints) + { + wxNode *node = m_originalPoints->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + delete point; + delete node; + node = m_originalPoints->First(); + } + delete m_originalPoints; + m_originalPoints = NULL; + } +} + + +// Width and height. Centre of object is centre of box. +void wxPolygonShape::GetBoundingBoxMin(double *width, double *height) +{ + *width = m_boundWidth; + *height = m_boundHeight; +} + +void wxPolygonShape::CalculateBoundingBox() +{ + // Calculate bounding box at construction (and presumably resize) time + double left = 10000; + double right = -10000; + double top = 10000; + double bottom = -10000; + + wxNode *node = m_points->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + if (point->x < left) left = point->x; + if (point->x > right) right = point->x; + + if (point->y < top) top = point->y; + if (point->y > bottom) bottom = point->y; + + node = node->Next(); + } + m_boundWidth = right - left; + m_boundHeight = bottom - top; +} + +// Recalculates the centre of the polygon, and +// readjusts the point offsets accordingly. +// Necessary since the centre of the polygon +// is expected to be the real centre of the bounding +// box. +void wxPolygonShape::CalculatePolygonCentre() +{ + double left = 10000; + double right = -10000; + double top = 10000; + double bottom = -10000; + + wxNode *node = m_points->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + if (point->x < left) left = point->x; + if (point->x > right) right = point->x; + + if (point->y < top) top = point->y; + if (point->y > bottom) bottom = point->y; + + node = node->Next(); + } + double bwidth = right - left; + double bheight = bottom - top; + + double newCentreX = (double)(left + (bwidth/2.0)); + double newCentreY = (double)(top + (bheight/2.0)); + + node = m_points->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + point->x -= newCentreX; + point->y -= newCentreY; + node = node->Next(); + } + m_xpos += newCentreX; + m_ypos += newCentreY; +} + +bool PolylineHitTest(double n, double xvec[], double yvec[], + double x1, double y1, double x2, double y2) +{ + bool isAHit = FALSE; + int i; + double lastx = xvec[0]; + double lasty = yvec[0]; + + double min_ratio = 1.0; + double line_ratio; + double other_ratio; + +// char buf[300]; + for (i = 1; i < n; i++) + { + oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[i], yvec[i], + &line_ratio, &other_ratio); + if (line_ratio != 1.0) + isAHit = TRUE; +// sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio); +// ClipsErrorFunction(buf); + lastx = xvec[i]; + lasty = yvec[i]; + + if (line_ratio < min_ratio) + min_ratio = line_ratio; + } + + // Do last (implicit) line if last and first doubles are not identical + if (!(xvec[0] == lastx && yvec[0] == lasty)) + { + oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[0], yvec[0], + &line_ratio, &other_ratio); + if (line_ratio != 1.0) + isAHit = TRUE; +// sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio); +// ClipsErrorFunction(buf); + + if (line_ratio < min_ratio) + min_ratio = line_ratio; + } +// ClipsErrorFunction("\n"); + return isAHit; +} + +bool wxPolygonShape::HitTest(double x, double y, int *attachment, double *distance) +{ + // Imagine four lines radiating from this point. If all of these lines hit the polygon, + // we're inside it, otherwise we're not. Obviously we'd need more radiating lines + // to be sure of correct results for very strange (concave) shapes. + double endPointsX[4]; + double endPointsY[4]; + // North + endPointsX[0] = x; + endPointsY[0] = (double)(y - 1000.0); + // East + endPointsX[1] = (double)(x + 1000.0); + endPointsY[1] = y; + // South + endPointsX[2] = x; + endPointsY[2] = (double)(y + 1000.0); + // West + endPointsX[3] = (double)(x - 1000.0); + endPointsY[3] = y; + + // Store polygon points in an array + int np = m_points->Number(); + double *xpoints = new double[np]; + double *ypoints = new double[np]; + wxNode *node = m_points->First(); + int i = 0; + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + xpoints[i] = point->x + m_xpos; + ypoints[i] = point->y + m_ypos; + node = node->Next(); + i ++; + } + + // We assume it's inside the polygon UNLESS one or more + // lines don't hit the outline. + bool isContained = TRUE; + + int noPoints = 4; + for (i = 0; i < noPoints; i++) + { + if (!PolylineHitTest(np, xpoints, ypoints, x, y, endPointsX[i], endPointsY[i])) + isContained = FALSE; + } +/* + if (isContained) + ClipsErrorFunction("It's a hit!\n"); + else + ClipsErrorFunction("No hit.\n"); +*/ + delete[] xpoints; + delete[] ypoints; + + if (!isContained) + return FALSE; + + int nearest_attachment = 0; + + // If a hit, check the attachment points within the object. + int n = GetNumberOfAttachments(); + double nearest = 999999.0; + + for (i = 0; i < n; i++) + { + double xp, yp; + if (GetAttachmentPositionEdge(i, &xp, &yp)) + { + double l = (double)sqrt(((xp - x) * (xp - x)) + + ((yp - y) * (yp - y))); + if (l < nearest) + { + nearest = l; + nearest_attachment = i; + } + } + } + *attachment = nearest_attachment; + *distance = nearest; + return TRUE; +} + +// Really need to be able to reset the shape! Otherwise, if the +// points ever go to zero, we've lost it, and can't resize. +void wxPolygonShape::SetSize(double new_width, double new_height, bool recursive) +{ + SetAttachmentSize(new_width, new_height); + + // Multiply all points by proportion of new size to old size + double x_proportion = (double)(fabs(new_width/m_originalWidth)); + double y_proportion = (double)(fabs(new_height/m_originalHeight)); + + wxNode *node = m_points->First(); + wxNode *original_node = m_originalPoints->First(); + while (node && original_node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxRealPoint *original_point = (wxRealPoint *)original_node->Data(); + + point->x = (original_point->x * x_proportion); + point->y = (original_point->y * y_proportion); + + node = node->Next(); + original_node = original_node->Next(); + } + +// CalculateBoundingBox(); + m_boundWidth = (double)fabs(new_width); + m_boundHeight = (double)fabs(new_height); + SetDefaultRegionSize(); +} + +// Make the original points the same as the working points +void wxPolygonShape::UpdateOriginalPoints() +{ + if (!m_originalPoints) m_originalPoints = new wxList; + wxNode *original_node = m_originalPoints->First(); + while (original_node) + { + wxNode *next_node = original_node->Next(); + wxRealPoint *original_point = (wxRealPoint *)original_node->Data(); + delete original_point; + delete original_node; + + original_node = next_node; + } + + wxNode *node = m_points->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxRealPoint *original_point = new wxRealPoint(point->x, point->y); + m_originalPoints->Append((wxObject*) original_point); + + node = node->Next(); + } + CalculateBoundingBox(); + m_originalWidth = m_boundWidth; + m_originalHeight = m_boundHeight; +} + +void wxPolygonShape::AddPolygonPoint(int pos) +{ + wxNode *node = m_points->Nth(pos); + if (!node) node = m_points->First(); + wxRealPoint *firstPoint = (wxRealPoint *)node->Data(); + + wxNode *node2 = m_points->Nth(pos + 1); + if (!node2) node2 = m_points->First(); + wxRealPoint *secondPoint = (wxRealPoint *)node2->Data(); + + double x = (double)((secondPoint->x - firstPoint->x)/2.0 + firstPoint->x); + double y = (double)((secondPoint->y - firstPoint->y)/2.0 + firstPoint->y); + wxRealPoint *point = new wxRealPoint(x, y); + + if (pos >= (m_points->Number() - 1)) + m_points->Append((wxObject*) point); + else + m_points->Insert(node2, (wxObject*) point); + + UpdateOriginalPoints(); + + if (m_selected) + { + DeleteControlPoints(); + MakeControlPoints(); + } +} + +void wxPolygonShape::DeletePolygonPoint(int pos) +{ + wxNode *node = m_points->Nth(pos); + if (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + delete point; + delete node; + UpdateOriginalPoints(); + if (m_selected) + { + DeleteControlPoints(); + MakeControlPoints(); + } + } +} + +// Assume (x1, y1) is centre of box (most generally, line end at box) +bool wxPolygonShape::GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3) +{ + int n = m_points->Number(); + + // First check for situation where the line is vertical, + // and we would want to connect to a point on that vertical -- + // oglFindEndForPolyline can't cope with this (the arrow + // gets drawn to the wrong place). + if ((m_attachmentMode == ATTACHMENT_MODE_NONE) && (x1 == x2)) + { + // Look for the point we'd be connecting to. This is + // a heuristic... + wxNode *node = m_points->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + if (point->x == 0.0) + { + if ((y2 > y1) && (point->y > 0.0)) + { + *x3 = point->x + m_xpos; + *y3 = point->y + m_ypos; + return TRUE; + } + else if ((y2 < y1) && (point->y < 0.0)) + { + *x3 = point->x + m_xpos; + *y3 = point->y + m_ypos; + return TRUE; + } + } + node = node->Next(); + } + } + + double *xpoints = new double[n]; + double *ypoints = new double[n]; + + wxNode *node = m_points->First(); + int i = 0; + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + xpoints[i] = point->x + m_xpos; + ypoints[i] = point->y + m_ypos; + node = node->Next(); + i ++; + } + + oglFindEndForPolyline(n, xpoints, ypoints, + x1, y1, x2, y2, x3, y3); + + delete[] xpoints; + delete[] ypoints; + + return TRUE; +} + +void wxPolygonShape::OnDraw(wxDC& dc) +{ + int n = m_points->Number(); + wxPoint *intPoints = new wxPoint[n]; + int i; + for (i = 0; i < n; i++) + { + wxRealPoint* point = (wxRealPoint*) m_points->Nth(i)->Data(); + intPoints[i].x = WXROUND(point->x); + intPoints[i].y = WXROUND(point->y); + } + + if (m_shadowMode != SHADOW_NONE) + { + if (m_shadowBrush) + dc.SetBrush(* m_shadowBrush); + dc.SetPen(* g_oglTransparentPen); + + dc.DrawPolygon(n, intPoints, WXROUND(m_xpos + m_shadowOffsetX), WXROUND(m_ypos + m_shadowOffsetY)); + } + + if (m_pen) + { + if (m_pen->GetWidth() == 0) + dc.SetPen(* g_oglTransparentPen); + else + dc.SetPen(* m_pen); + } + if (m_brush) + dc.SetBrush(* m_brush); + dc.DrawPolygon(n, intPoints, WXROUND(m_xpos), WXROUND(m_ypos)); + + delete[] intPoints; +} + +void wxPolygonShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h) +{ + dc.SetBrush(* wxTRANSPARENT_BRUSH); + // Multiply all points by proportion of new size to old size + double x_proportion = (double)(fabs(w/m_originalWidth)); + double y_proportion = (double)(fabs(h/m_originalHeight)); + + int n = m_originalPoints->Number(); + wxPoint *intPoints = new wxPoint[n]; + int i; + for (i = 0; i < n; i++) + { + wxRealPoint* point = (wxRealPoint*) m_originalPoints->Nth(i)->Data(); + intPoints[i].x = WXROUND(x_proportion * point->x); + intPoints[i].y = WXROUND(y_proportion * point->y); + } + dc.DrawPolygon(n, intPoints, WXROUND(x), WXROUND(y)); + delete[] intPoints; +} + +// Make as many control points as there are vertices. +void wxPolygonShape::MakeControlPoints() +{ + wxNode *node = m_points->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxPolygonControlPoint *control = new wxPolygonControlPoint(m_canvas, this, CONTROL_POINT_SIZE, + point, point->x, point->y); + m_canvas->AddShape(control); + m_controlPoints.Append(control); + node = node->Next(); + } +} + +void wxPolygonShape::ResetControlPoints() +{ + wxNode *node = m_points->First(); + wxNode *controlPointNode = m_controlPoints.First(); + while (node && controlPointNode) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxPolygonControlPoint *controlPoint = (wxPolygonControlPoint *)controlPointNode->Data(); + + controlPoint->m_xoffset = point->x; + controlPoint->m_yoffset = point->y; + controlPoint->m_polygonVertex = point; + + node = node->Next(); + controlPointNode = controlPointNode->Next(); + } +} + + +#ifdef PROLOGIO +void wxPolygonShape::WriteAttributes(wxExpr *clause) +{ + wxShape::WriteAttributes(clause); + + clause->AddAttributeValue("x", m_xpos); + clause->AddAttributeValue("y", m_ypos); + + // Make a list of lists for the coordinates + wxExpr *list = new wxExpr(wxExprList); + wxNode *node = m_points->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxExpr *point_list = new wxExpr(wxExprList); + wxExpr *x_expr = new wxExpr((double)point->x); + wxExpr *y_expr = new wxExpr((double)point->y); + + point_list->Append(x_expr); + point_list->Append(y_expr); + list->Append(point_list); + + node = node->Next(); + } + clause->AddAttributeValue("points", list); + + // Save the original (unscaled) points + list = new wxExpr(wxExprList); + node = m_originalPoints->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxExpr *point_list = new wxExpr(wxExprList); + wxExpr *x_expr = new wxExpr((double) point->x); + wxExpr *y_expr = new wxExpr((double) point->y); + point_list->Append(x_expr); + point_list->Append(y_expr); + list->Append(point_list); + + node = node->Next(); + } + clause->AddAttributeValue("m_originalPoints", list); +} + +void wxPolygonShape::ReadAttributes(wxExpr *clause) +{ + wxShape::ReadAttributes(clause); + + // Read a list of lists + m_points = new wxList; + m_originalPoints = new wxList; + + wxExpr *points_list = NULL; + clause->AssignAttributeValue("points", &points_list); + + // If no points_list, don't crash!! Assume a diamond instead. + double the_height = 100.0; + double the_width = 100.0; + if (!points_list) + { + wxRealPoint *point = new wxRealPoint(0.0, (-the_height/2)); + m_points->Append((wxObject*) point); + + point = new wxRealPoint((the_width/2), 0.0); + m_points->Append((wxObject*) point); + + point = new wxRealPoint(0.0, (the_height/2)); + m_points->Append((wxObject*) point); + + point = new wxRealPoint((-the_width/2), 0.0); + m_points->Append((wxObject*) point); + + point = new wxRealPoint(0.0, (-the_height/2)); + m_points->Append((wxObject*) point); + } + else + { + wxExpr *node = points_list->value.first; + + while (node) + { + wxExpr *xexpr = node->value.first; + long x = xexpr->IntegerValue(); + + wxExpr *yexpr = xexpr->next; + long y = yexpr->IntegerValue(); + + wxRealPoint *point = new wxRealPoint((double)x, (double)y); + m_points->Append((wxObject*) point); + + node = node->next; + } + } + + points_list = NULL; + clause->AssignAttributeValue("m_originalPoints", &points_list); + + // If no points_list, don't crash!! Assume a diamond instead. + if (!points_list) + { + wxRealPoint *point = new wxRealPoint(0.0, (-the_height/2)); + m_originalPoints->Append((wxObject*) point); + + point = new wxRealPoint((the_width/2), 0.0); + m_originalPoints->Append((wxObject*) point); + + point = new wxRealPoint(0.0, (the_height/2)); + m_originalPoints->Append((wxObject*) point); + + point = new wxRealPoint((-the_width/2), 0.0); + m_originalPoints->Append((wxObject*) point); + + point = new wxRealPoint(0.0, (-the_height/2)); + m_originalPoints->Append((wxObject*) point); + + m_originalWidth = the_width; + m_originalHeight = the_height; + } + else + { + wxExpr *node = points_list->value.first; + double min_x = 1000; + double min_y = 1000; + double max_x = -1000; + double max_y = -1000; + while (node) + { + wxExpr *xexpr = node->value.first; + long x = xexpr->IntegerValue(); + + wxExpr *yexpr = xexpr->next; + long y = yexpr->IntegerValue(); + + wxRealPoint *point = new wxRealPoint((double)x, (double)y); + m_originalPoints->Append((wxObject*) point); + + if (x < min_x) + min_x = (double)x; + if (y < min_y) + min_y = (double)y; + if (x > max_x) + max_x = (double)x; + if (y > max_y) + max_y = (double)y; + + node = node->next; + } + m_originalWidth = max_x - min_x; + m_originalHeight = max_y - min_y; + } + + CalculateBoundingBox(); +} +#endif + +void wxPolygonShape::Copy(wxShape& copy) +{ + wxShape::Copy(copy); + + wxASSERT( copy.IsKindOf(CLASSINFO(wxPolygonShape)) ); + + wxPolygonShape& polyCopy = (wxPolygonShape&) copy; + + polyCopy.ClearPoints(); + + polyCopy.m_points = new wxList; + polyCopy.m_originalPoints = new wxList; + + wxNode *node = m_points->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxRealPoint *new_point = new wxRealPoint(point->x, point->y); + polyCopy.m_points->Append((wxObject*) new_point); + node = node->Next(); + } + node = m_originalPoints->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxRealPoint *new_point = new wxRealPoint(point->x, point->y); + polyCopy.m_originalPoints->Append((wxObject*) new_point); + node = node->Next(); + } + polyCopy.m_boundWidth = m_boundWidth; + polyCopy.m_boundHeight = m_boundHeight; + polyCopy.m_originalWidth = m_originalWidth; + polyCopy.m_originalHeight = m_originalHeight; +} + +int wxPolygonShape::GetNumberOfAttachments() const +{ + int maxN = (m_points ? (m_points->Number() - 1) : 0); + wxNode *node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + if (point->m_id > maxN) + maxN = point->m_id; + node = node->Next(); + } + return maxN+1;; +} + +bool wxPolygonShape::GetAttachmentPosition(int attachment, double *x, double *y, + int nth, int no_arcs, wxLineShape *line) +{ + if ((m_attachmentMode == ATTACHMENT_MODE_EDGE) && m_points && attachment < m_points->Number()) + { + wxRealPoint *point = (wxRealPoint *)m_points->Nth(attachment)->Data(); + *x = point->x + m_xpos; + *y = point->y + m_ypos; + return TRUE; + } + else + { return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line); } +} + +bool wxPolygonShape::AttachmentIsValid(int attachment) +{ + if (!m_points) + return FALSE; + + if ((attachment >= 0) && (attachment < m_points->Number())) + return TRUE; + + wxNode *node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + if (point->m_id == attachment) + return TRUE; + node = node->Next(); + } + return FALSE; +} + +// Rotate about the given axis by the given amount in radians +void wxPolygonShape::Rotate(double x, double y, double theta) +{ + double actualTheta = theta-m_rotation; + + // Rotate attachment points + double sinTheta = (double)sin(actualTheta); + double cosTheta = (double)cos(actualTheta); + wxNode *node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + double x1 = point->m_x; + double y1 = point->m_y; + point->m_x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta; + point->m_y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta; + node = node->Next(); + } + + node = m_points->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + double x1 = point->x; + double y1 = point->y; + point->x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta; + point->y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta; + node = node->Next(); + } + node = m_originalPoints->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + double x1 = point->x; + double y1 = point->y; + point->x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta; + point->y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta; + node = node->Next(); + } + + m_rotation = theta; + + CalculatePolygonCentre(); + CalculateBoundingBox(); + ResetControlPoints(); +} + +// Rectangle object + +IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape, wxShape) + +wxRectangleShape::wxRectangleShape(double w, double h) +{ + m_width = w; m_height = h; m_cornerRadius = 0.0; + SetDefaultRegionSize(); +} + +void wxRectangleShape::OnDraw(wxDC& dc) +{ + double x1 = (double)(m_xpos - m_width/2.0); + double y1 = (double)(m_ypos - m_height/2.0); + + if (m_shadowMode != SHADOW_NONE) + { + if (m_shadowBrush) + dc.SetBrush(* m_shadowBrush); + dc.SetPen(* g_oglTransparentPen); + + if (m_cornerRadius != 0.0) + dc.DrawRoundedRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY), + WXROUND(m_width), WXROUND(m_height), m_cornerRadius); + else + dc.DrawRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY), WXROUND(m_width), WXROUND(m_height)); + } + + if (m_pen) + { + if (m_pen->GetWidth() == 0) + dc.SetPen(* g_oglTransparentPen); + else + dc.SetPen(* m_pen); + } + if (m_brush) + dc.SetBrush(* m_brush); + + if (m_cornerRadius != 0.0) + dc.DrawRoundedRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height), m_cornerRadius); + else + dc.DrawRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height)); +} + +void wxRectangleShape::GetBoundingBoxMin(double *the_width, double *the_height) +{ + *the_width = m_width; + *the_height = m_height; +} + +void wxRectangleShape::SetSize(double x, double y, bool recursive) +{ + SetAttachmentSize(x, y); + m_width = (double)wxMax(x, 1.0); + m_height = (double)wxMax(y, 1.0); + SetDefaultRegionSize(); +} + +void wxRectangleShape::SetCornerRadius(double rad) +{ + m_cornerRadius = rad; +} + +// Assume (x1, y1) is centre of box (most generally, line end at box) +bool wxRectangleShape::GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3) +{ + double bound_x, bound_y; + GetBoundingBoxMax(&bound_x, &bound_y); + oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3); + + return TRUE; +} + +#ifdef PROLOGIO +void wxRectangleShape::WriteAttributes(wxExpr *clause) +{ + wxShape::WriteAttributes(clause); + clause->AddAttributeValue("x", m_xpos); + clause->AddAttributeValue("y", m_ypos); + + clause->AddAttributeValue("width", m_width); + clause->AddAttributeValue("height", m_height); + if (m_cornerRadius != 0.0) + clause->AddAttributeValue("corner", m_cornerRadius); +} + +void wxRectangleShape::ReadAttributes(wxExpr *clause) +{ + wxShape::ReadAttributes(clause); + clause->AssignAttributeValue("width", &m_width); + clause->AssignAttributeValue("height", &m_height); + clause->AssignAttributeValue("corner", &m_cornerRadius); + + // In case we're reading an old file, set the region's size + if (m_regions.Number() == 1) + { + wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data(); + region->SetSize(m_width, m_height); + } +} +#endif + +void wxRectangleShape::Copy(wxShape& copy) +{ + wxShape::Copy(copy); + + wxASSERT( copy.IsKindOf(CLASSINFO(wxRectangleShape)) ); + + wxRectangleShape& rectCopy = (wxRectangleShape&) copy; + rectCopy.m_width = m_width; + rectCopy.m_height = m_height; + rectCopy.m_cornerRadius = m_cornerRadius; +} + +int wxRectangleShape::GetNumberOfAttachments() const +{ + return wxShape::GetNumberOfAttachments(); +} + + +// There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom, +// 3 = left. +bool wxRectangleShape::GetAttachmentPosition(int attachment, double *x, double *y, + int nth, int no_arcs, wxLineShape *line) +{ + return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line); +} + +// Text object (no box) + +IMPLEMENT_DYNAMIC_CLASS(wxTextShape, wxRectangleShape) + +wxTextShape::wxTextShape(double width, double height): + wxRectangleShape(width, height) +{ +} + +void wxTextShape::OnDraw(wxDC& dc) +{ +} + +void wxTextShape::Copy(wxShape& copy) +{ + wxRectangleShape::Copy(copy); +} + +#ifdef PROLOGIO +void wxTextShape::WriteAttributes(wxExpr *clause) +{ + wxRectangleShape::WriteAttributes(clause); +} +#endif + +// Ellipse object + +IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape, wxShape) + +wxEllipseShape::wxEllipseShape(double w, double h) +{ + m_width = w; m_height = h; + SetDefaultRegionSize(); +} + +void wxEllipseShape::GetBoundingBoxMin(double *w, double *h) +{ + *w = m_width; *h = m_height; +} + +bool wxEllipseShape::GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3) +{ + double bound_x, bound_y; + GetBoundingBoxMax(&bound_x, &bound_y); + +// oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3); + oglDrawArcToEllipse(m_xpos, m_ypos, bound_x, bound_y, x2, y2, x1, y1, x3, y3); + + return TRUE; +} + +void wxEllipseShape::OnDraw(wxDC& dc) +{ + if (m_shadowMode != SHADOW_NONE) + { + if (m_shadowBrush) + dc.SetBrush(* m_shadowBrush); + dc.SetPen(* g_oglTransparentPen); + dc.DrawEllipse((long) ((m_xpos - GetWidth()/2) + m_shadowOffsetX), + (long) ((m_ypos - GetHeight()/2) + m_shadowOffsetY), + (long) GetWidth(), (long) GetHeight()); + } + + if (m_pen) + { + if (m_pen->GetWidth() == 0) + dc.SetPen(* g_oglTransparentPen); + else + dc.SetPen(* m_pen); + } + if (m_brush) + dc.SetBrush(* m_brush); + dc.DrawEllipse((long) (m_xpos - GetWidth()/2), (long) (m_ypos - GetHeight()/2), (long) GetWidth(), (long) GetHeight()); +} + +void wxEllipseShape::SetSize(double x, double y, bool recursive) +{ + SetAttachmentSize(x, y); + m_width = x; + m_height = y; + SetDefaultRegionSize(); +} + +#ifdef PROLOGIO +void wxEllipseShape::WriteAttributes(wxExpr *clause) +{ + wxShape::WriteAttributes(clause); + clause->AddAttributeValue("x", m_xpos); + clause->AddAttributeValue("y", m_ypos); + + clause->AddAttributeValue("width", m_width); + clause->AddAttributeValue("height", m_height); +} + +void wxEllipseShape::ReadAttributes(wxExpr *clause) +{ + wxShape::ReadAttributes(clause); + clause->AssignAttributeValue("width", &m_width); + clause->AssignAttributeValue("height", &m_height); + + // In case we're reading an old file, set the region's size + if (m_regions.Number() == 1) + { + wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data(); + region->SetSize(m_width, m_height); + } +} +#endif + +void wxEllipseShape::Copy(wxShape& copy) +{ + wxShape::Copy(copy); + + wxASSERT( copy.IsKindOf(CLASSINFO(wxEllipseShape)) ); + + wxEllipseShape& ellipseCopy = (wxEllipseShape&) copy; + + ellipseCopy.m_width = m_width; + ellipseCopy.m_height = m_height; +} + +int wxEllipseShape::GetNumberOfAttachments() const +{ + return wxShape::GetNumberOfAttachments(); +} + +// There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom, +// 3 = left. +bool wxEllipseShape::GetAttachmentPosition(int attachment, double *x, double *y, + int nth, int no_arcs, wxLineShape *line) +{ + if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING) + return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line); + + if (m_attachmentMode != ATTACHMENT_MODE_NONE) + { + double top = (double)(m_ypos + m_height/2.0); + double bottom = (double)(m_ypos - m_height/2.0); + double left = (double)(m_xpos - m_width/2.0); + double right = (double)(m_xpos + m_width/2.0); + + int physicalAttachment = LogicalToPhysicalAttachment(attachment); + + switch (physicalAttachment) + { + case 0: + { + if (m_spaceAttachments) + *x = left + (nth + 1)*m_width/(no_arcs + 1); + else *x = m_xpos; + *y = top; + // We now have the point on the bounding box: but get the point on the ellipse + // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting + // the ellipse. + oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, *x, (double)(m_ypos-m_height-500), *x, m_ypos, x, y); + break; + } + case 1: + { + *x = right; + if (m_spaceAttachments) + *y = bottom + (nth + 1)*m_height/(no_arcs + 1); + else *y = m_ypos; + oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, (double)(m_xpos+m_width+500), *y, m_xpos, *y, x, y); + break; + } + case 2: + { + if (m_spaceAttachments) + *x = left + (nth + 1)*m_width/(no_arcs + 1); + else *x = m_xpos; + *y = bottom; + oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, *x, (double)(m_ypos+m_height+500), *x, m_ypos, x, y); + break; + } + case 3: + { + *x = left; + if (m_spaceAttachments) + *y = bottom + (nth + 1)*m_height/(no_arcs + 1); + else *y = m_ypos; + oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, (double)(m_xpos-m_width-500), *y, m_xpos, *y, x, y); + break; + } + default: + { + return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line); + break; + } + } + return TRUE; + } + else + { *x = m_xpos; *y = m_ypos; return TRUE; } +} + + +// Circle object +IMPLEMENT_DYNAMIC_CLASS(wxCircleShape, wxEllipseShape) + +wxCircleShape::wxCircleShape(double diameter):wxEllipseShape(diameter, diameter) +{ + SetMaintainAspectRatio(TRUE); +} + +void wxCircleShape::Copy(wxShape& copy) +{ + wxEllipseShape::Copy(copy); +} + +bool wxCircleShape::GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3) +{ + oglFindEndForCircle(m_width/2, + m_xpos, m_ypos, // Centre of circle + x2, y2, // Other end of line + x3, y3); + + return TRUE; +} + +// Control points + +double wxControlPoint::sm_controlPointDragStartX = 0.0; +double wxControlPoint::sm_controlPointDragStartY = 0.0; +double wxControlPoint::sm_controlPointDragStartWidth = 0.0; +double wxControlPoint::sm_controlPointDragStartHeight = 0.0; +double wxControlPoint::sm_controlPointDragEndWidth = 0.0; +double wxControlPoint::sm_controlPointDragEndHeight = 0.0; +double wxControlPoint::sm_controlPointDragPosX = 0.0; +double wxControlPoint::sm_controlPointDragPosY = 0.0; + +IMPLEMENT_DYNAMIC_CLASS(wxControlPoint, wxRectangleShape) + +wxControlPoint::wxControlPoint(wxShapeCanvas *theCanvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type):wxRectangleShape(size, size) +{ + m_canvas = theCanvas; + m_shape = object; + m_xoffset = the_xoffset; + m_yoffset = the_yoffset; + m_type = the_type; + SetPen(g_oglBlackForegroundPen); + SetBrush(wxBLACK_BRUSH); + m_oldCursor = NULL; + m_visible = TRUE; + m_eraseObject = TRUE; +} + +wxControlPoint::~wxControlPoint() +{ +} + +// Don't even attempt to draw any text - waste of time! +void wxControlPoint::OnDrawContents(wxDC& dc) +{ +} + +void wxControlPoint::OnDraw(wxDC& dc) +{ + m_xpos = m_shape->GetX() + m_xoffset; + m_ypos = m_shape->GetY() + m_yoffset; + wxRectangleShape::OnDraw(dc); +} + +void wxControlPoint::OnErase(wxDC& dc) +{ + wxRectangleShape::OnErase(dc); +} + +// Implement resizing of canvas object +void wxControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment) +{ + m_shape->GetEventHandler()->OnSizingDragLeft(this, draw, x, y, keys, attachment); +} + +void wxControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment) +{ + m_shape->GetEventHandler()->OnSizingBeginDragLeft(this, x, y, keys, attachment); +} + +void wxControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment) +{ + m_shape->GetEventHandler()->OnSizingEndDragLeft(this, x, y, keys, attachment); +} + +int wxControlPoint::GetNumberOfAttachments() const +{ + return 1; +} + +bool wxControlPoint::GetAttachmentPosition(int attachment, double *x, double *y, + int nth, int no_arcs, wxLineShape *line) +{ + *x = m_xpos; *y = m_ypos; + return TRUE; +} + +// Control points ('handles') redirect control to the actual shape, to make it easier +// to override sizing behaviour. +void wxShape::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment) +{ + double bound_x; + double bound_y; + this->GetBoundingBoxMin(&bound_x, &bound_y); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + dc.SetLogicalFunction(OGLRBLF); + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetPen(dottedPen); + dc.SetBrush((* wxTRANSPARENT_BRUSH)); + + if (this->GetCentreResize()) + { + // Maintain the same centre point. + double new_width = (double)(2.0*fabs(x - this->GetX())); + double new_height = (double)(2.0*fabs(y - this->GetY())); + + // Constrain sizing according to what control point you're dragging + if (pt->m_type == CONTROL_POINT_HORIZONTAL) + { + if (GetMaintainAspectRatio()) + { + new_height = bound_y*(new_width/bound_x); + } + else + new_height = bound_y; + } + else if (pt->m_type == CONTROL_POINT_VERTICAL) + { + if (GetMaintainAspectRatio()) + { + new_width = bound_x*(new_height/bound_y); + } + else + new_width = bound_x; + } + else if (pt->m_type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT)) + new_height = bound_y*(new_width/bound_x); + + if (this->GetFixedWidth()) + new_width = bound_x; + + if (this->GetFixedHeight()) + new_height = bound_y; + + pt->sm_controlPointDragEndWidth = new_width; + pt->sm_controlPointDragEndHeight = new_height; + + this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(), + new_width, new_height); + } + else + { + // Don't maintain the same centre point! + double newX1 = wxMin(pt->sm_controlPointDragStartX, x); + double newY1 = wxMin(pt->sm_controlPointDragStartY, y); + double newX2 = wxMax(pt->sm_controlPointDragStartX, x); + double newY2 = wxMax(pt->sm_controlPointDragStartY, y); + if (pt->m_type == CONTROL_POINT_HORIZONTAL) + { + newY1 = pt->sm_controlPointDragStartY; + newY2 = newY1 + pt->sm_controlPointDragStartHeight; + } + else if (pt->m_type == CONTROL_POINT_VERTICAL) + { + newX1 = pt->sm_controlPointDragStartX; + newX2 = newX1 + pt->sm_controlPointDragStartWidth; + } + else if (pt->m_type == CONTROL_POINT_DIAGONAL && ((keys & KEY_SHIFT) || GetMaintainAspectRatio())) + { + double newH = (double)((newX2 - newX1)*(pt->sm_controlPointDragStartHeight/pt->sm_controlPointDragStartWidth)); + if (GetY() > pt->sm_controlPointDragStartY) + newY2 = (double)(newY1 + newH); + else + newY1 = (double)(newY2 - newH); + } + double newWidth = (double)(newX2 - newX1); + double newHeight = (double)(newY2 - newY1); + + if (pt->m_type == CONTROL_POINT_VERTICAL && GetMaintainAspectRatio()) + { + newWidth = bound_x * (newHeight/bound_y) ; + } + + if (pt->m_type == CONTROL_POINT_HORIZONTAL && GetMaintainAspectRatio()) + { + newHeight = bound_y * (newWidth/bound_x) ; + } + + pt->sm_controlPointDragPosX = (double)(newX1 + (newWidth/2.0)); + pt->sm_controlPointDragPosY = (double)(newY1 + (newHeight/2.0)); + if (this->GetFixedWidth()) + newWidth = bound_x; + + if (this->GetFixedHeight()) + newHeight = bound_y; + + pt->sm_controlPointDragEndWidth = newWidth; + pt->sm_controlPointDragEndHeight = newHeight; + this->GetEventHandler()->OnDrawOutline(dc, pt->sm_controlPointDragPosX, pt->sm_controlPointDragPosY, newWidth, newHeight); + } +} + +void wxShape::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment) +{ + m_canvas->CaptureMouse(); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); +/* + if (pt->m_eraseObject) + this->Erase(dc); +*/ + + dc.SetLogicalFunction(OGLRBLF); + + double bound_x; + double bound_y; + this->GetBoundingBoxMin(&bound_x, &bound_y); + + // Choose the 'opposite corner' of the object as the stationary + // point in case this is non-centring resizing. + if (pt->GetX() < this->GetX()) + pt->sm_controlPointDragStartX = (double)(this->GetX() + (bound_x/2.0)); + else + pt->sm_controlPointDragStartX = (double)(this->GetX() - (bound_x/2.0)); + + if (pt->GetY() < this->GetY()) + pt->sm_controlPointDragStartY = (double)(this->GetY() + (bound_y/2.0)); + else + pt->sm_controlPointDragStartY = (double)(this->GetY() - (bound_y/2.0)); + + if (pt->m_type == CONTROL_POINT_HORIZONTAL) + pt->sm_controlPointDragStartY = (double)(this->GetY() - (bound_y/2.0)); + else if (pt->m_type == CONTROL_POINT_VERTICAL) + pt->sm_controlPointDragStartX = (double)(this->GetX() - (bound_x/2.0)); + + // We may require the old width and height. + pt->sm_controlPointDragStartWidth = bound_x; + pt->sm_controlPointDragStartHeight = bound_y; + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetPen(dottedPen); + dc.SetBrush((* wxTRANSPARENT_BRUSH)); + + if (this->GetCentreResize()) + { + double new_width = (double)(2.0*fabs(x - this->GetX())); + double new_height = (double)(2.0*fabs(y - this->GetY())); + + // Constrain sizing according to what control point you're dragging + if (pt->m_type == CONTROL_POINT_HORIZONTAL) + { + if (GetMaintainAspectRatio()) + { + new_height = bound_y*(new_width/bound_x); + } + else + new_height = bound_y; + } + else if (pt->m_type == CONTROL_POINT_VERTICAL) + { + if (GetMaintainAspectRatio()) + { + new_width = bound_x*(new_height/bound_y); + } + else + new_width = bound_x; + } + else if (pt->m_type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT)) + new_height = bound_y*(new_width/bound_x); + + if (this->GetFixedWidth()) + new_width = bound_x; + + if (this->GetFixedHeight()) + new_height = bound_y; + + pt->sm_controlPointDragEndWidth = new_width; + pt->sm_controlPointDragEndHeight = new_height; + this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(), + new_width, new_height); + } + else + { + // Don't maintain the same centre point! + double newX1 = wxMin(pt->sm_controlPointDragStartX, x); + double newY1 = wxMin(pt->sm_controlPointDragStartY, y); + double newX2 = wxMax(pt->sm_controlPointDragStartX, x); + double newY2 = wxMax(pt->sm_controlPointDragStartY, y); + if (pt->m_type == CONTROL_POINT_HORIZONTAL) + { + newY1 = pt->sm_controlPointDragStartY; + newY2 = newY1 + pt->sm_controlPointDragStartHeight; + } + else if (pt->m_type == CONTROL_POINT_VERTICAL) + { + newX1 = pt->sm_controlPointDragStartX; + newX2 = newX1 + pt->sm_controlPointDragStartWidth; + } + else if (pt->m_type == CONTROL_POINT_DIAGONAL && ((keys & KEY_SHIFT) || GetMaintainAspectRatio())) + { + double newH = (double)((newX2 - newX1)*(pt->sm_controlPointDragStartHeight/pt->sm_controlPointDragStartWidth)); + if (pt->GetY() > pt->sm_controlPointDragStartY) + newY2 = (double)(newY1 + newH); + else + newY1 = (double)(newY2 - newH); + } + double newWidth = (double)(newX2 - newX1); + double newHeight = (double)(newY2 - newY1); + + if (pt->m_type == CONTROL_POINT_VERTICAL && GetMaintainAspectRatio()) + { + newWidth = bound_x * (newHeight/bound_y) ; + } + + if (pt->m_type == CONTROL_POINT_HORIZONTAL && GetMaintainAspectRatio()) + { + newHeight = bound_y * (newWidth/bound_x) ; + } + + pt->sm_controlPointDragPosX = (double)(newX1 + (newWidth/2.0)); + pt->sm_controlPointDragPosY = (double)(newY1 + (newHeight/2.0)); + if (this->GetFixedWidth()) + newWidth = bound_x; + + if (this->GetFixedHeight()) + newHeight = bound_y; + + pt->sm_controlPointDragEndWidth = newWidth; + pt->sm_controlPointDragEndHeight = newHeight; + this->GetEventHandler()->OnDrawOutline(dc, pt->sm_controlPointDragPosX, pt->sm_controlPointDragPosY, newWidth, newHeight); + } +} + +void wxShape::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment) +{ + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + m_canvas->ReleaseMouse(); + dc.SetLogicalFunction(wxCOPY); + this->Recompute(); + this->ResetControlPoints(); + + this->Erase(dc); +/* + if (!pt->m_eraseObject) + this->Show(FALSE); +*/ + + this->SetSize(pt->sm_controlPointDragEndWidth, pt->sm_controlPointDragEndHeight); + + // The next operation could destroy this control point (it does for label objects, + // via formatting the text), so save all values we're going to use, or + // we'll be accessing garbage. + wxShape *theObject = this; + wxShapeCanvas *theCanvas = m_canvas; + bool eraseIt = pt->m_eraseObject; + + if (theObject->GetCentreResize()) + theObject->Move(dc, theObject->GetX(), theObject->GetY()); + else + theObject->Move(dc, pt->sm_controlPointDragPosX, pt->sm_controlPointDragPosY); + +/* + if (!eraseIt) + theObject->Show(TRUE); +*/ + + // Recursively redraw links if we have a composite. + if (theObject->GetChildren().Number() > 0) + theObject->DrawLinks(dc, -1, TRUE); + + double width, height; + theObject->GetBoundingBoxMax(&width, &height); + theObject->GetEventHandler()->OnEndSize(width, height); + + if (!theCanvas->GetQuickEditMode() && eraseIt) theCanvas->Redraw(dc); +} + + + +// Polygon control points + +IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint, wxControlPoint) + +wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas *theCanvas, wxShape *object, double size, + wxRealPoint *vertex, double the_xoffset, double the_yoffset): + wxControlPoint(theCanvas, object, size, the_xoffset, the_yoffset, 0) +{ + m_polygonVertex = vertex; + m_originalDistance = 0.0; +} + +wxPolygonControlPoint::~wxPolygonControlPoint() +{ +} + +// Calculate what new size would be, at end of resize +void wxPolygonControlPoint::CalculateNewSize(double x, double y) +{ + double bound_x; + double bound_y; + GetShape()->GetBoundingBoxMin(&bound_x, &bound_y); + + double dist = (double)sqrt((x - m_shape->GetX())*(x - m_shape->GetX()) + + (y - m_shape->GetY())*(y - m_shape->GetY())); + + m_newSize.x = (double)(dist/this->m_originalDistance)*this->m_originalSize.x; + m_newSize.y = (double)(dist/this->m_originalDistance)*this->m_originalSize.y; +} + + +// Implement resizing polygon or moving the vertex. +void wxPolygonControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment) +{ + m_shape->GetEventHandler()->OnSizingDragLeft(this, draw, x, y, keys, attachment); +} + +void wxPolygonControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment) +{ + m_shape->GetEventHandler()->OnSizingBeginDragLeft(this, x, y, keys, attachment); +} + +void wxPolygonControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment) +{ + m_shape->GetEventHandler()->OnSizingEndDragLeft(this, x, y, keys, attachment); +} + +// Control points ('handles') redirect control to the actual shape, to make it easier +// to override sizing behaviour. +void wxPolygonShape::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment) +{ + wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt; + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + dc.SetLogicalFunction(OGLRBLF); + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetPen(dottedPen); + dc.SetBrush((* wxTRANSPARENT_BRUSH)); + + if (0) // keys & KEY_CTRL) + { + // TODO: mend this code. Currently we rely on altering the + // actual points, but we should assume we're not, as per + // the normal sizing case. + m_canvas->Snap(&x, &y); + + // Move point + ppt->m_polygonVertex->x = x - this->GetX(); + ppt->m_polygonVertex->y = y - this->GetY(); + ppt->SetX(x); + ppt->SetY(y); + ((wxPolygonShape *)this)->CalculateBoundingBox(); + ((wxPolygonShape *)this)->CalculatePolygonCentre(); + } + else + { + ppt->CalculateNewSize(x, y); + } + + this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(), + ppt->GetNewSize().x, ppt->GetNewSize().y); +} + +void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment) +{ + wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt; + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + this->Erase(dc); + + dc.SetLogicalFunction(OGLRBLF); + + double bound_x; + double bound_y; + this->GetBoundingBoxMin(&bound_x, &bound_y); + + double dist = (double)sqrt((x - this->GetX())*(x - this->GetX()) + + (y - this->GetY())*(y - this->GetY())); + ppt->m_originalDistance = dist; + ppt->m_originalSize.x = bound_x; + ppt->m_originalSize.y = bound_y; + + if (ppt->m_originalDistance == 0.0) ppt->m_originalDistance = (double) 0.0001; + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetPen(dottedPen); + dc.SetBrush((* wxTRANSPARENT_BRUSH)); + + if (0) // keys & KEY_CTRL) + { + // TODO: mend this code. Currently we rely on altering the + // actual points, but we should assume we're not, as per + // the normal sizing case. + m_canvas->Snap(&x, &y); + + // Move point + ppt->m_polygonVertex->x = x - this->GetX(); + ppt->m_polygonVertex->y = y - this->GetY(); + ppt->SetX(x); + ppt->SetY(y); + ((wxPolygonShape *)this)->CalculateBoundingBox(); + ((wxPolygonShape *)this)->CalculatePolygonCentre(); + } + else + { + ppt->CalculateNewSize(x, y); + } + + this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(), + ppt->GetNewSize().x, ppt->GetNewSize().y); + + m_canvas->CaptureMouse(); +} + +void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment) +{ + wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt; + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + m_canvas->ReleaseMouse(); + dc.SetLogicalFunction(wxCOPY); + + // If we're changing shape, must reset the original points + if (keys & KEY_CTRL) + { + ((wxPolygonShape *)this)->CalculateBoundingBox(); + ((wxPolygonShape *)this)->UpdateOriginalPoints(); + } + else + { + SetSize(ppt->GetNewSize().x, ppt->GetNewSize().y); + } + + ((wxPolygonShape *)this)->CalculateBoundingBox(); + ((wxPolygonShape *)this)->CalculatePolygonCentre(); + + this->Recompute(); + this->ResetControlPoints(); + this->Move(dc, this->GetX(), this->GetY()); + if (!m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc); +} + +/* + * Object region + * + */ +IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion, wxObject) + +wxShapeRegion::wxShapeRegion() +{ + m_regionText = ""; + m_font = g_oglNormalFont; + m_minHeight = 5.0; + m_minWidth = 5.0; + m_width = 0.0; + m_height = 0.0; + m_x = 0.0; + m_y = 0.0; + + m_regionProportionX = -1.0; + m_regionProportionY = -1.0; + m_formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT; + m_regionName = ""; + m_textColour = "BLACK"; + m_penColour = "BLACK"; + m_penStyle = wxSOLID; + m_actualColourObject = NULL; + m_actualPenObject = NULL; +} + +wxShapeRegion::wxShapeRegion(wxShapeRegion& region) +{ + m_regionText = region.m_regionText; + m_regionName = region.m_regionName; + m_textColour = region.m_textColour; + + m_font = region.m_font; + m_minHeight = region.m_minHeight; + m_minWidth = region.m_minWidth; + m_width = region.m_width; + m_height = region.m_height; + m_x = region.m_x; + m_y = region.m_y; + + m_regionProportionX = region.m_regionProportionX; + m_regionProportionY = region.m_regionProportionY; + m_formatMode = region.m_formatMode; + m_actualColourObject = NULL; + m_actualPenObject = NULL; + m_penStyle = region.m_penStyle; + m_penColour = region.m_penColour; + + ClearText(); + wxNode *node = region.m_formattedText.First(); + while (node) + { + wxShapeTextLine *line = (wxShapeTextLine *)node->Data(); + wxShapeTextLine *new_line = + new wxShapeTextLine(line->GetX(), line->GetY(), line->GetText()); + m_formattedText.Append(new_line); + node = node->Next(); + } +} + +wxShapeRegion::~wxShapeRegion() +{ + ClearText(); +} + +void wxShapeRegion::ClearText() +{ + wxNode *node = m_formattedText.First(); + while (node) + { + wxShapeTextLine *line = (wxShapeTextLine *)node->Data(); + wxNode *next = node->Next(); + delete line; + delete node; + node = next; + } +} + +void wxShapeRegion::SetFont(wxFont *f) +{ + m_font = f; +} + +void wxShapeRegion::SetMinSize(double w, double h) +{ + m_minWidth = w; + m_minHeight = h; +} + +void wxShapeRegion::SetSize(double w, double h) +{ + m_width = w; + m_height = h; +} + +void wxShapeRegion::SetPosition(double xp, double yp) +{ + m_x = xp; + m_y = yp; +} + +void wxShapeRegion::SetProportions(double xp, double yp) +{ + m_regionProportionX = xp; + m_regionProportionY = yp; +} + +void wxShapeRegion::SetFormatMode(int mode) +{ + m_formatMode = mode; +} + +void wxShapeRegion::SetColour(const wxString& col) +{ + m_textColour = col; + m_actualColourObject = NULL; +} + +wxColour *wxShapeRegion::GetActualColourObject() +{ + if (!m_actualColourObject) + m_actualColourObject = wxTheColourDatabase->FindColour(GetColour()); + if (!m_actualColourObject) + m_actualColourObject = wxBLACK; + return m_actualColourObject; +} + +void wxShapeRegion::SetPenColour(const wxString& col) +{ + m_penColour = col; + m_actualPenObject = NULL; +} + +// Returns NULL if the pen is invisible +// (different to pen being transparent; indicates that +// region boundary should not be drawn.) +wxPen *wxShapeRegion::GetActualPen() +{ + if (m_actualPenObject) + return m_actualPenObject; + + if (!m_penColour) return NULL; + if (m_penColour == "Invisible") + return NULL; + m_actualPenObject = wxThePenList->FindOrCreatePen(m_penColour, 1, m_penStyle); + return m_actualPenObject; +} + + diff --git a/src/ogl/bmpshape.cpp b/src/ogl/bmpshape.cpp new file mode 100644 index 0000000000..fc6218e234 --- /dev/null +++ b/src/ogl/bmpshape.cpp @@ -0,0 +1,115 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: bmpshape.cpp +// Purpose: Bitmap shape class +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "bmpshape.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#include +#include +#include +#include +#include + +/* + * Bitmap object + * + */ + +IMPLEMENT_DYNAMIC_CLASS(wxBitmapShape, wxShape) + +wxBitmapShape::wxBitmapShape():wxRectangleShape(100.0, 50.0) +{ + m_filename = ""; +} + +wxBitmapShape::~wxBitmapShape() +{ +} + +void wxBitmapShape::OnDraw(wxDC& dc) +{ + if (!m_bitmap.Ok()) + return; + + wxMemoryDC tempDC; + tempDC.SelectObject(m_bitmap); + double x, y; + x = WXROUND(m_xpos - m_bitmap.GetWidth() / 2.0); + y = WXROUND(m_ypos - m_bitmap.GetHeight() / 2.0); + dc.Blit((long) x, (long) y, m_bitmap.GetWidth(), m_bitmap.GetHeight(), &tempDC, 0, 0); +} + +void wxBitmapShape::SetSize(double w, double h, bool recursive) +{ + if (m_bitmap.Ok()) + { + w = m_bitmap.GetWidth(); + h = m_bitmap.GetHeight(); + } + + SetAttachmentSize(w, h); + + m_width = w; + m_height = h; + SetDefaultRegionSize(); +} + +#ifdef PROLOGIO +void wxBitmapShape::WriteAttributes(wxExpr *clause) +{ + // Can't really save the bitmap; so instantiate the bitmap + // at a higher level in the application, from a symbol library. + wxRectangleShape::WriteAttributes(clause); + clause->AddAttributeValueString("filename", m_filename); +} + +void wxBitmapShape::ReadAttributes(wxExpr *clause) +{ + wxRectangleShape::ReadAttributes(clause); + clause->GetAttributeValue("filename", m_filename); +} +#endif + +// Does the copying for this object +void wxBitmapShape::Copy(wxShape& copy) +{ + wxRectangleShape::Copy(copy); + + wxASSERT( copy.IsKindOf(CLASSINFO(wxBitmapShape)) ) ; + + wxBitmapShape& bitmapCopy = (wxBitmapShape&) copy; + + bitmapCopy.m_bitmap = m_bitmap; + bitmapCopy.SetFilename(m_filename); +} + +void wxBitmapShape::SetBitmap(const wxBitmap& bm) +{ + m_bitmap = bm; + if (m_bitmap.Ok()) + SetSize(m_bitmap.GetWidth(), m_bitmap.GetHeight()); +} + + diff --git a/src/ogl/canvas.cpp b/src/ogl/canvas.cpp new file mode 100644 index 0000000000..02bae38143 --- /dev/null +++ b/src/ogl/canvas.cpp @@ -0,0 +1,516 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: canvas.cpp +// Purpose: Shape canvas class +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "canvas.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#if wxUSE_IOSTREAMH +#include +#else +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define CONTROL_POINT_SIZE 6 + +// Control point types +// Rectangle and most other shapes +#define CONTROL_POINT_VERTICAL 1 +#define CONTROL_POINT_HORIZONTAL 2 +#define CONTROL_POINT_DIAGONAL 3 + +// Line +#define CONTROL_POINT_ENDPOINT_TO 4 +#define CONTROL_POINT_ENDPOINT_FROM 5 +#define CONTROL_POINT_LINE 6 + +extern wxCursor *g_oglBullseyeCursor; + +IMPLEMENT_DYNAMIC_CLASS(wxShapeCanvas, wxScrolledWindow) + +BEGIN_EVENT_TABLE(wxShapeCanvas, wxScrolledWindow) + EVT_PAINT(wxShapeCanvas::OnPaint) + EVT_MOUSE_EVENTS(wxShapeCanvas::OnMouseEvent) +END_EVENT_TABLE() + +// Object canvas +wxShapeCanvas::wxShapeCanvas(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style): + wxScrolledWindow(parent, id, pos, size, style) +{ + m_shapeDiagram = NULL; + m_dragState = NoDragging; + m_draggedShape = NULL; + m_oldDragX = 0; + m_oldDragY = 0; + m_firstDragX = 0; + m_firstDragY = 0; + m_checkTolerance = TRUE; +} + +wxShapeCanvas::~wxShapeCanvas() +{ +} + +void wxShapeCanvas::OnPaint(wxPaintEvent& event) +{ + wxPaintDC dc(this); + + PrepareDC(dc); + + dc.Clear(); + + if (GetDiagram()) + GetDiagram()->Redraw(dc); +} + +void wxShapeCanvas::OnMouseEvent(wxMouseEvent& event) +{ + wxClientDC dc(this); + PrepareDC(dc); + + wxPoint logPos(event.GetLogicalPosition(dc)); + + double x, y; + x = (double) logPos.x; + y = (double) logPos.y; + + int keys = 0; + if (event.ShiftDown()) + keys = keys | KEY_SHIFT; + if (event.ControlDown()) + keys = keys | KEY_CTRL; + + bool dragging = event.Dragging(); + + // Check if we're within the tolerance for mouse movements. + // If we're very close to the position we started dragging + // from, this may not be an intentional drag at all. + if (dragging) + { + int dx = abs(dc.LogicalToDeviceX((long) (x - m_firstDragX))); + int dy = abs(dc.LogicalToDeviceY((long) (y - m_firstDragY))); + if (m_checkTolerance && (dx <= GetDiagram()->GetMouseTolerance()) && (dy <= GetDiagram()->GetMouseTolerance())) + { + return; + } + else + // If we've ignored the tolerance once, then ALWAYS ignore + // tolerance in this drag, even if we come back within + // the tolerance range. + m_checkTolerance = FALSE; + } + + // Dragging - note that the effect of dragging is left entirely up + // to the object, so no movement is done unless explicitly done by + // object. + if (dragging && m_draggedShape && m_dragState == StartDraggingLeft) + { + m_dragState = ContinueDraggingLeft; + + // If the object isn't m_draggable, transfer message to canvas + if (m_draggedShape->Draggable()) + m_draggedShape->GetEventHandler()->OnBeginDragLeft((double)x, (double)y, keys, m_draggedAttachment); + else + { + m_draggedShape = NULL; + OnBeginDragLeft((double)x, (double)y, keys); + } + + m_oldDragX = x; m_oldDragY = y; + } + else if (dragging && m_draggedShape && m_dragState == ContinueDraggingLeft) + { + // Continue dragging + m_draggedShape->GetEventHandler()->OnDragLeft(FALSE, m_oldDragX, m_oldDragY, keys, m_draggedAttachment); + m_draggedShape->GetEventHandler()->OnDragLeft(TRUE, (double)x, (double)y, keys, m_draggedAttachment); + m_oldDragX = x; m_oldDragY = y; + } + else if (event.LeftUp() && m_draggedShape && m_dragState == ContinueDraggingLeft) + { + m_dragState = NoDragging; + m_checkTolerance = TRUE; + + m_draggedShape->GetEventHandler()->OnDragLeft(FALSE, m_oldDragX, m_oldDragY, keys, m_draggedAttachment); + + m_draggedShape->GetEventHandler()->OnEndDragLeft((double)x, (double)y, keys, m_draggedAttachment); + m_draggedShape = NULL; + } + else if (dragging && m_draggedShape && m_dragState == StartDraggingRight) + { + m_dragState = ContinueDraggingRight; + + if (m_draggedShape->Draggable()) + m_draggedShape->GetEventHandler()->OnBeginDragRight((double)x, (double)y, keys, m_draggedAttachment); + else + { + m_draggedShape = NULL; + OnBeginDragRight((double)x, (double)y, keys); + } + m_oldDragX = x; m_oldDragY = y; + } + else if (dragging && m_draggedShape && m_dragState == ContinueDraggingRight) + { + // Continue dragging + m_draggedShape->GetEventHandler()->OnDragRight(FALSE, m_oldDragX, m_oldDragY, keys, m_draggedAttachment); + m_draggedShape->GetEventHandler()->OnDragRight(TRUE, (double)x, (double)y, keys, m_draggedAttachment); + m_oldDragX = x; m_oldDragY = y; + } + else if (event.RightUp() && m_draggedShape && m_dragState == ContinueDraggingRight) + { + m_dragState = NoDragging; + m_checkTolerance = TRUE; + + m_draggedShape->GetEventHandler()->OnDragRight(FALSE, m_oldDragX, m_oldDragY, keys, m_draggedAttachment); + + m_draggedShape->GetEventHandler()->OnEndDragRight((double)x, (double)y, keys, m_draggedAttachment); + m_draggedShape = NULL; + } + + // All following events sent to canvas, not object + else if (dragging && !m_draggedShape && m_dragState == StartDraggingLeft) + { + m_dragState = ContinueDraggingLeft; + OnBeginDragLeft((double)x, (double)y, keys); + m_oldDragX = x; m_oldDragY = y; + } + else if (dragging && !m_draggedShape && m_dragState == ContinueDraggingLeft) + { + // Continue dragging + OnDragLeft(FALSE, m_oldDragX, m_oldDragY, keys); + OnDragLeft(TRUE, (double)x, (double)y, keys); + m_oldDragX = x; m_oldDragY = y; + } + else if (event.LeftUp() && !m_draggedShape && m_dragState == ContinueDraggingLeft) + { + m_dragState = NoDragging; + m_checkTolerance = TRUE; + + OnDragLeft(FALSE, m_oldDragX, m_oldDragY, keys); + OnEndDragLeft((double)x, (double)y, keys); + m_draggedShape = NULL; + } + else if (dragging && !m_draggedShape && m_dragState == StartDraggingRight) + { + m_dragState = ContinueDraggingRight; + OnBeginDragRight((double)x, (double)y, keys); + m_oldDragX = x; m_oldDragY = y; + } + else if (dragging && !m_draggedShape && m_dragState == ContinueDraggingRight) + { + // Continue dragging + OnDragRight(FALSE, m_oldDragX, m_oldDragY, keys); + OnDragRight(TRUE, (double)x, (double)y, keys); + m_oldDragX = x; m_oldDragY = y; + } + else if (event.RightUp() && !m_draggedShape && m_dragState == ContinueDraggingRight) + { + m_dragState = NoDragging; + m_checkTolerance = TRUE; + + OnDragRight(FALSE, m_oldDragX, m_oldDragY, keys); + OnEndDragRight((double)x, (double)y, keys); + m_draggedShape = NULL; + } + + // Non-dragging events + else if (event.IsButton()) + { + m_checkTolerance = TRUE; + + // Find the nearest object + int attachment = 0; + wxShape *nearest_object = FindShape(x, y, &attachment); + if (nearest_object) // Object event + { + if (event.LeftDown()) + { + m_draggedShape = nearest_object; + m_draggedAttachment = attachment; + m_dragState = StartDraggingLeft; + m_firstDragX = x; + m_firstDragY = y; + } + else if (event.LeftUp()) + { + // N.B. Only register a click if the same object was + // identified for down *and* up. + if (nearest_object == m_draggedShape) + nearest_object->GetEventHandler()->OnLeftClick((double)x, (double)y, keys, attachment); + + m_draggedShape = NULL; + m_dragState = NoDragging; + } + else if (event.LeftDClick()) + { + nearest_object->GetEventHandler()->OnLeftDoubleClick((double)x, (double)y, keys, attachment); + + m_draggedShape = NULL; + m_dragState = NoDragging; + } + else if (event.RightDown()) + { + m_draggedShape = nearest_object; + m_draggedAttachment = attachment; + m_dragState = StartDraggingRight; + m_firstDragX = x; + m_firstDragY = y; + } + else if (event.RightUp()) + { + if (nearest_object == m_draggedShape) + nearest_object->GetEventHandler()->OnRightClick((double)x, (double)y, keys, attachment); + + m_draggedShape = NULL; + m_dragState = NoDragging; + } + } + else // Canvas event (no nearest object) + { + if (event.LeftDown()) + { + m_draggedShape = NULL; + m_dragState = StartDraggingLeft; + m_firstDragX = x; + m_firstDragY = y; + } + else if (event.LeftUp()) + { + OnLeftClick((double)x, (double)y, keys); + + m_draggedShape = NULL; + m_dragState = NoDragging; + } + else if (event.RightDown()) + { + m_draggedShape = NULL; + m_dragState = StartDraggingRight; + m_firstDragX = x; + m_firstDragY = y; + } + else if (event.RightUp()) + { + OnRightClick((double)x, (double)y, keys); + + m_draggedShape = NULL; + m_dragState = NoDragging; + } + } + } +} + +/* + * Try to find a sensitive object, working up the hierarchy of composites. + * + */ +wxShape *wxShapeCanvas::FindFirstSensitiveShape(double x, double y, int *new_attachment, int op) +{ + wxShape *image = FindShape(x, y, new_attachment); + if (!image) return NULL; + + wxShape *actualImage = FindFirstSensitiveShape1(image, op); + if (actualImage) + { + double dist; + // Find actual attachment + actualImage->HitTest(x, y, new_attachment, &dist); + } + return actualImage; +} + +wxShape *wxShapeCanvas::FindFirstSensitiveShape1(wxShape *image, int op) +{ + if (image->GetSensitivityFilter() & op) + return image; + if (image->GetParent()) + return FindFirstSensitiveShape1(image->GetParent(), op); + return NULL; +} + +// Helper function: TRUE if 'contains' wholly contains 'contained'. +static bool WhollyContains(wxShape *contains, wxShape *contained) +{ + double xp1, yp1, xp2, yp2; + double w1, h1, w2, h2; + double left1, top1, right1, bottom1, left2, top2, right2, bottom2; + + xp1 = contains->GetX(); yp1 = contains->GetY(); xp2 = contained->GetX(); yp2 = contained->GetY(); + contains->GetBoundingBoxMax(&w1, &h1); + contained->GetBoundingBoxMax(&w2, &h2); + + left1 = (double)(xp1 - (w1 / 2.0)); + top1 = (double)(yp1 - (h1 / 2.0)); + right1 = (double)(xp1 + (w1 / 2.0)); + bottom1 = (double)(yp1 + (h1 / 2.0)); + + left2 = (double)(xp2 - (w2 / 2.0)); + top2 = (double)(yp2 - (h2 / 2.0)); + right2 = (double)(xp2 + (w2 / 2.0)); + bottom2 = (double)(yp2 + (h2 / 2.0)); + + return ((left1 <= left2) && (top1 <= top2) && (right1 >= right2) && (bottom1 >= bottom2)); +} + +wxShape *wxShapeCanvas::FindShape(double x, double y, int *attachment, wxClassInfo *info, wxShape *notObject) +{ + double nearest = 100000.0; + int nearest_attachment = 0; + wxShape *nearest_object = NULL; + + // Go backward through the object list, since we want: + // (a) to have the control points drawn LAST to overlay + // the other objects + // (b) to find the control points FIRST if they exist + + wxNode *current = GetDiagram()->GetShapeList()->Last(); + while (current) + { + wxShape *object = (wxShape *)current->Data(); + + double dist; + int temp_attachment; + + // First pass for lines, which might be inside a container, so we + // want lines to take priority over containers. This first loop + // could fail if we clickout side a line, so then we'll + // try other shapes. + if (object->IsShown() && + object->IsKindOf(CLASSINFO(wxLineShape)) && + object->HitTest(x, y, &temp_attachment, &dist) && + ((info == NULL) || object->IsKindOf(info)) && + (!notObject || !notObject->HasDescendant(object))) + { + // A line is trickier to spot than a normal object. + // For a line, since it's the diagonal of the box + // we use for the hit test, we may have several + // lines in the box and therefore we need to be able + // to specify the nearest point to the centre of the line + // as our hit criterion, to give the user some room for + // manouevre. + if (dist < nearest) + { + nearest = dist; + nearest_object = object; + nearest_attachment = temp_attachment; + } + } + if (current) + current = current->Previous(); + } + + current = GetDiagram()->GetShapeList()->Last(); + while (current) + { + wxShape *object = (wxShape *)current->Data(); + double dist; + int temp_attachment; + + // On second pass, only ever consider non-composites or divisions. If children want to pass + // up control to the composite, that's up to them. + if (object->IsShown() && (object->IsKindOf(CLASSINFO(wxDivisionShape)) || !object->IsKindOf(CLASSINFO(wxCompositeShape))) + && object->HitTest(x, y, &temp_attachment, &dist) && ((info == NULL) || object->IsKindOf(info)) && + (!notObject || !notObject->HasDescendant(object))) + { + if (!object->IsKindOf(CLASSINFO(wxLineShape))) + { + // If we've hit a container, and we have already found a line in the + // first pass, then ignore the container in case the line is in the container. + // Check for division in case line straddles divisions (i.e. is not wholly contained). + if (!nearest_object || !(object->IsKindOf(CLASSINFO(wxDivisionShape)) || WhollyContains(object, nearest_object))) + { + nearest = dist; + nearest_object = object; + nearest_attachment = temp_attachment; + current = NULL; + } + } + } + if (current) + current = current->Previous(); + } + + *attachment = nearest_attachment; + return nearest_object; +} + +/* + * Higher-level events called by OnEvent + * + */ + +void wxShapeCanvas::OnLeftClick(double x, double y, int keys) +{ +} + +void wxShapeCanvas::OnRightClick(double x, double y, int keys) +{ +} + +void wxShapeCanvas::OnDragLeft(bool draw, double x, double y, int keys) +{ +} + +void wxShapeCanvas::OnBeginDragLeft(double x, double y, int keys) +{ +} + +void wxShapeCanvas::OnEndDragLeft(double x, double y, int keys) +{ +} + +void wxShapeCanvas::OnDragRight(bool draw, double x, double y, int keys) +{ +} + +void wxShapeCanvas::OnBeginDragRight(double x, double y, int keys) +{ +} + +void wxShapeCanvas::OnEndDragRight(double x, double y, int keys) +{ +} + +void wxShapeCanvas::AddShape(wxShape *object, wxShape *addAfter) + { GetDiagram()->AddShape(object, addAfter); } +void wxShapeCanvas::InsertShape(wxShape *object) + { GetDiagram()->InsertShape(object); } +void wxShapeCanvas::RemoveShape(wxShape *object) + { GetDiagram()->RemoveShape(object); } +bool wxShapeCanvas::GetQuickEditMode() + { return GetDiagram()->GetQuickEditMode(); } +void wxShapeCanvas::Redraw(wxDC& dc) + { GetDiagram()->Redraw(dc); } +void wxShapeCanvas::Snap(double *x, double *y) + { GetDiagram()->Snap(x, y); } diff --git a/src/ogl/composit.cpp b/src/ogl/composit.cpp new file mode 100644 index 0000000000..ba237db51f --- /dev/null +++ b/src/ogl/composit.cpp @@ -0,0 +1,1784 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: composit.cpp +// Purpose: Composite OGL class +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "composit.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include + +// Sometimes, objects need to access the whole database to +// construct themselves. +wxExprDatabase *GlobalwxExprDatabase = NULL; + + +/* + * Division control point + */ + +class wxDivisionControlPoint: public wxControlPoint +{ + DECLARE_DYNAMIC_CLASS(wxDivisionControlPoint) + public: + wxDivisionControlPoint() {} + wxDivisionControlPoint(wxShapeCanvas *the_canvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type); + ~wxDivisionControlPoint(); + + 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); +}; + +IMPLEMENT_DYNAMIC_CLASS(wxDivisionControlPoint, wxControlPoint) + +/* + * Composite object + * + */ + +IMPLEMENT_DYNAMIC_CLASS(wxCompositeShape, wxRectangleShape) + +wxCompositeShape::wxCompositeShape(): wxRectangleShape(10.0, 10.0) +{ +// selectable = FALSE; + m_oldX = m_xpos; + m_oldY = m_ypos; +} + +wxCompositeShape::~wxCompositeShape() +{ + wxNode *node = m_constraints.First(); + while (node) + { + wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data(); + delete constraint; + node = node->Next(); + } + node = m_children.First(); + while (node) + { + wxShape *object = (wxShape *)node->Data(); + wxNode *next = node->Next(); + object->Unlink(); + delete object; + node = next; + } +} + +void wxCompositeShape::OnDraw(wxDC& dc) +{ + double x1 = (double)(m_xpos - m_width/2.0); + double y1 = (double)(m_ypos - m_height/2.0); + + if (m_shadowMode != SHADOW_NONE) + { + if (m_shadowBrush) + dc.SetBrush(* m_shadowBrush); + dc.SetPen(* g_oglTransparentPen); + + if (m_cornerRadius != 0.0) + dc.DrawRoundedRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY), + WXROUND(m_width), WXROUND(m_height), m_cornerRadius); + else + dc.DrawRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY), WXROUND(m_width), WXROUND(m_height)); + } +} + +void wxCompositeShape::OnDrawContents(wxDC& dc) +{ + wxNode *node = m_children.First(); + while (node) + { + wxShape *object = (wxShape *)node->Data(); + object->Draw(dc); + object->DrawLinks(dc); + node = node->Next(); + } + wxShape::OnDrawContents(dc); +} + +bool wxCompositeShape::OnMovePre(wxDC& dc, double x, double y, double oldx, double oldy, bool display) +{ + double diffX = x - oldx; + double diffY = y - oldy; + wxNode *node = m_children.First(); + while (node) + { + wxShape *object = (wxShape *)node->Data(); + + object->Erase(dc); + object->Move(dc, object->GetX() + diffX, object->GetY() + diffY, display); + + node = node->Next(); + } + return TRUE; +} + +void wxCompositeShape::OnErase(wxDC& dc) +{ + wxRectangleShape::OnErase(dc); + wxNode *node = m_children.First(); + while (node) + { + wxShape *object = (wxShape *)node->Data(); + object->Erase(dc); + node = node->Next(); + } +} + +static double objectStartX = 0.0; +static double objectStartY = 0.0; + +void wxCompositeShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment) +{ + double xx = x; + double yy = y; + m_canvas->Snap(&xx, &yy); + double offsetX = xx - objectStartX; + double offsetY = yy - objectStartY; + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + dc.SetLogicalFunction(OGLRBLF); + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetPen(dottedPen); + dc.SetBrush((* wxTRANSPARENT_BRUSH)); + + GetEventHandler()->OnDrawOutline(dc, GetX() + offsetX, GetY() + offsetY, GetWidth(), GetHeight()); +// wxShape::OnDragLeft(draw, x, y, keys, attachment); +} + +void wxCompositeShape::OnBeginDragLeft(double x, double y, int keys, int attachment) +{ + objectStartX = x; + objectStartY = y; + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + Erase(dc); + + dc.SetLogicalFunction(OGLRBLF); + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetPen(dottedPen); + dc.SetBrush((* wxTRANSPARENT_BRUSH)); + m_canvas->CaptureMouse(); + + double xx = x; + double yy = y; + m_canvas->Snap(&xx, &yy); + double offsetX = xx - objectStartX; + double offsetY = yy - objectStartY; + + GetEventHandler()->OnDrawOutline(dc, GetX() + offsetX, GetY() + offsetY, GetWidth(), GetHeight()); + +// wxShape::OnBeginDragLeft(x, y, keys, attachment); +} + +void wxCompositeShape::OnEndDragLeft(double x, double y, int keys, int attachment) +{ +// wxShape::OnEndDragLeft(x, y, keys, attachment); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + m_canvas->ReleaseMouse(); + + if (!m_draggable) + { + if (m_parent) m_parent->GetEventHandler()->OnEndDragLeft(x, y, keys, 0); + return; + } + + dc.SetLogicalFunction(wxCOPY); + double xx = x; + double yy = y; + m_canvas->Snap(&xx, &yy); + double offsetX = xx - objectStartX; + double offsetY = yy - objectStartY; + + Move(dc, GetX() + offsetX, GetY() + offsetY); + + if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc); +} + +void wxCompositeShape::OnRightClick(double x, double y, int keys, int attachment) +{ + // If we get a ctrl-right click, this means send the message to + // the division, so we can invoke a user interface for dealing with regions. + if (keys & KEY_CTRL) + { + wxNode *node = m_divisions.First(); + while (node) + { + wxDivisionShape *division = (wxDivisionShape *)node->Data(); + wxNode *next = node->Next(); + int attach = 0; + double dist = 0.0; + if (division->HitTest(x, y, &attach, &dist)) + { + division->GetEventHandler()->OnRightClick(x, y, keys, attach); + node = NULL; + } + if (node) + node = next; + } + } +} + +void wxCompositeShape::SetSize(double w, double h, bool recursive) +{ + SetAttachmentSize(w, h); + + double xScale = (double)(w/(wxMax(1.0, GetWidth()))); + double yScale = (double)(h/(wxMax(1.0, GetHeight()))); + + m_width = w; + m_height = h; + + if (!recursive) return; + + wxNode *node = m_children.First(); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + double xBound, yBound; + while (node) + { + wxShape *object = (wxShape *)node->Data(); + + // Scale the position first + double newX = (double)(((object->GetX() - GetX())*xScale) + GetX()); + double newY = (double)(((object->GetY() - GetY())*yScale) + GetY()); + object->Show(FALSE); + object->Move(dc, newX, newY); + object->Show(TRUE); + + // Now set the scaled size + object->GetBoundingBoxMin(&xBound, &yBound); + object->SetSize(object->GetFixedWidth() ? xBound : xScale*xBound, + object->GetFixedHeight() ? yBound : yScale*yBound); + + node = node->Next(); + } + SetDefaultRegionSize(); +} + +void wxCompositeShape::AddChild(wxShape *child, wxShape *addAfter) +{ + m_children.Append(child); + child->SetParent(this); + if (m_canvas) + { + // Ensure we add at the right position + if (addAfter) + child->RemoveFromCanvas(m_canvas); + child->AddToCanvas(m_canvas, addAfter); + } +} + +void wxCompositeShape::RemoveChild(wxShape *child) +{ + m_children.DeleteObject(child); + m_divisions.DeleteObject(child); + RemoveChildFromConstraints(child); + child->SetParent(NULL); +} + +void wxCompositeShape::DeleteConstraintsInvolvingChild(wxShape *child) +{ + wxNode *node = m_constraints.First(); + while (node) + { + wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data(); + wxNode *nextNode = node->Next(); + + if ((constraint->m_constrainingObject == child) || + constraint->m_constrainedObjects.Member(child)) + { + delete constraint; + delete node; + } + node = nextNode; + } +} + +void wxCompositeShape::RemoveChildFromConstraints(wxShape *child) +{ + wxNode *node = m_constraints.First(); + while (node) + { + wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data(); + wxNode *nextNode = node->Next(); + + if (constraint->m_constrainedObjects.Member(child)) + constraint->m_constrainedObjects.DeleteObject(child); + if (constraint->m_constrainingObject == child) + constraint->m_constrainingObject = NULL; + + // Delete the constraint if no participants left + if (!constraint->m_constrainingObject) + { + delete constraint; + delete node; + } + + node = nextNode; + } +} + +void wxCompositeShape::Copy(wxShape& copy) +{ + wxRectangleShape::Copy(copy); + + wxASSERT( copy.IsKindOf(CLASSINFO(wxCompositeShape)) ) ; + + wxCompositeShape& compositeCopy = (wxCompositeShape&) copy; + + // Associate old and new copies for compositeCopying constraints and division geometry + oglObjectCopyMapping.Append((long)this, &compositeCopy); + + // Copy the children + wxNode *node = m_children.First(); + while (node) + { + wxShape *object = (wxShape *)node->Data(); + wxShape *newObject = object->CreateNewCopy(FALSE, FALSE); + if (newObject->GetId() == 0) + newObject->SetId(wxNewId()); + + newObject->SetParent(&compositeCopy); + compositeCopy.m_children.Append(newObject); + + // Some m_children may be divisions + if (m_divisions.Member(object)) + compositeCopy.m_divisions.Append(newObject); + + oglObjectCopyMapping.Append((long)object, newObject); + + node = node->Next(); + } + + // Copy the constraints + node = m_constraints.First(); + while (node) + { + wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data(); + + wxShape *newConstraining = (wxShape *)(oglObjectCopyMapping.Find((long)constraint->m_constrainingObject)->Data()); + + wxList newConstrainedList; + wxNode *node2 = constraint->m_constrainedObjects.First(); + while (node2) + { + wxShape *constrainedObject = (wxShape *)node2->Data(); + wxShape *newConstrained = (wxShape *)(oglObjectCopyMapping.Find((long)constrainedObject)->Data()); + newConstrainedList.Append(newConstrained); + node2 = node2->Next(); + } + + wxOGLConstraint *newConstraint = new wxOGLConstraint(constraint->m_constraintType, newConstraining, + newConstrainedList); + newConstraint->m_constraintId = constraint->m_constraintId; + if (constraint->m_constraintName) + { + newConstraint->m_constraintName = constraint->m_constraintName; + } + newConstraint->SetSpacing(constraint->m_xSpacing, constraint->m_ySpacing); + compositeCopy.m_constraints.Append(newConstraint); + + node = node->Next(); + } + + // Now compositeCopy the division geometry + node = m_divisions.First(); + while (node) + { + wxDivisionShape *division = (wxDivisionShape *)node->Data(); + wxNode *node1 = oglObjectCopyMapping.Find((long)division); + wxNode *leftNode = NULL; + wxNode *topNode = NULL; + wxNode *rightNode = NULL; + wxNode *bottomNode = NULL; + if (division->GetLeftSide()) + leftNode = oglObjectCopyMapping.Find((long)division->GetLeftSide()); + if (division->GetTopSide()) + topNode = oglObjectCopyMapping.Find((long)division->GetTopSide()); + if (division->GetRightSide()) + rightNode = oglObjectCopyMapping.Find((long)division->GetRightSide()); + if (division->GetBottomSide()) + bottomNode = oglObjectCopyMapping.Find((long)division->GetBottomSide()); + if (node1) + { + wxDivisionShape *newDivision = (wxDivisionShape *)node1->Data(); + if (leftNode) + newDivision->SetLeftSide((wxDivisionShape *)leftNode->Data()); + if (topNode) + newDivision->SetTopSide((wxDivisionShape *)topNode->Data()); + if (rightNode) + newDivision->SetRightSide((wxDivisionShape *)rightNode->Data()); + if (bottomNode) + newDivision->SetBottomSide((wxDivisionShape *)bottomNode->Data()); + } + node = node->Next(); + } +} + +wxOGLConstraint *wxCompositeShape::AddConstraint(wxOGLConstraint *constraint) +{ + m_constraints.Append(constraint); + if (constraint->m_constraintId == 0) + constraint->m_constraintId = wxNewId(); + return constraint; +} + +wxOGLConstraint *wxCompositeShape::AddConstraint(int type, wxShape *constraining, wxList& constrained) +{ + wxOGLConstraint *constraint = new wxOGLConstraint(type, constraining, constrained); + if (constraint->m_constraintId == 0) + constraint->m_constraintId = wxNewId(); + m_constraints.Append(constraint); + return constraint; +} + +wxOGLConstraint *wxCompositeShape::AddConstraint(int type, wxShape *constraining, wxShape *constrained) +{ + wxList l; + l.Append(constrained); + wxOGLConstraint *constraint = new wxOGLConstraint(type, constraining, l); + if (constraint->m_constraintId == 0) + constraint->m_constraintId = wxNewId(); + m_constraints.Append(constraint); + return constraint; +} + +wxOGLConstraint *wxCompositeShape::FindConstraint(long cId, wxCompositeShape **actualComposite) +{ + wxNode *node = m_constraints.First(); + while (node) + { + wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data(); + if (constraint->m_constraintId == cId) + { + if (actualComposite) + *actualComposite = this; + return constraint; + } + node = node->Next(); + } + // If not found, try children. + node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + if (child->IsKindOf(CLASSINFO(wxCompositeShape))) + { + wxOGLConstraint *constraint = ((wxCompositeShape *)child)->FindConstraint(cId, actualComposite); + if (constraint) + { + if (actualComposite) + *actualComposite = (wxCompositeShape *)child; + return constraint; + } + } + node = node->Next(); + } + return NULL; +} + +void wxCompositeShape::DeleteConstraint(wxOGLConstraint *constraint) +{ + m_constraints.DeleteObject(constraint); + delete constraint; +} + +void wxCompositeShape::CalculateSize() +{ + double maxX = (double) -999999.9; + double maxY = (double) -999999.9; + double minX = (double) 999999.9; + double minY = (double) 999999.9; + + double w, h; + wxNode *node = m_children.First(); + while (node) + { + wxShape *object = (wxShape *)node->Data(); + + // Recalculate size of composite objects because may not conform + // to size it was set to - depends on the children. + object->CalculateSize(); + + object->GetBoundingBoxMax(&w, &h); + if ((object->GetX() + (w/2.0)) > maxX) + maxX = (double)(object->GetX() + (w/2.0)); + if ((object->GetX() - (w/2.0)) < minX) + minX = (double)(object->GetX() - (w/2.0)); + if ((object->GetY() + (h/2.0)) > maxY) + maxY = (double)(object->GetY() + (h/2.0)); + if ((object->GetY() - (h/2.0)) < minY) + minY = (double)(object->GetY() - (h/2.0)); + + node = node->Next(); + } + m_width = maxX - minX; + m_height = maxY - minY; + m_xpos = (double)(m_width/2.0 + minX); + m_ypos = (double)(m_height/2.0 + minY); +} + +bool wxCompositeShape::Recompute() +{ + int noIterations = 0; + bool changed = TRUE; + while (changed && (noIterations < 500)) + { + changed = Constrain(); + noIterations ++; + } +/* +#ifdef wx_x + if (changed) + cerr << "Warning: constraint algorithm failed after 500 iterations.\n"; +#endif +*/ + return (!changed); +} + +bool wxCompositeShape::Constrain() +{ + CalculateSize(); + + bool changed = FALSE; + wxNode *node = m_children.First(); + while (node) + { + wxShape *object = (wxShape *)node->Data(); + if (object->Constrain()) + changed = TRUE; + node = node->Next(); + } + + node = m_constraints.First(); + while (node) + { + wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data(); + if (constraint->Evaluate()) changed = TRUE; + node = node->Next(); + } + return changed; +} + +#ifdef PROLOGIO +void wxCompositeShape::WriteAttributes(wxExpr *clause) +{ + wxRectangleShape::WriteAttributes(clause); + +// clause->AddAttributeValue("selectable", (long)selectable); + + // Output constraints as constraint1 = (...), constraint2 = (...), etc. + int constraintNo = 1; + char m_constraintNameBuf[20]; + wxNode *node = m_constraints.First(); + while (node) + { + wxOGLConstraint *constraint = (wxOGLConstraint *)node->Data(); + sprintf(m_constraintNameBuf, "constraint%d", constraintNo); + + // Each constraint is stored in the form + // (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList) + wxExpr *constraintExpr = new wxExpr(wxExprList); + constraintExpr->Append(new wxExpr((long)constraint->m_constraintType)); + constraintExpr->Append(new wxExpr(wxExprString, constraint->m_constraintName)); + constraintExpr->Append(new wxExpr(constraint->m_constraintId)); + constraintExpr->Append(new wxExpr(constraint->m_xSpacing)); + constraintExpr->Append(new wxExpr(constraint->m_ySpacing)); + constraintExpr->Append(new wxExpr(constraint->m_constrainingObject->GetId())); + + wxExpr *objectList = new wxExpr(wxExprList); + wxNode *node1 = constraint->m_constrainedObjects.First(); + while (node1) + { + wxShape *obj = (wxShape *)node1->Data(); + objectList->Append(new wxExpr(obj->GetId())); + node1 = node1->Next(); + } + constraintExpr->Append(objectList); + + clause->AddAttributeValue(m_constraintNameBuf, constraintExpr); + + node = node->Next(); + constraintNo ++; + } + + // Write the ids of all the child images + wxExpr *childrenExpr = new wxExpr(wxExprList); + node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + childrenExpr->Append(new wxExpr(child->GetId())); + node = node->Next(); + } + clause->AddAttributeValue("children", childrenExpr); + + // Write the ids of all the division images + if (m_divisions.Number() > 0) + { + wxExpr *divisionsExpr = new wxExpr(wxExprList); + node = m_divisions.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + divisionsExpr->Append(new wxExpr(child->GetId())); + node = node->Next(); + } + clause->AddAttributeValue("divisions", divisionsExpr); + } +} + +// Problem. Child images are always written AFTER the parent +// so as to be able to link up to parent. So we may not be able +// to find the constraint participants until we've read everything +// in. Need to have another pass for composites. +void wxCompositeShape::ReadAttributes(wxExpr *clause) +{ + wxRectangleShape::ReadAttributes(clause); + +// clause->GetAttributeValue("selectable", selectable); +} + +void wxCompositeShape::ReadConstraints(wxExpr *clause, wxExprDatabase *database) +{ + // Constraints are output as constraint1 = (...), constraint2 = (...), etc. + int constraintNo = 1; + char m_constraintNameBuf[20]; + bool haveConstraints = TRUE; + + while (haveConstraints) + { + sprintf(m_constraintNameBuf, "constraint%d", constraintNo); + wxExpr *constraintExpr = NULL; + clause->GetAttributeValue(m_constraintNameBuf, &constraintExpr); + if (!constraintExpr) + { + haveConstraints = FALSE; + break; + } + int cType = 0; + double cXSpacing = 0.0; + double cYSpacing = 0.0; + wxString cName(""); + long cId = 0; + wxShape *m_constrainingObject = NULL; + wxList m_constrainedObjects; + + // Each constraint is stored in the form + // (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList) + + wxExpr *typeExpr = constraintExpr->Nth(0); + wxExpr *nameExpr = constraintExpr->Nth(1); + wxExpr *idExpr = constraintExpr->Nth(2); + wxExpr *xExpr = constraintExpr->Nth(3); + wxExpr *yExpr = constraintExpr->Nth(4); + wxExpr *constrainingExpr = constraintExpr->Nth(5); + wxExpr *constrainedExpr = constraintExpr->Nth(6); + + cType = (int)typeExpr->IntegerValue(); + cXSpacing = xExpr->RealValue(); + cYSpacing = yExpr->RealValue(); + cName = nameExpr->StringValue(); + cId = idExpr->IntegerValue(); + + wxExpr *objExpr1 = database->HashFind("node_image", constrainingExpr->IntegerValue()); + if (objExpr1 && objExpr1->GetClientData()) + m_constrainingObject = (wxShape *)objExpr1->GetClientData(); + else + wxFatalError("Couldn't find constraining image of composite.", "Object graphics error"); + + int i = 0; + wxExpr *currentIdExpr = constrainedExpr->Nth(i); + while (currentIdExpr) + { + long currentId = currentIdExpr->IntegerValue(); + wxExpr *objExpr2 = database->HashFind("node_image", currentId); + if (objExpr2 && objExpr2->GetClientData()) + { + m_constrainedObjects.Append((wxShape *)objExpr2->GetClientData()); + } + else + { + wxFatalError("Couldn't find constrained image of composite.", "Object graphics error"); + } + + i ++; + currentIdExpr = constrainedExpr->Nth(i); + } + wxOGLConstraint *newConstraint = AddConstraint(cType, m_constrainingObject, m_constrainedObjects); + newConstraint->SetSpacing(cXSpacing, cYSpacing); + newConstraint->m_constraintId = cId; + newConstraint->m_constraintName = (const char*) cName; + constraintNo ++; + } +} +#endif + +// Make this composite into a container by creating one wxDivisionShape +void wxCompositeShape::MakeContainer() +{ + wxDivisionShape *division = OnCreateDivision(); + m_divisions.Append(division); + AddChild(division); + + division->SetSize(m_width, m_height); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + division->Move(dc, GetX(), GetY()); + Recompute(); + division->Show(TRUE); +} + +wxDivisionShape *wxCompositeShape::OnCreateDivision() +{ + return new wxDivisionShape; +} + +wxShape *wxCompositeShape::FindContainerImage() +{ + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + if (!m_divisions.Member(child)) + return child; + node = node->Next(); + } + return NULL; +} + +// Returns TRUE if division is a descendant of this container +bool wxCompositeShape::ContainsDivision(wxDivisionShape *division) +{ + if (m_divisions.Member(division)) + return TRUE; + wxNode *node = m_children.First(); + while (node) + { + wxShape *child = (wxShape *)node->Data(); + if (child->IsKindOf(CLASSINFO(wxCompositeShape))) + { + bool ans = ((wxCompositeShape *)child)->ContainsDivision(division); + if (ans) + return TRUE; + } + node = node->Next(); + } + return FALSE; +} + +/* + * Division object + * + */ + +IMPLEMENT_DYNAMIC_CLASS(wxDivisionShape, wxCompositeShape) + +wxDivisionShape::wxDivisionShape() +{ + SetSensitivityFilter(OP_CLICK_LEFT | OP_CLICK_RIGHT | OP_DRAG_RIGHT); + SetCentreResize(FALSE); + SetAttachmentMode(TRUE); + m_leftSide = NULL; + m_rightSide = NULL; + m_topSide = NULL; + m_bottomSide = NULL; + m_handleSide = DIVISION_SIDE_NONE; + m_leftSidePen = wxBLACK_PEN; + m_topSidePen = wxBLACK_PEN; + m_leftSideColour = "BLACK"; + m_topSideColour = "BLACK"; + m_leftSideStyle = "Solid"; + m_topSideStyle = "Solid"; + ClearRegions(); +} + +wxDivisionShape::~wxDivisionShape() +{ +} + +void wxDivisionShape::OnDraw(wxDC& dc) +{ + dc.SetBrush(* wxTRANSPARENT_BRUSH); + dc.SetBackgroundMode(wxTRANSPARENT); + + double x1 = (double)(GetX() - (GetWidth()/2.0)); + double y1 = (double)(GetY() - (GetHeight()/2.0)); + double x2 = (double)(GetX() + (GetWidth()/2.0)); + double y2 = (double)(GetY() + (GetHeight()/2.0)); + + // Should subtract 1 pixel if drawing under Windows +#ifdef __WXMSW__ + y2 -= (double)1.0; +#endif + + if (m_leftSide) + { + dc.SetPen(* m_leftSidePen); + dc.DrawLine(WXROUND(x1), WXROUND(y2), WXROUND(x1), WXROUND(y1)); + } + if (m_topSide) + { + dc.SetPen(* m_topSidePen); + dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y1)); + } + + // For testing purposes, draw a rectangle so we know + // how big the division is. +// SetBrush(* wxCYAN_BRUSH); +// wxRectangleShape::OnDraw(dc); +} + +void wxDivisionShape::OnDrawContents(wxDC& dc) +{ + wxCompositeShape::OnDrawContents(dc); +} + +bool wxDivisionShape::OnMovePre(wxDC& dc, double x, double y, double oldx, double oldy, bool display) +{ + double diffX = x - oldx; + double diffY = y - oldy; + wxNode *node = m_children.First(); + while (node) + { + wxShape *object = (wxShape *)node->Data(); + object->Erase(dc); + object->Move(dc, object->GetX() + diffX, object->GetY() + diffY, display); + node = node->Next(); + } + return TRUE; +} + +void wxDivisionShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment) +{ + if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT) + { + attachment = 0; + double dist; + if (m_parent) + { + m_parent->HitTest(x, y, &attachment, &dist); + m_parent->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment); + } + return; + } + wxShape::OnDragLeft(draw, x, y, keys, attachment); +} + +void wxDivisionShape::OnBeginDragLeft(double x, double y, int keys, int attachment) +{ + if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT) + { + attachment = 0; + double dist; + if (m_parent) + { + m_parent->HitTest(x, y, &attachment, &dist); + m_parent->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment); + } + return; + } + + wxShape::OnBeginDragLeft(x, y, keys, attachment); +} + +void wxDivisionShape::OnEndDragLeft(double x, double y, int keys, int attachment) +{ + m_canvas->ReleaseMouse(); + if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT) + { + attachment = 0; + double dist; + if (m_parent) + { + m_parent->HitTest(x, y, &attachment, &dist); + m_parent->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment); + } + return; + } + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + dc.SetLogicalFunction(wxCOPY); + + m_canvas->Snap(&m_xpos, &m_ypos); + GetEventHandler()->OnMovePre(dc, x, y, m_oldX, m_oldY); + + ResetControlPoints(); + Draw(dc); + MoveLinks(dc); + GetEventHandler()->OnDrawControlPoints(dc); + + if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc); +} + +void wxDivisionShape::SetSize(double w, double h, bool recursive) +{ + m_width = w; + m_height = h; + wxRectangleShape::SetSize(w, h, recursive); +} + +void wxDivisionShape::CalculateSize() +{ +} + +void wxDivisionShape::Copy(wxShape& copy) +{ + wxCompositeShape::Copy(copy); + + wxASSERT( copy.IsKindOf(CLASSINFO(wxDivisionShape)) ) ; + + wxDivisionShape& divisionCopy = (wxDivisionShape&) copy; + + divisionCopy.m_leftSideStyle = m_leftSideStyle; + divisionCopy.m_topSideStyle = m_topSideStyle; + divisionCopy.m_leftSideColour = m_leftSideColour; + divisionCopy.m_topSideColour = m_topSideColour; + + divisionCopy.m_leftSidePen = m_leftSidePen; + divisionCopy.m_topSidePen = m_topSidePen; + divisionCopy.m_handleSide = m_handleSide; + + // Division geometry copying is handled at the wxCompositeShape level. +} + +#ifdef PROLOGIO +void wxDivisionShape::WriteAttributes(wxExpr *clause) +{ + wxCompositeShape::WriteAttributes(clause); + + if (m_leftSide) + clause->AddAttributeValue("left_side", (long)m_leftSide->GetId()); + if (m_topSide) + clause->AddAttributeValue("top_side", (long)m_topSide->GetId()); + if (m_rightSide) + clause->AddAttributeValue("right_side", (long)m_rightSide->GetId()); + if (m_bottomSide) + clause->AddAttributeValue("bottom_side", (long)m_bottomSide->GetId()); + + clause->AddAttributeValue("handle_side", (long)m_handleSide); + clause->AddAttributeValueString("left_colour", m_leftSideColour); + clause->AddAttributeValueString("top_colour", m_topSideColour); + clause->AddAttributeValueString("left_style", m_leftSideStyle); + clause->AddAttributeValueString("top_style", m_topSideStyle); +} + +void wxDivisionShape::ReadAttributes(wxExpr *clause) +{ + wxCompositeShape::ReadAttributes(clause); + + clause->GetAttributeValue("handle_side", m_handleSide); + clause->GetAttributeValue("left_colour", m_leftSideColour); + clause->GetAttributeValue("top_colour", m_topSideColour); + clause->GetAttributeValue("left_style", m_leftSideStyle); + clause->GetAttributeValue("top_style", m_topSideStyle); +} +#endif + +// Experimental +void wxDivisionShape::OnRightClick(double x, double y, int keys, int attachment) +{ + if (keys & KEY_CTRL) + { + PopupMenu(x, y); + } +/* + else if (keys & KEY_SHIFT) + { + if (m_leftSide || m_topSide || m_rightSide || m_bottomSide) + { + if (Selected()) + { + Select(FALSE); + GetParent()->Draw(dc); + } + else + Select(TRUE); + } + } +*/ + else + { + attachment = 0; + double dist; + if (m_parent) + { + m_parent->HitTest(x, y, &attachment, &dist); + m_parent->GetEventHandler()->OnRightClick(x, y, keys, attachment); + } + return; + } +} + + +// Divide wxHORIZONTALly or wxVERTICALly +bool wxDivisionShape::Divide(int direction) +{ + // Calculate existing top-left, bottom-right + double x1 = (double)(GetX() - (GetWidth()/2.0)); + double y1 = (double)(GetY() - (GetHeight()/2.0)); + wxCompositeShape *compositeParent = (wxCompositeShape *)GetParent(); + double oldWidth = GetWidth(); + double oldHeight = GetHeight(); + if (Selected()) + Select(FALSE); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + if (direction == wxVERTICAL) + { + // Dividing vertically means notionally putting a horizontal line through it. + // Break existing piece into two. + double newXPos1 = GetX(); + double newYPos1 = (double)(y1 + (GetHeight()/4.0)); + double newXPos2 = GetX(); + double newYPos2 = (double)(y1 + (3.0*GetHeight()/4.0)); + wxDivisionShape *newDivision = compositeParent->OnCreateDivision(); + newDivision->Show(TRUE); + + Erase(dc); + + // Anything adjoining the bottom of this division now adjoins the + // bottom of the new division. + wxNode *node = compositeParent->GetDivisions().First(); + while (node) + { + wxDivisionShape *obj = (wxDivisionShape *)node->Data(); + if (obj->GetTopSide() == this) + obj->SetTopSide(newDivision); + node = node->Next(); + } + newDivision->SetTopSide(this); + newDivision->SetBottomSide(m_bottomSide); + newDivision->SetLeftSide(m_leftSide); + newDivision->SetRightSide(m_rightSide); + m_bottomSide = newDivision; + + compositeParent->GetDivisions().Append(newDivision); + + // CHANGE: Need to insert this division at start of divisions in the object + // list, because e.g.: + // 1) Add division + // 2) Add contained object + // 3) Add division + // Division is now receiving mouse events _before_ the contained object, + // because it was added last (on top of all others) + + // Add after the image that visualizes the container + compositeParent->AddChild(newDivision, compositeParent->FindContainerImage()); + + m_handleSide = DIVISION_SIDE_BOTTOM; + newDivision->SetHandleSide(DIVISION_SIDE_TOP); + + SetSize(oldWidth, (double)(oldHeight/2.0)); + Move(dc, newXPos1, newYPos1); + + newDivision->SetSize(oldWidth, (double)(oldHeight/2.0)); + newDivision->Move(dc, newXPos2, newYPos2); + } + else + { + // Dividing horizontally means notionally putting a vertical line through it. + // Break existing piece into two. + double newXPos1 = (double)(x1 + (GetWidth()/4.0)); + double newYPos1 = GetY(); + double newXPos2 = (double)(x1 + (3.0*GetWidth()/4.0)); + double newYPos2 = GetY(); + wxDivisionShape *newDivision = compositeParent->OnCreateDivision(); + newDivision->Show(TRUE); + + Erase(dc); + + // Anything adjoining the left of this division now adjoins the + // left of the new division. + wxNode *node = compositeParent->GetDivisions().First(); + while (node) + { + wxDivisionShape *obj = (wxDivisionShape *)node->Data(); + if (obj->GetLeftSide() == this) + obj->SetLeftSide(newDivision); + node = node->Next(); + } + newDivision->SetTopSide(m_topSide); + newDivision->SetBottomSide(m_bottomSide); + newDivision->SetLeftSide(this); + newDivision->SetRightSide(m_rightSide); + m_rightSide = newDivision; + + compositeParent->GetDivisions().Append(newDivision); + compositeParent->AddChild(newDivision, compositeParent->FindContainerImage()); + + m_handleSide = DIVISION_SIDE_RIGHT; + newDivision->SetHandleSide(DIVISION_SIDE_LEFT); + + SetSize((double)(oldWidth/2.0), oldHeight); + Move(dc, newXPos1, newYPos1); + + newDivision->SetSize((double)(oldWidth/2.0), oldHeight); + newDivision->Move(dc, newXPos2, newYPos2); + } + if (compositeParent->Selected()) + { + compositeParent->DeleteControlPoints(& dc); + compositeParent->MakeControlPoints(); + compositeParent->MakeMandatoryControlPoints(); + } + compositeParent->Draw(dc); + return TRUE; +} + +// Make one control point for every visible line +void wxDivisionShape::MakeControlPoints() +{ + MakeMandatoryControlPoints(); +} + +void wxDivisionShape::MakeMandatoryControlPoints() +{ + double maxX, maxY; + + GetBoundingBoxMax(&maxX, &maxY); + double x, y; + int direction; +/* + if (m_leftSide) + { + x = (double)(-maxX/2.0); + y = 0.0; + wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y, + CONTROL_POINT_HORIZONTAL); + m_canvas->AddShape(control); + m_controlPoints.Append(control); + } + if (m_topSide) + { + x = 0.0; + y = (double)(-maxY/2.0); + wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y, + CONTROL_POINT_VERTICAL); + m_canvas->AddShape(control); + m_controlPoints.Append(control); + } +*/ + switch (m_handleSide) + { + case DIVISION_SIDE_LEFT: + { + x = (double)(-maxX/2.0); + y = 0.0; + direction = CONTROL_POINT_HORIZONTAL; + break; + } + case DIVISION_SIDE_TOP: + { + x = 0.0; + y = (double)(-maxY/2.0); + direction = CONTROL_POINT_VERTICAL; + break; + } + case DIVISION_SIDE_RIGHT: + { + x = (double)(maxX/2.0); + y = 0.0; + direction = CONTROL_POINT_HORIZONTAL; + break; + } + case DIVISION_SIDE_BOTTOM: + { + x = 0.0; + y = (double)(maxY/2.0); + direction = CONTROL_POINT_VERTICAL; + break; + } + default: + break; + } + if (m_handleSide != DIVISION_SIDE_NONE) + { + wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y, + direction); + m_canvas->AddShape(control); + m_controlPoints.Append(control); + } +} + +void wxDivisionShape::ResetControlPoints() +{ + ResetMandatoryControlPoints(); +} + +void wxDivisionShape::ResetMandatoryControlPoints() +{ + if (m_controlPoints.Number() < 1) + return; + + double maxX, maxY; + + GetBoundingBoxMax(&maxX, &maxY); +/* + wxNode *node = m_controlPoints.First(); + while (node) + { + wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data(); + if (control->type == CONTROL_POINT_HORIZONTAL) + { + control->xoffset = (double)(-maxX/2.0); control->m_yoffset = 0.0; + } + else if (control->type == CONTROL_POINT_VERTICAL) + { + control->xoffset = 0.0; control->m_yoffset = (double)(-maxY/2.0); + } + node = node->Next(); + } +*/ + wxNode *node = m_controlPoints.First(); + if ((m_handleSide == DIVISION_SIDE_LEFT) && node) + { + wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data(); + control->m_xoffset = (double)(-maxX/2.0); control->m_yoffset = 0.0; + } + + if ((m_handleSide == DIVISION_SIDE_TOP) && node) + { + wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data(); + control->m_xoffset = 0.0; control->m_yoffset = (double)(-maxY/2.0); + } + + if ((m_handleSide == DIVISION_SIDE_RIGHT) && node) + { + wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data(); + control->m_xoffset = (double)(maxX/2.0); control->m_yoffset = 0.0; + } + + if ((m_handleSide == DIVISION_SIDE_BOTTOM) && node) + { + wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data(); + control->m_xoffset = 0.0; control->m_yoffset = (double)(maxY/2.0); + } +} + +// Adjust a side, returning FALSE if it's not physically possible. +bool wxDivisionShape::AdjustLeft(double left, bool test) +{ + double x2 = (double)(GetX() + (GetWidth()/2.0)); + + if (left >= x2) + return FALSE; + if (test) + return TRUE; + + double newW = x2 - left; + double newX = (double)(left + newW/2.0); + SetSize(newW, GetHeight()); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + Move(dc, newX, GetY()); + + return TRUE; +} + +bool wxDivisionShape::AdjustTop(double top, bool test) +{ + double y2 = (double)(GetY() + (GetHeight()/2.0)); + + if (top >= y2) + return FALSE; + if (test) + return TRUE; + + double newH = y2 - top; + double newY = (double)(top + newH/2.0); + SetSize(GetWidth(), newH); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + Move(dc, GetX(), newY); + + return TRUE; +} + +bool wxDivisionShape::AdjustRight(double right, bool test) +{ + double x1 = (double)(GetX() - (GetWidth()/2.0)); + + if (right <= x1) + return FALSE; + if (test) + return TRUE; + + double newW = right - x1; + double newX = (double)(x1 + newW/2.0); + SetSize(newW, GetHeight()); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + Move(dc, newX, GetY()); + + return TRUE; +} + +bool wxDivisionShape::AdjustBottom(double bottom, bool test) +{ + double y1 = (double)(GetY() - (GetHeight()/2.0)); + + if (bottom <= y1) + return FALSE; + if (test) + return TRUE; + + double newH = bottom - y1; + double newY = (double)(y1 + newH/2.0); + SetSize(GetWidth(), newH); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + Move(dc, GetX(), newY); + + return TRUE; +} + +wxDivisionControlPoint::wxDivisionControlPoint(wxShapeCanvas *the_canvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type): + wxControlPoint(the_canvas, object, size, the_xoffset, the_yoffset, the_type) +{ + SetEraseObject(FALSE); +} + +wxDivisionControlPoint::~wxDivisionControlPoint() +{ +} + +static double originalX = 0.0; +static double originalY = 0.0; +static double originalW = 0.0; +static double originalH = 0.0; + +// Implement resizing of canvas object +void wxDivisionControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment) +{ + wxControlPoint::OnDragLeft(draw, x, y, keys, attachment); +} + +void wxDivisionControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment) +{ + wxDivisionShape *division = (wxDivisionShape *)m_shape; + originalX = division->GetX(); + originalY = division->GetY(); + originalW = division->GetWidth(); + originalH = division->GetHeight(); + + wxControlPoint::OnBeginDragLeft(x, y, keys, attachment); +} + +void wxDivisionControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment) +{ + wxControlPoint::OnEndDragLeft(x, y, keys, attachment); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + wxDivisionShape *division = (wxDivisionShape *)m_shape; + wxCompositeShape *divisionParent = (wxCompositeShape *)division->GetParent(); + + // Need to check it's within the bounds of the parent composite. + double x1 = (double)(divisionParent->GetX() - (divisionParent->GetWidth()/2.0)); + double y1 = (double)(divisionParent->GetY() - (divisionParent->GetHeight()/2.0)); + double x2 = (double)(divisionParent->GetX() + (divisionParent->GetWidth()/2.0)); + double y2 = (double)(divisionParent->GetY() + (divisionParent->GetHeight()/2.0)); + + // Need to check it has not made the division zero or negative width/height + double dx1 = (double)(division->GetX() - (division->GetWidth()/2.0)); + double dy1 = (double)(division->GetY() - (division->GetHeight()/2.0)); + double dx2 = (double)(division->GetX() + (division->GetWidth()/2.0)); + double dy2 = (double)(division->GetY() + (division->GetHeight()/2.0)); + + bool success = TRUE; + switch (division->GetHandleSide()) + { + case DIVISION_SIDE_LEFT: + { + if ((x <= x1) || (x >= x2) || (x >= dx2)) + success = FALSE; + // Try it out first... + else if (!division->ResizeAdjoining(DIVISION_SIDE_LEFT, x, TRUE)) + success = FALSE; + else + division->ResizeAdjoining(DIVISION_SIDE_LEFT, x, FALSE); + + break; + } + case DIVISION_SIDE_TOP: + { + if ((y <= y1) || (y >= y2) || (y >= dy2)) + success = FALSE; + else if (!division->ResizeAdjoining(DIVISION_SIDE_TOP, y, TRUE)) + success = FALSE; + else + division->ResizeAdjoining(DIVISION_SIDE_TOP, y, FALSE); + + break; + } + case DIVISION_SIDE_RIGHT: + { + if ((x <= x1) || (x >= x2) || (x <= dx1)) + success = FALSE; + else if (!division->ResizeAdjoining(DIVISION_SIDE_RIGHT, x, TRUE)) + success = FALSE; + else + division->ResizeAdjoining(DIVISION_SIDE_RIGHT, x, FALSE); + + break; + } + case DIVISION_SIDE_BOTTOM: + { + if ((y <= y1) || (y >= y2) || (y <= dy1)) + success = FALSE; + else if (!division->ResizeAdjoining(DIVISION_SIDE_BOTTOM, y, TRUE)) + success = FALSE; + else + division->ResizeAdjoining(DIVISION_SIDE_BOTTOM, y, FALSE); + + break; + } + } + if (!success) + { + division->SetSize(originalW, originalH); + division->Move(dc, originalX, originalY); + } + divisionParent->Draw(dc); + division->GetEventHandler()->OnDrawControlPoints(dc); +} + +/* Resize adjoining divisions. + * + Behaviour should be as follows: + If right edge moves, find all objects whose left edge + adjoins this object, and move left edge accordingly. + If left..., move ... right. + If top..., move ... bottom. + If bottom..., move top. + If size goes to zero or end position is other side of start position, + resize to original size and return. + */ +bool wxDivisionShape::ResizeAdjoining(int side, double newPos, bool test) +{ + wxCompositeShape *divisionParent = (wxCompositeShape *)GetParent(); + wxNode *node = divisionParent->GetDivisions().First(); + while (node) + { + wxDivisionShape *division = (wxDivisionShape *)node->Data(); + switch (side) + { + case DIVISION_SIDE_LEFT: + { + if (division->m_rightSide == this) + { + bool success = division->AdjustRight(newPos, test); + if (!success && test) + return FALSE; + } + break; + } + case DIVISION_SIDE_TOP: + { + if (division->m_bottomSide == this) + { + bool success = division->AdjustBottom(newPos, test); + if (!success && test) + return FALSE; + } + break; + } + case DIVISION_SIDE_RIGHT: + { + if (division->m_leftSide == this) + { + bool success = division->AdjustLeft(newPos, test); + if (!success && test) + return FALSE; + } + break; + } + case DIVISION_SIDE_BOTTOM: + { + if (division->m_topSide == this) + { + bool success = division->AdjustTop(newPos, test); + if (!success && test) + return FALSE; + } + break; + } + default: + break; + } + node = node->Next(); + } + + return TRUE; +} + +/* + * Popup menu for editing divisions + * + */ +class OGLPopupDivisionMenu : public wxMenu { +public: + OGLPopupDivisionMenu() : wxMenu() { + Append(DIVISION_MENU_SPLIT_HORIZONTALLY, "Split horizontally"); + Append(DIVISION_MENU_SPLIT_VERTICALLY, "Split vertically"); + AppendSeparator(); + Append(DIVISION_MENU_EDIT_LEFT_EDGE, "Edit left edge"); + Append(DIVISION_MENU_EDIT_TOP_EDGE, "Edit top edge"); + } + + void OnMenu(wxCommandEvent& event); + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(OGLPopupDivisionMenu, wxMenu) + EVT_CUSTOM_RANGE(wxEVT_COMMAND_MENU_SELECTED, + DIVISION_MENU_SPLIT_HORIZONTALLY, + DIVISION_MENU_EDIT_BOTTOM_EDGE, + OGLPopupDivisionMenu::OnMenu) +END_EVENT_TABLE() + + +void OGLPopupDivisionMenu::OnMenu(wxCommandEvent& event) +{ + wxDivisionShape *division = (wxDivisionShape *)GetClientData(); + switch (event.GetInt()) + { + case DIVISION_MENU_SPLIT_HORIZONTALLY: + { + division->Divide(wxHORIZONTAL); + break; + } + case DIVISION_MENU_SPLIT_VERTICALLY: + { + division->Divide(wxVERTICAL); + break; + } + case DIVISION_MENU_EDIT_LEFT_EDGE: + { + division->EditEdge(DIVISION_SIDE_LEFT); + break; + } + case DIVISION_MENU_EDIT_TOP_EDGE: + { + division->EditEdge(DIVISION_SIDE_TOP); + break; + } + default: + break; + } +} + +void wxDivisionShape::EditEdge(int side) +{ + wxMessageBox("EditEdge() not implemented", "OGL", wxOK); + +#if 0 + wxBeginBusyCursor(); + + wxPen *currentPen = NULL; + char **pColour = NULL; + char **pStyle = NULL; + if (side == DIVISION_SIDE_LEFT) + { + currentPen = m_leftSidePen; + pColour = &m_leftSideColour; + pStyle = &m_leftSideStyle; + } + else + { + currentPen = m_topSidePen; + pColour = &m_topSideColour; + pStyle = &m_topSideStyle; + } + + GraphicsForm *form = new GraphicsForm("Containers"); + int lineWidth = currentPen->GetWidth(); + + form->Add(wxMakeFormShort("Width", &lineWidth, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL, + 150)); + form->Add(wxMakeFormString("Colour", pColour, wxFORM_CHOICE, + new wxList(wxMakeConstraintStrings( + "BLACK" , + "BLUE" , + "BROWN" , + "CORAL" , + "CYAN" , + "DARK GREY" , + "DARK GREEN" , + "DIM GREY" , + "GREY" , + "GREEN" , + "LIGHT BLUE" , + "LIGHT GREY" , + "MAGENTA" , + "MAROON" , + "NAVY" , + "ORANGE" , + "PURPLE" , + "RED" , + "TURQUOISE" , + "VIOLET" , + "WHITE" , + "YELLOW" , + NULL), + NULL), NULL, wxVERTICAL, 150)); + form->Add(wxMakeFormString("Style", pStyle, wxFORM_CHOICE, + new wxList(wxMakeConstraintStrings( + "Solid" , + "Short Dash" , + "Long Dash" , + "Dot" , + "Dot Dash" , + NULL), + NULL), NULL, wxVERTICAL, 100)); + + wxDialogBox *dialog = new wxDialogBox(m_canvas->GetParent(), "Division properties", 10, 10, 500, 500); + if (GraphicsLabelFont) + dialog->SetLabelFont(GraphicsLabelFont); + if (GraphicsButtonFont) + dialog->SetButtonFont(GraphicsButtonFont); + + form->AssociatePanel(dialog); + form->dialog = dialog; + + dialog->Fit(); + dialog->Centre(wxBOTH); + + wxEndBusyCursor(); + dialog->Show(TRUE); + + int lineStyle = wxSOLID; + if (*pStyle) + { + if (strcmp(*pStyle, "Solid") == 0) + lineStyle = wxSOLID; + else if (strcmp(*pStyle, "Dot") == 0) + lineStyle = wxDOT; + else if (strcmp(*pStyle, "Short Dash") == 0) + lineStyle = wxSHORT_DASH; + else if (strcmp(*pStyle, "Long Dash") == 0) + lineStyle = wxLONG_DASH; + else if (strcmp(*pStyle, "Dot Dash") == 0) + lineStyle = wxDOT_DASH; + } + + wxPen *newPen = wxThePenList->FindOrCreatePen(*pColour, lineWidth, lineStyle); + if (!pen) + pen = wxBLACK_PEN; + if (side == DIVISION_SIDE_LEFT) + m_leftSidePen = newPen; + else + m_topSidePen = newPen; + + // Need to draw whole image again + wxCompositeShape *compositeParent = (wxCompositeShape *)GetParent(); + compositeParent->Draw(dc); +#endif +} + +// Popup menu +void wxDivisionShape::PopupMenu(double x, double y) +{ + wxMenu* oglPopupDivisionMenu = new OGLPopupDivisionMenu; + + oglPopupDivisionMenu->SetClientData((void *)this); + if (m_leftSide) + oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_LEFT_EDGE, TRUE); + else + oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_LEFT_EDGE, FALSE); + if (m_topSide) + oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_TOP_EDGE, TRUE); + else + oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_TOP_EDGE, FALSE); + + int x1, y1; + m_canvas->ViewStart(&x1, &y1); + + int unit_x, unit_y; + m_canvas->GetScrollPixelsPerUnit(&unit_x, &unit_y); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + int mouse_x = (int)(dc.LogicalToDeviceX((long)(x - x1*unit_x))); + int mouse_y = (int)(dc.LogicalToDeviceY((long)(y - y1*unit_y))); + + m_canvas->PopupMenu(oglPopupDivisionMenu, mouse_x, mouse_y); + delete oglPopupDivisionMenu; +} + +void wxDivisionShape::SetLeftSideColour(const wxString& colour) +{ + m_leftSideColour = colour; +} + +void wxDivisionShape::SetTopSideColour(const wxString& colour) +{ + m_topSideColour = colour; +} + +void wxDivisionShape::SetLeftSideStyle(const wxString& style) +{ + m_leftSideStyle = style; +} + +void wxDivisionShape::SetTopSideStyle(const wxString& style) +{ + m_topSideStyle = style; +} + diff --git a/src/ogl/constrnt.cpp b/src/ogl/constrnt.cpp new file mode 100644 index 0000000000..ed2562b2ab --- /dev/null +++ b/src/ogl/constrnt.cpp @@ -0,0 +1,619 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: constrnt.cpp +// Purpose: OGL Constraint classes +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "constrnt.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#include +#include +#include + +wxList *wxOGLConstraintTypes = NULL; + +/* + * Constraint type + * + */ + +IMPLEMENT_DYNAMIC_CLASS(wxOGLConstraintType, wxObject) + +wxOGLConstraintType::wxOGLConstraintType(int theType, const wxString& theName, const wxString& thePhrase) +{ + m_type = theType; + m_name = theName; + m_phrase = thePhrase; +} + +wxOGLConstraintType::~wxOGLConstraintType() +{ +} + +void OGLInitializeConstraintTypes() +{ + if (!wxOGLConstraintTypes) + return; + + wxOGLConstraintTypes = new wxList(wxKEY_INTEGER); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_CENTRED_VERTICALLY, + new wxOGLConstraintType(gyCONSTRAINT_CENTRED_VERTICALLY, "Centre vertically", "centred vertically w.r.t.")); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_CENTRED_HORIZONTALLY, + new wxOGLConstraintType(gyCONSTRAINT_CENTRED_HORIZONTALLY, "Centre horizontally", "centred horizontally w.r.t.")); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_CENTRED_BOTH, + new wxOGLConstraintType(gyCONSTRAINT_CENTRED_BOTH, "Centre", "centred w.r.t.")); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_LEFT_OF, + new wxOGLConstraintType(gyCONSTRAINT_LEFT_OF, "Left of", "left of")); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_RIGHT_OF, + new wxOGLConstraintType(gyCONSTRAINT_RIGHT_OF, "Right of", "right of")); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_ABOVE, + new wxOGLConstraintType(gyCONSTRAINT_ABOVE, "Above", "above")); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_BELOW, + new wxOGLConstraintType(gyCONSTRAINT_BELOW, "Below", "below")); + + // Alignment + wxOGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_TOP, + new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_TOP, "Top-aligned", "aligned to the top of")); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_BOTTOM, + new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_BOTTOM, "Bottom-aligned", "aligned to the bottom of")); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_LEFT, + new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_LEFT, "Left-aligned", "aligned to the left of")); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_ALIGNED_RIGHT, + new wxOGLConstraintType(gyCONSTRAINT_ALIGNED_RIGHT, "Right-aligned", "aligned to the right of")); + + // Mid-alignment + wxOGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_TOP, + new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_TOP, "Top-midaligned", "centred on the top of")); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_BOTTOM, + new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_BOTTOM, "Bottom-midaligned", "centred on the bottom of")); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_LEFT, + new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_LEFT, "Left-midaligned", "centred on the left of")); + + wxOGLConstraintTypes->Append(gyCONSTRAINT_MIDALIGNED_RIGHT, + new wxOGLConstraintType(gyCONSTRAINT_MIDALIGNED_RIGHT, "Right-midaligned", "centred on the right of")); +} + +void OGLCleanUpConstraintTypes() +{ + if (!wxOGLConstraintTypes) + return; + + wxNode* node = wxOGLConstraintTypes->First(); + while (node) + { + wxOGLConstraintType* ct = (wxOGLConstraintType*) node->Data(); + delete ct; + node = node->Next(); + } + delete wxOGLConstraintTypes; + wxOGLConstraintTypes = NULL; +} + +/* + * Constraint Stuff + * + */ + +IMPLEMENT_DYNAMIC_CLASS(wxOGLConstraint, wxObject) + +wxOGLConstraint::wxOGLConstraint(int type, wxShape *constraining, wxList& constrained) +{ + m_xSpacing = 0.0; + m_ySpacing = 0.0; + + m_constraintType = type; + m_constrainingObject = constraining; + + m_constraintId = 0; + m_constraintName = "noname"; + + wxNode *node = constrained.First(); + while (node) + { + m_constrainedObjects.Append(node->Data()); + node = node->Next(); + } +} + +wxOGLConstraint::~wxOGLConstraint() +{ +} + +bool wxOGLConstraint::Equals(double a, double b) +{ + double marg = 0.5; + + bool eq = ((b <= a + marg) && (b >= a - marg)); + return eq; +} + +// Return TRUE if anything changed +bool wxOGLConstraint::Evaluate() +{ + double maxWidth, maxHeight, minWidth, minHeight, x, y; + m_constrainingObject->GetBoundingBoxMax(&maxWidth, &maxHeight); + m_constrainingObject->GetBoundingBoxMin(&minWidth, &minHeight); + x = m_constrainingObject->GetX(); + y = m_constrainingObject->GetY(); + + wxClientDC dc(m_constrainingObject->GetCanvas()); + m_constrainingObject->GetCanvas()->PrepareDC(dc); + + switch (m_constraintType) + { + case gyCONSTRAINT_CENTRED_VERTICALLY: + { + int n = m_constrainedObjects.Number(); + double totalObjectHeight = 0.0; + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + totalObjectHeight += height2; + node = node->Next(); + } + double startY; + double spacingY; + // Check if within the constraining object... + if ((totalObjectHeight + (n + 1)*m_ySpacing) <= minHeight) + { + spacingY = (double)((minHeight - totalObjectHeight)/(n + 1)); + startY = (double)(y - (minHeight/2.0)); + } + // Otherwise, use default spacing + else + { + spacingY = m_ySpacing; + startY = (double)(y - ((totalObjectHeight + (n+1)*spacingY)/2.0)); + } + + // Now position the objects + bool changed = FALSE; + node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + startY += (double)(spacingY + (height2/2.0)); + if (!Equals(startY, constrainedObject->GetY())) + { + constrainedObject->Move(dc, constrainedObject->GetX(), startY, FALSE); + changed = TRUE; + } + startY += (double)(height2/2.0); + node = node->Next(); + } + return changed; + } + case gyCONSTRAINT_CENTRED_HORIZONTALLY: + { + int n = m_constrainedObjects.Number(); + double totalObjectWidth = 0.0; + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + totalObjectWidth += width2; + node = node->Next(); + } + double startX; + double spacingX; + // Check if within the constraining object... + if ((totalObjectWidth + (n + 1)*m_xSpacing) <= minWidth) + { + spacingX = (double)((minWidth - totalObjectWidth)/(n + 1)); + startX = (double)(x - (minWidth/2.0)); + } + // Otherwise, use default spacing + else + { + spacingX = m_xSpacing; + startX = (double)(x - ((totalObjectWidth + (n+1)*spacingX)/2.0)); + } + + // Now position the objects + bool changed = FALSE; + node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + startX += (double)(spacingX + (width2/2.0)); + if (!Equals(startX, constrainedObject->GetX())) + { + constrainedObject->Move(dc, startX, constrainedObject->GetY(), FALSE); + changed = TRUE; + } + startX += (double)(width2/2.0); + node = node->Next(); + } + return changed; + } + case gyCONSTRAINT_CENTRED_BOTH: + { + int n = m_constrainedObjects.Number(); + double totalObjectWidth = 0.0; + double totalObjectHeight = 0.0; + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + totalObjectWidth += width2; + totalObjectHeight += height2; + node = node->Next(); + } + double startX; + double spacingX; + double startY; + double spacingY; + + // Check if within the constraining object... + if ((totalObjectWidth + (n + 1)*m_xSpacing) <= minWidth) + { + spacingX = (double)((minWidth - totalObjectWidth)/(n + 1)); + startX = (double)(x - (minWidth/2.0)); + } + // Otherwise, use default spacing + else + { + spacingX = m_xSpacing; + startX = (double)(x - ((totalObjectWidth + (n+1)*spacingX)/2.0)); + } + + // Check if within the constraining object... + if ((totalObjectHeight + (n + 1)*m_ySpacing) <= minHeight) + { + spacingY = (double)((minHeight - totalObjectHeight)/(n + 1)); + startY = (double)(y - (minHeight/2.0)); + } + // Otherwise, use default spacing + else + { + spacingY = m_ySpacing; + startY = (double)(y - ((totalObjectHeight + (n+1)*spacingY)/2.0)); + } + + // Now position the objects + bool changed = FALSE; + node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + startX += (double)(spacingX + (width2/2.0)); + startY += (double)(spacingY + (height2/2.0)); + + if ((!Equals(startX, constrainedObject->GetX())) || (!Equals(startY, constrainedObject->GetY()))) + { + constrainedObject->Move(dc, startX, startY, FALSE); + changed = TRUE; + } + + startX += (double)(width2/2.0); + startY += (double)(height2/2.0); + + node = node->Next(); + } + return changed; + } + case gyCONSTRAINT_LEFT_OF: + { + bool changed = FALSE; + + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + + double x3 = (double)(x - (minWidth/2.0) - (width2/2.0) - m_xSpacing); + if (!Equals(x3, constrainedObject->GetX())) + { + changed = TRUE; + constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE); + } + + node = node->Next(); + } + return changed; + } + case gyCONSTRAINT_RIGHT_OF: + { + bool changed = FALSE; + + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + + double x3 = (double)(x + (minWidth/2.0) + (width2/2.0) + m_xSpacing); + if (!Equals(x3, constrainedObject->GetX())) + { + changed = TRUE; + constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE); + } + + node = node->Next(); + } + return changed; + + return FALSE; + } + case gyCONSTRAINT_ABOVE: + { + bool changed = FALSE; + + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + + double y3 = (double)(y - (minHeight/2.0) - (height2/2.0) - m_ySpacing); + if (!Equals(y3, constrainedObject->GetY())) + { + changed = TRUE; + constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE); + } + + node = node->Next(); + } + return changed; + } + case gyCONSTRAINT_BELOW: + { + bool changed = FALSE; + + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + + double y3 = (double)(y + (minHeight/2.0) + (height2/2.0) + m_ySpacing); + if (!Equals(y3, constrainedObject->GetY())) + { + changed = TRUE; + constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE); + } + + node = node->Next(); + } + return changed; + } + case gyCONSTRAINT_ALIGNED_LEFT: + { + bool changed = FALSE; + + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + + double x3 = (double)(x - (minWidth/2.0) + (width2/2.0) + m_xSpacing); + if (!Equals(x3, constrainedObject->GetX())) + { + changed = TRUE; + constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE); + } + + node = node->Next(); + } + return changed; + } + case gyCONSTRAINT_ALIGNED_RIGHT: + { + bool changed = FALSE; + + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + + double x3 = (double)(x + (minWidth/2.0) - (width2/2.0) - m_xSpacing); + if (!Equals(x3, constrainedObject->GetX())) + { + changed = TRUE; + constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE); + } + + node = node->Next(); + } + return changed; + + return FALSE; + } + case gyCONSTRAINT_ALIGNED_TOP: + { + bool changed = FALSE; + + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + + double y3 = (double)(y - (minHeight/2.0) + (height2/2.0) + m_ySpacing); + if (!Equals(y3, constrainedObject->GetY())) + { + changed = TRUE; + constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE); + } + + node = node->Next(); + } + return changed; + } + case gyCONSTRAINT_ALIGNED_BOTTOM: + { + bool changed = FALSE; + + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double width2, height2; + constrainedObject->GetBoundingBoxMax(&width2, &height2); + + double y3 = (double)(y + (minHeight/2.0) - (height2/2.0) - m_ySpacing); + if (!Equals(y3, constrainedObject->GetY())) + { + changed = TRUE; + constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE); + } + + node = node->Next(); + } + return changed; + } + case gyCONSTRAINT_MIDALIGNED_LEFT: + { + bool changed = FALSE; + + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double x3 = (double)(x - (minWidth/2.0)); + if (!Equals(x3, constrainedObject->GetX())) + { + changed = TRUE; + constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE); + } + + node = node->Next(); + } + return changed; + } + case gyCONSTRAINT_MIDALIGNED_RIGHT: + { + bool changed = FALSE; + + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double x3 = (double)(x + (minWidth/2.0)); + if (!Equals(x3, constrainedObject->GetX())) + { + changed = TRUE; + constrainedObject->Move(dc, x3, constrainedObject->GetY(), FALSE); + } + + node = node->Next(); + } + return changed; + + return FALSE; + } + case gyCONSTRAINT_MIDALIGNED_TOP: + { + bool changed = FALSE; + + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double y3 = (double)(y - (minHeight/2.0)); + if (!Equals(y3, constrainedObject->GetY())) + { + changed = TRUE; + constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE); + } + + node = node->Next(); + } + return changed; + } + case gyCONSTRAINT_MIDALIGNED_BOTTOM: + { + bool changed = FALSE; + + wxNode *node = m_constrainedObjects.First(); + while (node) + { + wxShape *constrainedObject = (wxShape *)node->Data(); + + double y3 = (double)(y + (minHeight/2.0)); + if (!Equals(y3, constrainedObject->GetY())) + { + changed = TRUE; + constrainedObject->Move(dc, constrainedObject->GetX(), y3, FALSE); + } + + node = node->Next(); + } + return changed; + } + + default: + return FALSE; + } + return FALSE; +} + diff --git a/src/ogl/divided.cpp b/src/ogl/divided.cpp new file mode 100644 index 0000000000..8f66677315 --- /dev/null +++ b/src/ogl/divided.cpp @@ -0,0 +1,720 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: divided.cpp +// Purpose: wxDividedShape class +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "divided.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include + +class wxDividedShapeControlPoint: public wxControlPoint +{ + DECLARE_DYNAMIC_CLASS(wxDividedShapeControlPoint) + private: + int regionId; + public: + wxDividedShapeControlPoint() { regionId = 0; } + wxDividedShapeControlPoint(wxShapeCanvas *the_canvas, wxShape *object, int region, + double size, double the_xoffset, double the_yoffset, int the_type); + ~wxDividedShapeControlPoint(); + + 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); +}; + +IMPLEMENT_DYNAMIC_CLASS(wxDividedShapeControlPoint, wxControlPoint) + +/* + * Divided object + * + */ + +IMPLEMENT_DYNAMIC_CLASS(wxDividedShape, wxRectangleShape) + +wxDividedShape::wxDividedShape(double w, double h): wxRectangleShape(w, h) +{ + ClearRegions(); +} + +wxDividedShape::~wxDividedShape() +{ +} + +void wxDividedShape::OnDraw(wxDC& dc) +{ + wxRectangleShape::OnDraw(dc); +} + +void wxDividedShape::OnDrawContents(wxDC& dc) +{ + double defaultProportion = (double)(GetRegions().Number() > 0 ? (1.0/((double)(GetRegions().Number()))) : 0.0); + double currentY = (double)(m_ypos - (m_height / 2.0)); + double maxY = (double)(m_ypos + (m_height / 2.0)); + + double leftX = (double)(m_xpos - (m_width / 2.0)); + double rightX = (double)(m_xpos + (m_width / 2.0)); + + if (m_pen) dc.SetPen(* m_pen); + + if (m_textColour) dc.SetTextForeground(* m_textColour); + +#ifdef __WXMSW__ + // For efficiency, don't do this under X - doesn't make + // any visible difference for our purposes. + if (m_brush) + dc.SetTextBackground(m_brush->GetColour()); +#endif +/* + if (!formatted) + { + FormatRegionText(); + formatted = TRUE; + } +*/ + if (GetDisableLabel()) return; + + double xMargin = 2; + double yMargin = 2; + dc.SetBackgroundMode(wxTRANSPARENT); + + wxNode *node = GetRegions().First(); + while (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + dc.SetFont(* region->GetFont()); + dc.SetTextForeground(* region->GetActualColourObject()); + + double proportion = + region->m_regionProportionY < 0.0 ? defaultProportion : region->m_regionProportionY; + + double y = currentY + m_height*proportion; + double actualY = maxY < y ? maxY : y; + + double centreX = m_xpos; + double centreY = (double)(currentY + (actualY - currentY)/2.0); + + oglDrawFormattedText(dc, ®ion->m_formattedText, + (double)(centreX), (double)(centreY), (double)(m_width-2*xMargin), (double)(actualY - currentY - 2*yMargin), + region->m_formatMode); + if ((y <= maxY) && (node->Next())) + { + wxPen *regionPen = region->GetActualPen(); + if (regionPen) + { + dc.SetPen(* regionPen); + dc.DrawLine(WXROUND(leftX), WXROUND(y), WXROUND(rightX), WXROUND(y)); + } + } + + currentY = actualY; + + node = node->Next(); + } +} + +void wxDividedShape::SetSize(double w, double h, bool recursive) +{ + SetAttachmentSize(w, h); + m_width = w; + m_height = h; + SetRegionSizes(); +} + +void wxDividedShape::SetRegionSizes() +{ + if (GetRegions().Number() == 0) + return; + + double defaultProportion = (double)(GetRegions().Number() > 0 ? (1.0/((double)(GetRegions().Number()))) : 0.0); + double currentY = (double)(m_ypos - (m_height / 2.0)); + double maxY = (double)(m_ypos + (m_height / 2.0)); + +// double leftX = (double)(m_xpos - (m_width / 2.0)); +// double rightX = (double)(m_xpos + (m_width / 2.0)); + + wxNode *node = GetRegions().First(); + while (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + double proportion = + region->m_regionProportionY <= 0.0 ? defaultProportion : region->m_regionProportionY; + + double sizeY = (double)proportion*m_height; + double y = currentY + sizeY; + double actualY = maxY < y ? maxY : y; + + double centreY = (double)(currentY + (actualY - currentY)/2.0); + + region->SetSize(m_width, sizeY); + region->SetPosition(0.0, (double)(centreY - m_ypos)); + currentY = actualY; + node = node->Next(); + } +} + +// Attachment points correspond to regions in the divided box +bool wxDividedShape::GetAttachmentPosition(int attachment, double *x, double *y, int nth, int no_arcs, + wxLineShape *line) +{ + int totalNumberAttachments = (GetRegions().Number() * 2) + 2; + if ((GetAttachmentMode() == ATTACHMENT_MODE_NONE) || (attachment >= totalNumberAttachments)) + { + return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs); + } + + int n = GetRegions().Number(); + bool isEnd = (line && line->IsEnd(this)); + + double left = (double)(m_xpos - m_width/2.0); + double right = (double)(m_xpos + m_width/2.0); + double top = (double)(m_ypos - m_height/2.0); + double bottom = (double)(m_ypos + m_height/2.0); + + // Zero is top, n+1 is bottom. + if (attachment == 0) + { + *y = top; + if (m_spaceAttachments) + { + if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE)) + { + // Align line according to the next handle along + wxRealPoint *point = line->GetNextControlPoint(this); + if (point->x < left) + *x = left; + else if (point->x > right) + *x = right; + else + *x = point->x; + } + else + *x = left + (nth + 1)*m_width/(no_arcs + 1); + } + else + *x = m_xpos; + } + else if (attachment == (n+1)) + { + *y = bottom; + if (m_spaceAttachments) + { + if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE)) + { + // Align line according to the next handle along + wxRealPoint *point = line->GetNextControlPoint(this); + if (point->x < left) + *x = left; + else if (point->x > right) + *x = right; + else + *x = point->x; + } + else + *x = left + (nth + 1)*m_width/(no_arcs + 1); + } + else + *x = m_xpos; + } + // Left or right. + else + { + int i = 0; + bool isLeft = FALSE; + if (attachment < (n+1)) + { + i = attachment-1; + isLeft = FALSE; + } + else + { + i = (totalNumberAttachments - attachment - 1); + isLeft = TRUE; + } + wxNode *node = GetRegions().Nth(i); + if (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + + if (isLeft) + *x = left; + else + *x = right; + + // Calculate top and bottom of region + top = (double)((m_ypos + region->m_y) - (region->m_height/2.0)); + bottom = (double)((m_ypos + region->m_y) + (region->m_height/2.0)); + + // Assuming we can trust the absolute size and + // position of these regions... + if (m_spaceAttachments) + { + if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE)) + { + // Align line according to the next handle along + wxRealPoint *point = line->GetNextControlPoint(this); + if (point->y < bottom) + *y = bottom; + else if (point->y > top) + *y = top; + else + *y = point->y; + } + else +// *y = (double)(((m_ypos + region->m_y) - (region->m_height/2.0)) + (nth + 1)*region->m_height/(no_arcs+1)); + *y = (double)(top + (nth + 1)*region->m_height/(no_arcs+1)); + } + else + *y = (double)(m_ypos + region->m_y); + } + else + { + *x = m_xpos; + *y = m_ypos; + return FALSE; + } + } + return TRUE; +} + +int wxDividedShape::GetNumberOfAttachments() const +{ + // There are two attachments for each region (left and right), + // plus one on the top and one on the bottom. + int n = (GetRegions().Number() * 2) + 2; + + int maxN = n - 1; + wxNode *node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + if (point->m_id > maxN) + maxN = point->m_id; + node = node->Next(); + } + return maxN + 1; +} + +bool wxDividedShape::AttachmentIsValid(int attachment) +{ + int totalNumberAttachments = (GetRegions().Number() * 2) + 2; + if (attachment >= totalNumberAttachments) + { + return wxShape::AttachmentIsValid(attachment); + } + else if (attachment >= 0) + return TRUE; + else + return FALSE; +} + +void wxDividedShape::Copy(wxShape& copy) +{ + wxRectangleShape::Copy(copy); +} + +// Region operations + +void wxDividedShape::MakeControlPoints() +{ + wxRectangleShape::MakeControlPoints(); + + MakeMandatoryControlPoints(); +} + +void wxDividedShape::MakeMandatoryControlPoints() +{ + double currentY = (double)(GetY() - (m_height / 2.0)); + double maxY = (double)(GetY() + (m_height / 2.0)); + + wxNode *node = GetRegions().First(); + int i = 0; + while (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + + double proportion = region->m_regionProportionY; + + double y = currentY + m_height*proportion; + double actualY = (double)(maxY < y ? maxY : y); + + if (node->Next()) + { + wxDividedShapeControlPoint *controlPoint = + new wxDividedShapeControlPoint(m_canvas, this, i, CONTROL_POINT_SIZE, 0.0, (double)(actualY - GetY()), 0); + m_canvas->AddShape(controlPoint); + m_controlPoints.Append(controlPoint); + } + currentY = actualY; + i ++; + node = node->Next(); + } +} + +void wxDividedShape::ResetControlPoints() +{ + // May only have the region handles, (n - 1) of them. + if (m_controlPoints.Number() > (GetRegions().Number() - 1)) + wxRectangleShape::ResetControlPoints(); + + ResetMandatoryControlPoints(); +} + +void wxDividedShape::ResetMandatoryControlPoints() +{ + double currentY = (double)(GetY() - (m_height / 2.0)); + double maxY = (double)(GetY() + (m_height / 2.0)); + + wxNode *node = m_controlPoints.First(); + int i = 0; + while (node) + { + wxControlPoint *controlPoint = (wxControlPoint *)node->Data(); + if (controlPoint->IsKindOf(CLASSINFO(wxDividedShapeControlPoint))) + { + wxNode *node1 = GetRegions().Nth(i); + wxShapeRegion *region = (wxShapeRegion *)node1->Data(); + + double proportion = region->m_regionProportionY; + + double y = currentY + m_height*proportion; + double actualY = (double)(maxY < y ? maxY : y); + + controlPoint->m_xoffset = 0.0; + controlPoint->m_yoffset = (double)(actualY - GetY()); + currentY = actualY; + i ++; + } + node = node->Next(); + } +} + +#ifdef PROLOGIO +void wxDividedShape::WriteAttributes(wxExpr *clause) +{ + wxRectangleShape::WriteAttributes(clause); +} + +void wxDividedShape::ReadAttributes(wxExpr *clause) +{ + wxRectangleShape::ReadAttributes(clause); +} +#endif + +/* + * Edit the division colour/style + * + */ + +void wxDividedShape::EditRegions() +{ + wxMessageBox("EditRegions() is unimplemented.", "OGL", wxOK); + + // TODO +#if 0 + if (GetRegions().Number() < 2) + return; + + wxBeginBusyCursor(); + + GraphicsForm *form = new GraphicsForm("Divided nodes"); + // Need an array to store all the style strings, + // since they need to be converted to integers + char **styleStrings = new char *[GetRegions().Number()]; + for (int j = 0; j < GetRegions().Number(); j++) + styleStrings[j] = NULL; + + int i = 0; + wxNode *node = GetRegions().First(); + while (node && node->Next()) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + char buf[50]; + sprintf(buf, "Region %d", (i+1)); + form->Add(wxMakeFormMessage(buf)); + form->Add(wxMakeFormNewLine()); + + form->Add(wxMakeFormString("Colour", ®ion->penColour, wxFORM_CHOICE, + new wxList(wxMakeConstraintStrings( + "Invisible" , + "BLACK" , + "BLUE" , + "BROWN" , + "CORAL" , + "CYAN" , + "DARK GREY" , + "DARK GREEN" , + "DIM GREY" , + "GREY" , + "GREEN" , + "LIGHT BLUE" , + "LIGHT GREY" , + "MAGENTA" , + "MAROON" , + "NAVY" , + "ORANGE" , + "PURPLE" , + "RED" , + "TURQUOISE" , + "VIOLET" , + "WHITE" , + "YELLOW" , + NULL), + NULL), NULL, wxVERTICAL, 150)); + + char *styleString = NULL; + switch (region->penStyle) + { + case wxSHORT_DASH: + styleString = "Short Dash"; + break; + case wxLONG_DASH: + styleString = "Long Dash"; + break; + case wxDOT: + styleString = "Dot"; + break; + case wxDOT_DASH: + styleString = "Dot Dash"; + break; + case wxSOLID: + default: + styleString = "Solid"; + break; + } + styleStrings[i] = copystring(styleString); + form->Add(wxMakeFormString("Style", &(styleStrings[i]), wxFORM_CHOICE, + new wxList(wxMakeConstraintStrings( + "Solid" , + "Short Dash" , + "Long Dash" , + "Dot" , + "Dot Dash" , + NULL), + NULL), NULL, wxVERTICAL, 100)); + node = node->Next(); + i ++; + if (node && node->Next()) + form->Add(wxMakeFormNewLine()); + } + wxDialogBox *dialog = new wxDialogBox(m_canvas->GetParent(), "Divided object properties", 10, 10, 500, 500); + if (GraphicsLabelFont) + dialog->SetLabelFont(GraphicsLabelFont); + if (GraphicsButtonFont) + dialog->SetButtonFont(GraphicsButtonFont); + form->AssociatePanel(dialog); + form->dialog = dialog; + + dialog->Fit(); + dialog->Centre(wxBOTH); + + wxEndBusyCursor(); + + dialog->Show(TRUE); + + node = GetRegions().First(); + i = 0; + while (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + + if (styleStrings[i]) + { + if (strcmp(styleStrings[i], "Solid") == 0) + region->penStyle = wxSOLID; + else if (strcmp(styleStrings[i], "Dot") == 0) + region->penStyle = wxDOT; + else if (strcmp(styleStrings[i], "Short Dash") == 0) + region->penStyle = wxSHORT_DASH; + else if (strcmp(styleStrings[i], "Long Dash") == 0) + region->penStyle = wxLONG_DASH; + else if (strcmp(styleStrings[i], "Dot Dash") == 0) + region->penStyle = wxDOT_DASH; + delete[] styleStrings[i]; + } + region->m_actualPenObject = NULL; + node = node->Next(); + i ++; + } + delete[] styleStrings; + Draw(dc); +#endif +} + +void wxDividedShape::OnRightClick(double x, double y, int keys, int attachment) +{ + if (keys & KEY_CTRL) + { + EditRegions(); + } + else + { + wxRectangleShape::OnRightClick(x, y, keys, attachment); + } +} + +wxDividedShapeControlPoint::wxDividedShapeControlPoint(wxShapeCanvas *the_canvas, wxShape *object, + int region, double size, double the_m_xoffset, double the_m_yoffset, int the_type): + wxControlPoint(the_canvas, object, size, the_m_xoffset, the_m_yoffset, the_type) +{ + regionId = region; +} + +wxDividedShapeControlPoint::~wxDividedShapeControlPoint() +{ +} + +// Implement resizing of divided object division +void wxDividedShapeControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment) +{ + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + dc.SetLogicalFunction(OGLRBLF); + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetPen(dottedPen); + dc.SetBrush((* wxTRANSPARENT_BRUSH)); + + wxDividedShape *dividedObject = (wxDividedShape *)m_shape; + double x1 = (double)(dividedObject->GetX() - (dividedObject->GetWidth()/2.0)); + double y1 = y; + double x2 = (double)(dividedObject->GetX() + (dividedObject->GetWidth()/2.0)); + double y2 = y; + dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y2)); +} + +void wxDividedShapeControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment) +{ + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + wxDividedShape *dividedObject = (wxDividedShape *)m_shape; + dc.SetLogicalFunction(OGLRBLF); + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetPen(dottedPen); + dc.SetBrush((* wxTRANSPARENT_BRUSH)); + + double x1 = (double)(dividedObject->GetX() - (dividedObject->GetWidth()/2.0)); + double y1 = y; + double x2 = (double)(dividedObject->GetX() + (dividedObject->GetWidth()/2.0)); + double y2 = y; + dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y2)); + m_canvas->CaptureMouse(); +} + +void wxDividedShapeControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment) +{ + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + wxDividedShape *dividedObject = (wxDividedShape *)m_shape; + wxNode *node = dividedObject->GetRegions().Nth(regionId); + if (!node) + return; + + wxShapeRegion *thisRegion = (wxShapeRegion *)node->Data(); + wxShapeRegion *nextRegion = NULL; // Region below this one + + dc.SetLogicalFunction(wxCOPY); + + m_canvas->ReleaseMouse(); + + // Find the old top and bottom of this region, + // and calculate the new proportion for this region + // if legal. + + double currentY = (double)(dividedObject->GetY() - (dividedObject->GetHeight() / 2.0)); + double maxY = (double)(dividedObject->GetY() + (dividedObject->GetHeight() / 2.0)); + + // Save values + double thisRegionTop = 0.0; + double thisRegionBottom = 0.0; + double nextRegionBottom = 0.0; + + node = dividedObject->GetRegions().First(); + while (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + + double proportion = region->m_regionProportionY; + double yy = currentY + (dividedObject->GetHeight()*proportion); + double actualY = (double)(maxY < yy ? maxY : yy); + + if (region == thisRegion) + { + thisRegionTop = currentY; + thisRegionBottom = actualY; + if (node->Next()) + nextRegion = (wxShapeRegion *)node->Next()->Data(); + } + if (region == nextRegion) + { + nextRegionBottom = actualY; + } + + currentY = actualY; + node = node->Next(); + } + if (!nextRegion) + return; + + // Check that we haven't gone above this region or below + // next region. + if ((y <= thisRegionTop) || (y >= nextRegionBottom)) + return; + + dividedObject->EraseLinks(dc); + + // Now calculate the new proportions of this region and the next region. + double thisProportion = (double)((y - thisRegionTop)/dividedObject->GetHeight()); + double nextProportion = (double)((nextRegionBottom - y)/dividedObject->GetHeight()); + thisRegion->SetProportions(0.0, thisProportion); + nextRegion->SetProportions(0.0, nextProportion); + m_yoffset = (double)(y - dividedObject->GetY()); + + // Now reformat text + int i = 0; + node = dividedObject->GetRegions().First(); + while (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + if (region->GetText()) + { + char *s = copystring(region->GetText()); + dividedObject->FormatText(dc, s, i); + delete[] s; + } + node = node->Next(); + i++; + } + dividedObject->SetRegionSizes(); + dividedObject->Draw(dc); + dividedObject->GetEventHandler()->OnMoveLinks(dc); +} + diff --git a/src/ogl/drawn.cpp b/src/ogl/drawn.cpp new file mode 100644 index 0000000000..b410537294 --- /dev/null +++ b/src/ogl/drawn.cpp @@ -0,0 +1,2489 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: drawn.cpp +// Purpose: wxDrawnShape +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "drawn.h" +#pragma implementation "drawnp.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +static void IntToHex(unsigned int dec, char *buf); +static unsigned long HexToInt(char *buf); +extern char *oglBuffer; + +#define gyTYPE_PEN 40 +#define gyTYPE_BRUSH 41 +#define gyTYPE_FONT 42 + +/* + * Drawn object + * + */ + +IMPLEMENT_DYNAMIC_CLASS(wxDrawnShape, wxRectangleShape) + +wxDrawnShape::wxDrawnShape():wxRectangleShape(100.0, 50.0) +{ + m_saveToFile = TRUE; + m_currentAngle = oglDRAWN_ANGLE_0; +} + +wxDrawnShape::~wxDrawnShape() +{ +} + +void wxDrawnShape::OnDraw(wxDC& dc) +{ + // Pass pen and brush in case we have force outline + // and fill colours + if (m_shadowMode != SHADOW_NONE) + { + if (m_shadowBrush) + m_metafiles[m_currentAngle].m_fillBrush = m_shadowBrush; + m_metafiles[m_currentAngle].m_outlinePen = g_oglTransparentPen; + m_metafiles[m_currentAngle].Draw(dc, m_xpos + m_shadowOffsetX, m_ypos + m_shadowOffsetY); + } + + m_metafiles[m_currentAngle].m_outlinePen = m_pen; + m_metafiles[m_currentAngle].m_fillBrush = m_brush; + m_metafiles[m_currentAngle].Draw(dc, m_xpos, m_ypos); +} + +void wxDrawnShape::SetSize(double w, double h, bool recursive) +{ + SetAttachmentSize(w, h); + + double scaleX; + double scaleY; + if (GetWidth() == 0.0) + scaleX = 1.0; + else scaleX = w/GetWidth(); + if (GetHeight() == 0.0) + scaleY = 1.0; + else scaleY = h/GetHeight(); + + int i = 0; + for (i = 0; i < 4; i++) + { + if (m_metafiles[i].IsValid()) + m_metafiles[i].Scale(scaleX, scaleY); + } + m_width = w; + m_height = h; + SetDefaultRegionSize(); +} + +void wxDrawnShape::Scale(double sx, double sy) +{ + int i; + for (i = 0; i < 4; i++) + { + if (m_metafiles[i].IsValid()) + { + m_metafiles[i].Scale(sx, sy); + m_metafiles[i].CalculateSize(this); + } + } +} + +void wxDrawnShape::Translate(double x, double y) +{ + int i; + for (i = 0; i < 4; i++) + { + if (m_metafiles[i].IsValid()) + { + m_metafiles[i].Translate(x, y); + m_metafiles[i].CalculateSize(this); + } + } +} + +// theta is absolute rotation from the zero position +void wxDrawnShape::Rotate(double x, double y, double theta) +{ + m_currentAngle = DetermineMetaFile(theta); + + if (m_currentAngle == 0) + { + // Rotate metafile + if (!m_metafiles[0].GetRotateable()) + return; + + m_metafiles[0].Rotate(x, y, theta); + } + + double actualTheta = theta-m_rotation; + + // Rotate attachment points + double sinTheta = (double)sin(actualTheta); + double cosTheta = (double)cos(actualTheta); + wxNode *node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + double x1 = point->m_x; + double y1 = point->m_y; + point->m_x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta; + point->m_y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta; + node = node->Next(); + } + m_rotation = theta; + + m_metafiles[m_currentAngle].CalculateSize(this); +} + +// Which metafile do we use now? Based on current rotation and validity +// of metafiles. + +int wxDrawnShape::DetermineMetaFile(double rotation) +{ + double tolerance = 0.0001; + const double pi = 3.1415926535897932384626433832795 ; + double angle1 = 0.0; + double angle2 = pi/2.0; + double angle3 = pi; + double angle4 = 3.0*pi/2.0; + + int whichMetafile = 0; + + if (oglRoughlyEqual(rotation, angle1, tolerance)) + { + whichMetafile = 0; + } + else if (oglRoughlyEqual(rotation, angle2, tolerance)) + { + whichMetafile = 1; + } + else if (oglRoughlyEqual(rotation, angle3, tolerance)) + { + whichMetafile = 2; + } + else if (oglRoughlyEqual(rotation, angle4, tolerance)) + { + whichMetafile = 3; + } + + if ((whichMetafile > 0) && !m_metafiles[whichMetafile].IsValid()) + whichMetafile = 0; + + return whichMetafile; +} + +void wxDrawnShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h) +{ + if (m_metafiles[m_currentAngle].GetOutlineOp() != -1) + { + wxNode* node = m_metafiles[m_currentAngle].GetOps().Nth(m_metafiles[m_currentAngle].GetOutlineOp()); + wxASSERT (node != NULL); + wxDrawOp* op = (wxDrawOp*) node->Data(); + + if (op->OnDrawOutline(dc, x, y, w, h, m_width, m_height)) + return; + } + + // Default... just use a rectangle + wxRectangleShape::OnDrawOutline(dc, x, y, w, h); +} + +// Get the perimeter point using the special outline op, if there is one, +// otherwise use default wxRectangleShape scheme +bool wxDrawnShape::GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3) +{ + if (m_metafiles[m_currentAngle].GetOutlineOp() != -1) + { + wxNode* node = m_metafiles[m_currentAngle].GetOps().Nth(m_metafiles[m_currentAngle].GetOutlineOp()); + wxASSERT (node != NULL); + wxDrawOp* op = (wxDrawOp*) node->Data(); + + if (op->GetPerimeterPoint(x1, y1, x2, y2, x3, y3, GetX(), GetY(), GetAttachmentMode())) + return TRUE; + } + + // Default... just use a rectangle + return wxRectangleShape::GetPerimeterPoint(x1, y1, x2, y2, x3, y3); +} + +#ifdef PROLOGIO +void wxDrawnShape::WriteAttributes(wxExpr *clause) +{ + wxRectangleShape::WriteAttributes(clause); + + clause->AddAttributeValue("current_angle", (long)m_currentAngle); + clause->AddAttributeValue("save_metafile", (long)m_saveToFile); + if (m_saveToFile) + { + int i = 0; + for (i = 0; i < 4; i++) + { + if (m_metafiles[i].IsValid()) + m_metafiles[i].WriteAttributes(clause, i); + } + } +} + +void wxDrawnShape::ReadAttributes(wxExpr *clause) +{ + wxRectangleShape::ReadAttributes(clause); + + int iVal = (int) m_saveToFile; + clause->GetAttributeValue("save_metafile", iVal); + clause->GetAttributeValue("current_angle", m_currentAngle); + m_saveToFile = (iVal != 0); + + if (m_saveToFile) + { + int i = 0; + for (i = 0; i < 4; i++) + { + m_metafiles[i].ReadAttributes(clause, i); + } + } +} +#endif + +// Does the copying for this object +void wxDrawnShape::Copy(wxShape& copy) +{ + wxRectangleShape::Copy(copy); + + wxASSERT( copy.IsKindOf(CLASSINFO(wxDrawnShape)) ) ; + + wxDrawnShape& drawnCopy = (wxDrawnShape&) copy; + + int i = 0; + for (i = 0; i < 4; i++) + { + m_metafiles[i].Copy(drawnCopy.m_metafiles[i]); + } + drawnCopy.m_saveToFile = m_saveToFile; + drawnCopy.m_currentAngle = m_currentAngle; +} + +bool wxDrawnShape::LoadFromMetaFile(char *filename) +{ + return m_metafiles[0].LoadFromMetaFile(filename, &m_width, &m_height); +} + +// Set of functions for drawing into a pseudo metafile. +// They use integers, but doubles are used internally for accuracy +// when scaling. + +void wxDrawnShape::DrawLine(const wxPoint& pt1, const wxPoint& pt2) +{ + m_metafiles[m_currentAngle].DrawLine(pt1, pt2); +} + +void wxDrawnShape::DrawRectangle(const wxRect& rect) +{ + m_metafiles[m_currentAngle].DrawRectangle(rect); +} + +void wxDrawnShape::DrawRoundedRectangle(const wxRect& rect, double radius) +{ + m_metafiles[m_currentAngle].DrawRoundedRectangle(rect, radius); +} + +void wxDrawnShape::DrawEllipse(const wxRect& rect) +{ + m_metafiles[m_currentAngle].DrawEllipse(rect); +} + +void wxDrawnShape::DrawArc(const wxPoint& centrePt, const wxPoint& startPt, const wxPoint& endPt) +{ + m_metafiles[m_currentAngle].DrawArc(centrePt, startPt, endPt); +} + +void wxDrawnShape::DrawEllipticArc(const wxRect& rect, double startAngle, double endAngle) +{ + m_metafiles[m_currentAngle].DrawEllipticArc(rect, startAngle, endAngle); +} + +void wxDrawnShape::DrawPoint(const wxPoint& pt) +{ + m_metafiles[m_currentAngle].DrawPoint(pt); +} + +void wxDrawnShape::DrawText(const wxString& text, const wxPoint& pt) +{ + m_metafiles[m_currentAngle].DrawText(text, pt); +} + +void wxDrawnShape::DrawLines(int n, wxPoint pts[]) +{ + m_metafiles[m_currentAngle].DrawLines(n, pts); +} + +void wxDrawnShape::DrawPolygon(int n, wxPoint pts[], int flags) +{ + if (flags & oglMETAFLAGS_ATTACHMENTS) + { + ClearAttachments(); + int i; + for (i = 0; i < n; i++) + m_attachmentPoints.Append(new wxAttachmentPoint(i, pts[i].x, pts[i].y)); + } + m_metafiles[m_currentAngle].DrawPolygon(n, pts, flags); +} + +void wxDrawnShape::DrawSpline(int n, wxPoint pts[]) +{ + m_metafiles[m_currentAngle].DrawSpline(n, pts); +} + +void wxDrawnShape::SetClippingRect(const wxRect& rect) +{ + m_metafiles[m_currentAngle].SetClippingRect(rect); +} + +void wxDrawnShape::DestroyClippingRect() +{ + m_metafiles[m_currentAngle].DestroyClippingRect(); +} + +void wxDrawnShape::SetDrawnPen(wxPen* pen, bool isOutline) +{ + m_metafiles[m_currentAngle].SetPen(pen, isOutline); +} + +void wxDrawnShape::SetDrawnBrush(wxBrush* brush, bool isFill) +{ + m_metafiles[m_currentAngle].SetBrush(brush, isFill); +} + +void wxDrawnShape::SetDrawnFont(wxFont* font) +{ + m_metafiles[m_currentAngle].SetFont(font); +} + +void wxDrawnShape::SetDrawnTextColour(const wxColour& colour) +{ + m_metafiles[m_currentAngle].SetTextColour(colour); +} + +void wxDrawnShape::SetDrawnBackgroundColour(const wxColour& colour) +{ + m_metafiles[m_currentAngle].SetBackgroundColour(colour); +} + +void wxDrawnShape::SetDrawnBackgroundMode(int mode) +{ + m_metafiles[m_currentAngle].SetBackgroundMode(mode); +} + + +/* + * Individual operations + * + */ + +/* + * Set font, brush, text colour + * + */ + +wxOpSetGDI::wxOpSetGDI(int theOp, wxPseudoMetaFile *theImage, int theGdiIndex, int theMode): + wxDrawOp(theOp) +{ + m_gdiIndex = theGdiIndex; + m_image = theImage; + m_mode = theMode; +} + +void wxOpSetGDI::Do(wxDC& dc, double xoffset, double yoffset) +{ + switch (m_op) + { + case DRAWOP_SET_PEN: + { + // Check for overriding this operation for outline + // colour + if (m_image->m_outlineColours.Member((wxObject *)m_gdiIndex)) + { + if (m_image->m_outlinePen) + dc.SetPen(* m_image->m_outlinePen); + } + else + { + wxNode *node = m_image->m_gdiObjects.Nth(m_gdiIndex); + if (node) + { + wxPen *pen = (wxPen *)node->Data(); + if (pen) + dc.SetPen(* pen); + } + } + break; + } + case DRAWOP_SET_BRUSH: + { + // Check for overriding this operation for outline or fill + // colour + if (m_image->m_outlineColours.Member((wxObject *)m_gdiIndex)) + { + // Need to construct a brush to match the outline pen's colour + if (m_image->m_outlinePen) + { + wxBrush *br = wxTheBrushList->FindOrCreateBrush(m_image->m_outlinePen->GetColour(), wxSOLID); + if (br) + dc.SetBrush(* br); + } + } + else if (m_image->m_fillColours.Member((wxObject *)m_gdiIndex)) + { + if (m_image->m_fillBrush) + { + dc.SetBrush(* m_image->m_fillBrush); + } + } + else + { + wxNode *node = m_image->m_gdiObjects.Nth(m_gdiIndex); + if (node) + { + wxBrush *brush = (wxBrush *)node->Data(); + if (brush) + dc.SetBrush(* brush); + } + } + break; + } + case DRAWOP_SET_FONT: + { + wxNode *node = m_image->m_gdiObjects.Nth(m_gdiIndex); + if (node) + { + wxFont *font = (wxFont *)node->Data(); + if (font) + dc.SetFont(* font); + } + break; + } + case DRAWOP_SET_TEXT_COLOUR: + { + wxColour col(m_r,m_g,m_b); + dc.SetTextForeground(col); + break; + } + case DRAWOP_SET_BK_COLOUR: + { + wxColour col(m_r,m_g,m_b); + dc.SetTextBackground(col); + break; + } + case DRAWOP_SET_BK_MODE: + { + dc.SetBackgroundMode(m_mode); + break; + } + default: + break; + } +} + +wxDrawOp *wxOpSetGDI::Copy(wxPseudoMetaFile *newImage) +{ + wxOpSetGDI *newOp = new wxOpSetGDI(m_op, newImage, m_gdiIndex, m_mode); + newOp->m_r = m_r; + newOp->m_g = m_g; + newOp->m_b = m_b; + return newOp; +} + +wxExpr *wxOpSetGDI::WriteExpr(wxPseudoMetaFile *image) +{ + wxExpr *expr = new wxExpr(wxExprList); + expr->Append(new wxExpr((long)m_op)); + switch (m_op) + { + case DRAWOP_SET_PEN: + case DRAWOP_SET_BRUSH: + case DRAWOP_SET_FONT: + { + expr->Append(new wxExpr((long)m_gdiIndex)); + break; + } + case DRAWOP_SET_TEXT_COLOUR: + case DRAWOP_SET_BK_COLOUR: + { + expr->Append(new wxExpr((long)m_r)); + expr->Append(new wxExpr((long)m_g)); + expr->Append(new wxExpr((long)m_b)); + break; + } + case DRAWOP_SET_BK_MODE: + { + expr->Append(new wxExpr((long)m_mode)); + break; + } + default: + break; + } + return expr; +} + +void wxOpSetGDI::ReadExpr(wxPseudoMetaFile *image, wxExpr *expr) +{ + switch (m_op) + { + case DRAWOP_SET_PEN: + case DRAWOP_SET_BRUSH: + case DRAWOP_SET_FONT: + { + m_gdiIndex = (int)expr->Nth(1)->IntegerValue(); + break; + } + case DRAWOP_SET_TEXT_COLOUR: + case DRAWOP_SET_BK_COLOUR: + { + m_r = (unsigned char)expr->Nth(1)->IntegerValue(); + m_g = (unsigned char)expr->Nth(2)->IntegerValue(); + m_b = (unsigned char)expr->Nth(3)->IntegerValue(); + break; + } + case DRAWOP_SET_BK_MODE: + { + m_mode = (int)expr->Nth(1)->IntegerValue(); + break; + } + default: + break; + } +} + +/* + * Set/destroy clipping + * + */ + +wxOpSetClipping::wxOpSetClipping(int theOp, double theX1, double theY1, + double theX2, double theY2):wxDrawOp(theOp) +{ + m_x1 = theX1; + m_y1 = theY1; + m_x2 = theX2; + m_y2 = theY2; +} + +wxDrawOp *wxOpSetClipping::Copy(wxPseudoMetaFile *newImage) +{ + wxOpSetClipping *newOp = new wxOpSetClipping(m_op, m_x1, m_y1, m_x2, m_y2); + return newOp; +} + +void wxOpSetClipping::Do(wxDC& dc, double xoffset, double yoffset) +{ + switch (m_op) + { + case DRAWOP_SET_CLIPPING_RECT: + { + dc.SetClippingRegion((long)(m_x1 + xoffset), (long)(m_y1 + yoffset), (long)(m_x2 + xoffset), (long)(m_y2 + yoffset)); + break; + } + case DRAWOP_DESTROY_CLIPPING_RECT: + { + dc.DestroyClippingRegion(); + break; + } + default: + break; + } +} + +void wxOpSetClipping::Scale(double xScale, double yScale) +{ + m_x1 *= xScale; + m_y1 *= yScale; + m_x2 *= xScale; + m_y2 *= yScale; +} + +void wxOpSetClipping::Translate(double x, double y) +{ + m_x1 += x; + m_y1 += y; +} + +wxExpr *wxOpSetClipping::WriteExpr(wxPseudoMetaFile *image) +{ + wxExpr *expr = new wxExpr(wxExprList); + expr->Append(new wxExpr((long)m_op)); + switch (m_op) + { + case DRAWOP_SET_CLIPPING_RECT: + { + expr->Append(new wxExpr(m_x1)); + expr->Append(new wxExpr(m_y1)); + expr->Append(new wxExpr(m_x2)); + expr->Append(new wxExpr(m_y2)); + break; + } + default: + break; + } + return expr; +} + +void wxOpSetClipping::ReadExpr(wxPseudoMetaFile *image, wxExpr *expr) +{ + switch (m_op) + { + case DRAWOP_SET_CLIPPING_RECT: + { + m_x1 = expr->Nth(1)->RealValue(); + m_y1 = expr->Nth(2)->RealValue(); + m_x2 = expr->Nth(3)->RealValue(); + m_y2 = expr->Nth(4)->RealValue(); + break; + } + default: + break; + } +} + +/* + * Draw line, rectangle, rounded rectangle, ellipse, point, arc, text + * + */ + +wxOpDraw::wxOpDraw(int theOp, double theX1, double theY1, double theX2, double theY2, + double theRadius, char *s):wxDrawOp(theOp) +{ + m_x1 = theX1; + m_y1 = theY1; + m_x2 = theX2; + m_y2 = theY2; + m_x3 = 0.0; + m_y3 = 0.0; + m_radius = theRadius; + if (s) m_textString = copystring(s); + else m_textString = NULL; +} + +wxOpDraw::~wxOpDraw() +{ + if (m_textString) delete[] m_textString; +} + +wxDrawOp *wxOpDraw::Copy(wxPseudoMetaFile *newImage) +{ + wxOpDraw *newOp = new wxOpDraw(m_op, m_x1, m_y1, m_x2, m_y2, m_radius, m_textString); + newOp->m_x3 = m_x3; + newOp->m_y3 = m_y3; + return newOp; +} + +void wxOpDraw::Do(wxDC& dc, double xoffset, double yoffset) +{ + switch (m_op) + { + case DRAWOP_DRAW_LINE: + { + dc.DrawLine(WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset), WXROUND(m_x2+xoffset), WXROUND(m_y2+yoffset)); + break; + } + case DRAWOP_DRAW_RECT: + { + dc.DrawRectangle(WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset), WXROUND(m_x2), WXROUND(m_y2)); + break; + } + case DRAWOP_DRAW_ROUNDED_RECT: + { + dc.DrawRoundedRectangle(WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset), WXROUND(m_x2), WXROUND(m_y2), m_radius); + break; + } + case DRAWOP_DRAW_ELLIPSE: + { + dc.DrawEllipse(WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset), WXROUND(m_x2), WXROUND(m_y2)); + break; + } + case DRAWOP_DRAW_ARC: + { + dc.DrawArc(WXROUND(m_x2+xoffset), WXROUND(m_y2+yoffset), + WXROUND(m_x3+xoffset), WXROUND(m_y3+yoffset), + WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset)); + break; + } + case DRAWOP_DRAW_ELLIPTIC_ARC: + { + const double pi = 3.1415926535897932384626433832795 ; + + // Convert back to degrees + dc.DrawEllipticArc( + WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset), + WXROUND(m_x2), WXROUND(m_y2), + WXROUND(m_x3*(360.0/(2.0*pi))), WXROUND(m_y3*(360.0/(2.0*pi)))); + break; + } + case DRAWOP_DRAW_POINT: + { + dc.DrawPoint(WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset)); + break; + } + case DRAWOP_DRAW_TEXT: + { + dc.DrawText(m_textString, WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset)); + break; + } + default: + break; + } +} + +void wxOpDraw::Scale(double scaleX, double scaleY) +{ + m_x1 *= scaleX; + m_y1 *= scaleY; + m_x2 *= scaleX; + m_y2 *= scaleY; + + if (m_op != DRAWOP_DRAW_ELLIPTIC_ARC) + { + m_x3 *= scaleX; + m_y3 *= scaleY; + } + + m_radius *= scaleX; +} + +void wxOpDraw::Translate(double x, double y) +{ + m_x1 += x; + m_y1 += y; + + switch (m_op) + { + case DRAWOP_DRAW_LINE: + { + m_x2 += x; + m_y2 += y; + break; + } + case DRAWOP_DRAW_ARC: + { + m_x2 += x; + m_y2 += y; + m_x3 += x; + m_y3 += y; + break; + } + case DRAWOP_DRAW_ELLIPTIC_ARC: + { + break; + } + default: + break; + } +} + +void wxOpDraw::Rotate(double x, double y, double theta, double sinTheta, double cosTheta) +{ + double newX1 = m_x1*cosTheta - m_y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta; + double newY1 = m_x1*sinTheta + m_y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta; + + switch (m_op) + { + case DRAWOP_DRAW_LINE: + { + double newX2 = m_x2*cosTheta - m_y2*sinTheta + x*(1.0 - cosTheta) + y*sinTheta; + double newY2 = m_x2*sinTheta + m_y2*cosTheta + y*(1.0 - cosTheta) + x*sinTheta; + + m_x1 = newX1; + m_y1 = newY1; + m_x2 = newX2; + m_y2 = newY2; + break; + } + case DRAWOP_DRAW_RECT: + case DRAWOP_DRAW_ROUNDED_RECT: + case DRAWOP_DRAW_ELLIPTIC_ARC: + { + // Assume only 0, 90, 180, 270 degree rotations. + // oldX1, oldY1 represents the top left corner. Find the + // bottom right, and rotate that. Then the width/height is the difference + // between x/y values. + double oldBottomRightX = m_x1 + m_x2; + double oldBottomRightY = m_y1 + m_y2; + double newBottomRightX = oldBottomRightX*cosTheta - oldBottomRightY*sinTheta + x*(1.0 - cosTheta) + y*sinTheta; + double newBottomRightY = oldBottomRightX*sinTheta + oldBottomRightY*cosTheta + y*(1.0 - cosTheta) + x*sinTheta; + + // Now find the new top-left, bottom-right coordinates. + double minX = wxMin(newX1, newBottomRightX); + double minY = wxMin(newY1, newBottomRightY); + double maxX = wxMax(newX1, newBottomRightX); + double maxY = wxMax(newY1, newBottomRightY); + + m_x1 = minX; + m_y1 = minY; + m_x2 = maxX - minX; // width + m_y2 = maxY - minY; // height + + if (m_op == DRAWOP_DRAW_ELLIPTIC_ARC) + { + // Add rotation to angles + m_x3 += theta; + m_y3 += theta; + } + + break; + } + case DRAWOP_DRAW_ARC: + { + double newX2 = m_x2*cosTheta - m_y2*sinTheta + x*(1.0 - cosTheta) + y*sinTheta; + double newY2 = m_x2*sinTheta + m_y2*cosTheta + y*(1.0 - cosTheta) + x*sinTheta; + double newX3 = m_x3*cosTheta - m_y3*sinTheta + x*(1.0 - cosTheta) + y*sinTheta; + double newY3 = m_x3*sinTheta + m_y3*cosTheta + y*(1.0 - cosTheta) + x*sinTheta; + + m_x1 = newX1; + m_y1 = newY1; + m_x2 = newX2; + m_y2 = newY2; + m_x3 = newX3; + m_y3 = newY3; + + break; + } + default: + break; + } +} + +wxExpr *wxOpDraw::WriteExpr(wxPseudoMetaFile *image) +{ + wxExpr *expr = new wxExpr(wxExprList); + expr->Append(new wxExpr((long)m_op)); + switch (m_op) + { + case DRAWOP_DRAW_LINE: + case DRAWOP_DRAW_RECT: + case DRAWOP_DRAW_ELLIPSE: + { + expr->Append(new wxExpr(m_x1)); + expr->Append(new wxExpr(m_y1)); + expr->Append(new wxExpr(m_x2)); + expr->Append(new wxExpr(m_y2)); + break; + } + case DRAWOP_DRAW_ROUNDED_RECT: + { + expr->Append(new wxExpr(m_x1)); + expr->Append(new wxExpr(m_y1)); + expr->Append(new wxExpr(m_x2)); + expr->Append(new wxExpr(m_y2)); + expr->Append(new wxExpr(m_radius)); + break; + } + case DRAWOP_DRAW_POINT: + { + expr->Append(new wxExpr(m_x1)); + expr->Append(new wxExpr(m_y1)); + break; + } + case DRAWOP_DRAW_TEXT: + { + expr->Append(new wxExpr(m_x1)); + expr->Append(new wxExpr(m_y1)); + expr->Append(new wxExpr(wxExprString, m_textString)); + break; + } + case DRAWOP_DRAW_ARC: + case DRAWOP_DRAW_ELLIPTIC_ARC: + { + expr->Append(new wxExpr(m_x1)); + expr->Append(new wxExpr(m_y1)); + expr->Append(new wxExpr(m_x2)); + expr->Append(new wxExpr(m_y2)); + expr->Append(new wxExpr(m_x3)); + expr->Append(new wxExpr(m_y3)); + break; + } + default: + { + break; + } + } + return expr; +} + +void wxOpDraw::ReadExpr(wxPseudoMetaFile *image, wxExpr *expr) +{ + switch (m_op) + { + case DRAWOP_DRAW_LINE: + case DRAWOP_DRAW_RECT: + case DRAWOP_DRAW_ELLIPSE: + { + m_x1 = expr->Nth(1)->RealValue(); + m_y1 = expr->Nth(2)->RealValue(); + m_x2 = expr->Nth(3)->RealValue(); + m_y2 = expr->Nth(4)->RealValue(); + break; + } + case DRAWOP_DRAW_ROUNDED_RECT: + { + m_x1 = expr->Nth(1)->RealValue(); + m_y1 = expr->Nth(2)->RealValue(); + m_x2 = expr->Nth(3)->RealValue(); + m_y2 = expr->Nth(4)->RealValue(); + m_radius = expr->Nth(5)->RealValue(); + break; + } + case DRAWOP_DRAW_POINT: + { + m_x1 = expr->Nth(1)->RealValue(); + m_y1 = expr->Nth(2)->RealValue(); + break; + } + case DRAWOP_DRAW_TEXT: + { + m_x1 = expr->Nth(1)->RealValue(); + m_y1 = expr->Nth(2)->RealValue(); + wxString str(expr->Nth(3)->StringValue()); + m_textString = copystring((const char*) str); + break; + } + case DRAWOP_DRAW_ARC: + case DRAWOP_DRAW_ELLIPTIC_ARC: + { + m_x1 = expr->Nth(1)->RealValue(); + m_y1 = expr->Nth(2)->RealValue(); + m_x2 = expr->Nth(3)->RealValue(); + m_y2 = expr->Nth(4)->RealValue(); + m_x3 = expr->Nth(5)->RealValue(); + m_y3 = expr->Nth(6)->RealValue(); + break; + } + default: + { + break; + } + } +} + +/* + * Draw polygon, polyline, spline + * + */ + +wxOpPolyDraw::wxOpPolyDraw(int theOp, int n, wxRealPoint *thePoints):wxDrawOp(theOp) +{ + m_noPoints = n; + m_points = thePoints; +} + +wxOpPolyDraw::~wxOpPolyDraw() +{ + delete[] m_points; +} + +wxDrawOp *wxOpPolyDraw::Copy(wxPseudoMetaFile *newImage) +{ + wxRealPoint *newPoints = new wxRealPoint[m_noPoints]; + for (int i = 0; i < m_noPoints; i++) + { + newPoints[i].x = m_points[i].x; + newPoints[i].y = m_points[i].y; + } + wxOpPolyDraw *newOp = new wxOpPolyDraw(m_op, m_noPoints, newPoints); + return newOp; +} + +void wxOpPolyDraw::Do(wxDC& dc, double xoffset, double yoffset) +{ + switch (m_op) + { + case DRAWOP_DRAW_POLYLINE: + { + wxPoint *actualPoints = new wxPoint[m_noPoints]; + int i; + for (i = 0; i < m_noPoints; i++) + { + actualPoints[i].x = WXROUND(m_points[i].x); + actualPoints[i].y = WXROUND(m_points[i].y); + } + + dc.DrawLines(m_noPoints, actualPoints, WXROUND(xoffset), WXROUND(yoffset)); + + delete[] actualPoints; + break; + } + case DRAWOP_DRAW_POLYGON: + { + wxPoint *actualPoints = new wxPoint[m_noPoints]; + int i; + for (i = 0; i < m_noPoints; i++) + { + actualPoints[i].x = WXROUND(m_points[i].x); + actualPoints[i].y = WXROUND(m_points[i].y); + } + + dc.DrawPolygon(m_noPoints, actualPoints, WXROUND(xoffset), WXROUND(yoffset)); + + delete[] actualPoints; + break; + } + case DRAWOP_DRAW_SPLINE: + { + wxPoint *actualPoints = new wxPoint[m_noPoints]; + int i; + for (i = 0; i < m_noPoints; i++) + { + actualPoints[i].x = WXROUND(m_points[i].x); + actualPoints[i].y = WXROUND(m_points[i].y); + } + + dc.DrawSpline(m_noPoints, actualPoints); // no offsets in DrawSpline // , xoffset, yoffset); + + delete[] actualPoints; + break; + break; + } + default: + break; + } +} + +void wxOpPolyDraw::Scale(double scaleX, double scaleY) +{ + for (int i = 0; i < m_noPoints; i++) + { + m_points[i].x *= scaleX; + m_points[i].y *= scaleY; + } +} + +void wxOpPolyDraw::Translate(double x, double y) +{ + for (int i = 0; i < m_noPoints; i++) + { + m_points[i].x += x; + m_points[i].y += y; + } +} + +void wxOpPolyDraw::Rotate(double x, double y, double theta, double sinTheta, double cosTheta) +{ + for (int i = 0; i < m_noPoints; i++) + { + double x1 = m_points[i].x; + double y1 = m_points[i].y; + m_points[i].x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta; + m_points[i].y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta; + } +} + +wxExpr *wxOpPolyDraw::WriteExpr(wxPseudoMetaFile *image) +{ + wxExpr *expr = new wxExpr(wxExprList); + expr->Append(new wxExpr((long)m_op)); + expr->Append(new wxExpr((long)m_noPoints)); + +// char buf1[9]; + char buf2[5]; + char buf3[5]; + + oglBuffer[0] = 0; + + /* + * Store each coordinate pair in a hex string to save space. + * E.g. "1B9080CD". 4 hex digits per coordinate pair. + * + */ + + for (int i = 0; i < m_noPoints; i++) + { + long signedX = (long)(m_points[i].x*100.0); + long signedY = (long)(m_points[i].y*100.0); + + // Scale to 0 -> 64K + long unSignedX = (long)(signedX + 32767.0); + long unSignedY = (long)(signedY + 32767.0); + +// IntToHex((unsigned int)signedX, buf2); +// IntToHex((unsigned int)signedY, buf3); + IntToHex((int)unSignedX, buf2); + IntToHex((int)unSignedY, buf3); + + // Don't overrun the buffer + if ((i*8) < 3000) + { + strcat(oglBuffer, buf2); + strcat(oglBuffer, buf3); + } + } + expr->Append(new wxExpr(wxExprString, oglBuffer)); + return expr; +} + +void wxOpPolyDraw::ReadExpr(wxPseudoMetaFile *image, wxExpr *expr) +{ + m_noPoints = (int)expr->Nth(1)->IntegerValue(); + + char buf1[5]; + char buf2[5]; + + m_points = new wxRealPoint[m_noPoints]; + int i = 0; + int bufPtr = 0; + wxString hexString = expr->Nth(2)->StringValue(); + while (i < m_noPoints) + { + buf1[0] = hexString[(size_t)bufPtr]; + buf1[1] = hexString[(size_t)(bufPtr + 1)]; + buf1[2] = hexString[(size_t)(bufPtr + 2)]; + buf1[3] = hexString[(size_t)(bufPtr + 3)]; + buf1[4] = 0; + + buf2[0] = hexString[(size_t)(bufPtr + 4)]; + buf2[1] = hexString[(size_t)(bufPtr + 5)]; + buf2[2] = hexString[(size_t)(bufPtr + 6)]; + buf2[3] = hexString[(size_t)(bufPtr + 7)]; + buf2[4] = 0; + + bufPtr += 8; + +// int signedX = (signed int)HexToInt(buf1); +// int signedY = (signed int)HexToInt(buf2); + long unSignedX = HexToInt(buf1); + long unSignedY = HexToInt(buf2); + // Scale -32K -> +32K + long signedX = unSignedX - 32767; + long signedY = unSignedY - 32767; +#ifdef __WXMSW__ + int testX = (signed int)unSignedX; + int testY = (signed int)unSignedY; +#endif + + m_points[i].x = (double)(signedX / 100.0); + m_points[i].y = (double)(signedY / 100.0); + + i ++; + } +} + +// Draw an outline using the current operation. +bool wxOpPolyDraw::OnDrawOutline(wxDC& dc, double x, double y, double w, double h, double oldW, double oldH) +{ + dc.SetBrush(* wxTRANSPARENT_BRUSH); + + // Multiply all points by proportion of new size to old size + double x_proportion = (double)(fabs(w/oldW)); + double y_proportion = (double)(fabs(h/oldH)); + + int n = m_noPoints; + wxPoint *intPoints = new wxPoint[n]; + int i; + for (i = 0; i < n; i++) + { + intPoints[i].x = WXROUND (x_proportion * m_points[i].x); + intPoints[i].y = WXROUND (y_proportion * m_points[i].y); + } + dc.DrawPolygon(n, intPoints, (long) x, (long) y); + delete[] intPoints; + return TRUE; +} + +// Assume (x1, y1) is centre of box (most generally, line end at box) +bool wxOpPolyDraw::GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3, + double xOffset, double yOffset, + int attachmentMode) +{ + int n = m_noPoints; + + // First check for situation where the line is vertical, + // and we would want to connect to a point on that vertical -- + // oglFindEndForPolyline can't cope with this (the arrow + // gets drawn to the wrong place). + if ((attachmentMode == ATTACHMENT_MODE_NONE) && (x1 == x2)) + { + // Look for the point we'd be connecting to. This is + // a heuristic... + int i; + for (i = 0; i < n; i++) + { + wxRealPoint *point = & (m_points[i]); + if (point->x == 0.0) + { + if ((y2 > y1) && (point->y > 0.0)) + { + *x3 = point->x + xOffset; + *y3 = point->y + yOffset; + return TRUE; + } + else if ((y2 < y1) && (point->y < 0.0)) + { + *x3 = point->x + xOffset; + *y3 = point->y + yOffset; + return TRUE; + } + } + } + } + + double *xpoints = new double[n]; + double *ypoints = new double[n]; + + int i = 0; + for (i = 0; i < n; i++) + { + wxRealPoint *point = & (m_points[i]); + xpoints[i] = point->x + xOffset; + ypoints[i] = point->y + yOffset; + } + + oglFindEndForPolyline(n, xpoints, ypoints, + x1, y1, x2, y2, x3, y3); + + delete[] xpoints; + delete[] ypoints; + + return TRUE; +} + + +/* + * Utilities + * + */ + +static char hexArray[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F' }; + +// Convert unsigned 16-bit integer to 4-character hex string +static void IntToHex(unsigned int dec, char *buf) +{ + int digit1 = (int)(dec/4096); + int digit2 = (int)((dec - (digit1*4096))/256); + int digit3 = (int)((dec - (digit1*4096) - (digit2*256))/16); + int digit4 = dec - (digit1*4096 + digit2*256 + digit3*16); + + buf[0] = hexArray[digit1]; + buf[1] = hexArray[digit2]; + buf[2] = hexArray[digit3]; + buf[3] = hexArray[digit4]; + buf[4] = 0; +} + +// One hex digit to decimal number +static int HexToInt1(char hex) +{ + switch (hex) + { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + case 'A': + return 10; + case 'B': + return 11; + case 'C': + return 12; + case 'D': + return 13; + case 'E': + return 14; + case 'F': + return 15; + default: + return 0; + } + return 0; +} + +// 4-digit hex string to unsigned integer +static unsigned long HexToInt(char *buf) +{ + long d1 = (long)(HexToInt1(buf[0])*4096.0) ; + long d2 = (long)(HexToInt1(buf[1])*256.0) ; + long d3 = (long)(HexToInt1(buf[2])*16.0) ; + long d4 = (long)(HexToInt1(buf[3])) ; + unsigned long n = (long)(d1 + d2 + d3 + d4) ; + return n; +} + +/* + * wxPseudo meta-file + * + */ + +IMPLEMENT_DYNAMIC_CLASS(wxPseudoMetaFile, wxObject) + +wxPseudoMetaFile::wxPseudoMetaFile() +{ + m_currentRotation = 0; + m_rotateable = TRUE; + m_width = 0.0; + m_height = 0.0; + m_outlinePen = NULL; + m_fillBrush = NULL; + m_outlineOp = -1; +} + +wxPseudoMetaFile::wxPseudoMetaFile(wxPseudoMetaFile& mf) +{ + mf.Copy(*this); +} + +wxPseudoMetaFile::~wxPseudoMetaFile() +{ + Clear(); +} + +void wxPseudoMetaFile::Clear() +{ + wxNode *node = m_ops.First(); + while (node) + { + wxDrawOp *op = (wxDrawOp *)node->Data(); + delete op; + node = node->Next(); + } + m_ops.Clear(); + m_gdiObjects.Clear(); + m_outlineColours.Clear(); + m_fillColours.Clear(); + m_outlineOp = -1; +} + +void wxPseudoMetaFile::Draw(wxDC& dc, double xoffset, double yoffset) +{ + wxNode *node = m_ops.First(); + while (node) + { + wxDrawOp *op = (wxDrawOp *)node->Data(); + op->Do(dc, xoffset, yoffset); + node = node->Next(); + } +} + +void wxPseudoMetaFile::Scale(double sx, double sy) +{ + wxNode *node = m_ops.First(); + while (node) + { + wxDrawOp *op = (wxDrawOp *)node->Data(); + op->Scale(sx, sy); + node = node->Next(); + } + m_width *= sx; + m_height *= sy; +} + +void wxPseudoMetaFile::Translate(double x, double y) +{ + wxNode *node = m_ops.First(); + while (node) + { + wxDrawOp *op = (wxDrawOp *)node->Data(); + op->Translate(x, y); + node = node->Next(); + } +} + +void wxPseudoMetaFile::Rotate(double x, double y, double theta) +{ + double theta1 = theta-m_currentRotation; + if (theta1 == 0.0) return; + double cosTheta = (double)cos(theta1); + double sinTheta = (double)sin(theta1); + + wxNode *node = m_ops.First(); + while (node) + { + wxDrawOp *op = (wxDrawOp *)node->Data(); + op->Rotate(x, y, theta, sinTheta, cosTheta); + node = node->Next(); + } + m_currentRotation = theta; +} + +#ifdef PROLOGIO +void wxPseudoMetaFile::WriteAttributes(wxExpr *clause, int whichAngle) +{ + wxString widthStr; + widthStr.Printf("meta_width%d", whichAngle); + + wxString heightStr; + heightStr.Printf("meta_height%d", whichAngle); + + wxString outlineStr; + outlineStr.Printf("outline_op%d", whichAngle); + + wxString rotateableStr; + rotateableStr.Printf("meta_rotateable%d", whichAngle); + + // Write width and height + clause->AddAttributeValue(widthStr, m_width); + clause->AddAttributeValue(heightStr, m_height); + clause->AddAttributeValue(rotateableStr, (long)m_rotateable); + clause->AddAttributeValue(outlineStr, (long)m_outlineOp); + + // Write GDI objects + char buf[50]; + int i = 1; + wxNode *node = m_gdiObjects.First(); + while (node) + { + sprintf(buf, "gdi%d_%d", whichAngle, i); + wxObject *obj = (wxObject *)node->Data(); + wxExpr *expr = NULL; + if (obj) + { + if (obj->IsKindOf(CLASSINFO(wxPen))) + { + wxPen *thePen = (wxPen *)obj; + expr = new wxExpr(wxExprList); + expr->Append(new wxExpr((long)gyTYPE_PEN)); + expr->Append(new wxExpr((long)thePen->GetWidth())); + expr->Append(new wxExpr((long)thePen->GetStyle())); + expr->Append(new wxExpr((long)thePen->GetColour().Red())); + expr->Append(new wxExpr((long)thePen->GetColour().Green())); + expr->Append(new wxExpr((long)thePen->GetColour().Blue())); + } + else if (obj->IsKindOf(CLASSINFO(wxBrush))) + { + wxBrush *theBrush = (wxBrush *)obj; + expr = new wxExpr(wxExprList); + expr->Append(new wxExpr((long)gyTYPE_BRUSH)); + expr->Append(new wxExpr((long)theBrush->GetStyle())); + expr->Append(new wxExpr((long)theBrush->GetColour().Red())); + expr->Append(new wxExpr((long)theBrush->GetColour().Green())); + expr->Append(new wxExpr((long)theBrush->GetColour().Blue())); + } + else if (obj->IsKindOf(CLASSINFO(wxFont))) + { + wxFont *theFont = (wxFont *)obj; + expr = new wxExpr(wxExprList); + expr->Append(new wxExpr((long)gyTYPE_FONT)); + expr->Append(new wxExpr((long)theFont->GetPointSize())); + expr->Append(new wxExpr((long)theFont->GetFamily())); + expr->Append(new wxExpr((long)theFont->GetStyle())); + expr->Append(new wxExpr((long)theFont->GetWeight())); + expr->Append(new wxExpr((long)theFont->GetUnderlined())); + } + } + else + { + // If no recognised GDI object, append a place holder anyway. + expr = new wxExpr(wxExprList); + expr->Append(new wxExpr((long)0)); + } + + if (expr) + { + clause->AddAttributeValue(buf, expr); + i ++; + } + node = node->Next(); + } + + // Write drawing operations + i = 1; + node = m_ops.First(); + while (node) + { + sprintf(buf, "op%d_%d", whichAngle, i); + wxDrawOp *op = (wxDrawOp *)node->Data(); + wxExpr *expr = op->WriteExpr(this); + if (expr) + { + clause->AddAttributeValue(buf, expr); + i ++; + } + node = node->Next(); + } + + // Write outline and fill GDI op lists (if any) + if (m_outlineColours.Number() > 0) + { + wxExpr *outlineExpr = new wxExpr(wxExprList); + node = m_outlineColours.First(); + while (node) + { + outlineExpr->Append(new wxExpr((long)node->Data())); + node = node->Next(); + } + wxString outlineObjectsStr; + outlineObjectsStr.Printf("outline_objects%d", whichAngle); + + clause->AddAttributeValue(outlineObjectsStr, outlineExpr); + } + if (m_fillColours.Number() > 0) + { + wxExpr *fillExpr = new wxExpr(wxExprList); + node = m_fillColours.First(); + while (node) + { + fillExpr->Append(new wxExpr((long)node->Data())); + node = node->Next(); + } + wxString fillObjectsStr; + fillObjectsStr.Printf("fill_objects%d", whichAngle); + + clause->AddAttributeValue(fillObjectsStr, fillExpr); + } + +} + +void wxPseudoMetaFile::ReadAttributes(wxExpr *clause, int whichAngle) +{ + wxString widthStr; + widthStr.Printf("meta_width%d", whichAngle); + + wxString heightStr; + heightStr.Printf("meta_height%d", whichAngle); + + wxString outlineStr; + outlineStr.Printf("outline_op%d", whichAngle); + + wxString rotateableStr; + rotateableStr.Printf("meta_rotateable%d", whichAngle); + + clause->GetAttributeValue(widthStr, m_width); + clause->GetAttributeValue(heightStr, m_height); + clause->GetAttributeValue(outlineStr, m_outlineOp); + + int iVal = (int) m_rotateable; + clause->GetAttributeValue(rotateableStr, iVal); + m_rotateable = (iVal != 0); + + // Read GDI objects + char buf[50]; + int i = 1; + bool keepGoing = TRUE; + while (keepGoing) + { + sprintf(buf, "gdi%d_%d", whichAngle, i); + wxExpr *expr = NULL; + clause->GetAttributeValue(buf, &expr); + if (!expr) + { + keepGoing = FALSE; + } + else + { + wxExpr *idExpr = expr->Nth(0); + switch (idExpr->IntegerValue()) + { + case gyTYPE_PEN: + { + int penWidth = (int)expr->Nth(1)->IntegerValue(); + int penStyle = (int)expr->Nth(2)->IntegerValue(); + int penRed = (int)expr->Nth(3)->IntegerValue(); + int penGreen = (int)expr->Nth(4)->IntegerValue(); + int penBlue = (int)expr->Nth(5)->IntegerValue(); + wxColour col(penRed, penGreen, penBlue); + wxPen *p = wxThePenList->FindOrCreatePen(col, penWidth, penStyle); + if (!p) + p = wxBLACK_PEN; + m_gdiObjects.Append(p); + break; + } + case gyTYPE_BRUSH: + { + int brushStyle = (int)expr->Nth(1)->IntegerValue(); + int brushRed = (int)expr->Nth(2)->IntegerValue(); + int brushGreen = (int)expr->Nth(3)->IntegerValue(); + int brushBlue = (int)expr->Nth(4)->IntegerValue(); + wxColour col(brushRed, brushGreen, brushBlue); + wxBrush *b = wxTheBrushList->FindOrCreateBrush(col, brushStyle); + if (!b) + b = wxWHITE_BRUSH; + m_gdiObjects.Append(b); + break; + } + case gyTYPE_FONT: + { + int fontPointSize = (int)expr->Nth(1)->IntegerValue(); + int fontFamily = (int)expr->Nth(2)->IntegerValue(); + int fontStyle = (int)expr->Nth(3)->IntegerValue(); + int fontWeight = (int)expr->Nth(4)->IntegerValue(); + int fontUnderlined = (int)expr->Nth(5)->IntegerValue(); + m_gdiObjects.Append(wxTheFontList->FindOrCreateFont(fontPointSize, + fontFamily, fontStyle, fontWeight, (fontUnderlined != 0))); + break; + } + default: + { + // Place holder + m_gdiObjects.Append(NULL); + break; + } + } + i ++; + } + } + + // Now read in the operations + keepGoing = TRUE; + i = 1; + while (keepGoing) + { + sprintf(buf, "op%d_%d", whichAngle, i); + wxExpr *expr = NULL; + clause->GetAttributeValue(buf, &expr); + if (!expr) + { + keepGoing = FALSE; + } + else + { + wxExpr *idExpr = expr->Nth(0); + int opId = (int)idExpr->IntegerValue(); + switch (opId) + { + case DRAWOP_SET_PEN: + case DRAWOP_SET_BRUSH: + case DRAWOP_SET_FONT: + case DRAWOP_SET_TEXT_COLOUR: + case DRAWOP_SET_BK_COLOUR: + case DRAWOP_SET_BK_MODE: + { + wxOpSetGDI *theOp = new wxOpSetGDI(opId, this, 0); + theOp->ReadExpr(this, expr); + m_ops.Append(theOp); + break; + } + + case DRAWOP_SET_CLIPPING_RECT: + case DRAWOP_DESTROY_CLIPPING_RECT: + { + wxOpSetClipping *theOp = new wxOpSetClipping(opId, 0.0, 0.0, 0.0, 0.0); + theOp->ReadExpr(this, expr); + m_ops.Append(theOp); + break; + } + + case DRAWOP_DRAW_LINE: + case DRAWOP_DRAW_RECT: + case DRAWOP_DRAW_ROUNDED_RECT: + case DRAWOP_DRAW_ELLIPSE: + case DRAWOP_DRAW_POINT: + case DRAWOP_DRAW_ARC: + case DRAWOP_DRAW_TEXT: + { + wxOpDraw *theOp = new wxOpDraw(opId, 0.0, 0.0, 0.0, 0.0); + theOp->ReadExpr(this, expr); + m_ops.Append(theOp); + break; + } + case DRAWOP_DRAW_SPLINE: + case DRAWOP_DRAW_POLYLINE: + case DRAWOP_DRAW_POLYGON: + { + wxOpPolyDraw *theOp = new wxOpPolyDraw(opId, 0, NULL); + theOp->ReadExpr(this, expr); + m_ops.Append(theOp); + break; + } + default: + break; + } + } + i ++; + } + + wxString outlineObjectsStr; + outlineObjectsStr.Printf("outline_objects%d", whichAngle); + + // Now read in the list of outline and fill operations, if any + wxExpr *expr1 = clause->AttributeValue(outlineObjectsStr); + if (expr1) + { + wxExpr *eachExpr = expr1->GetFirst(); + while (eachExpr) + { + m_outlineColours.Append((wxObject *)eachExpr->IntegerValue()); + eachExpr = eachExpr->GetNext(); + } + } + + wxString fillObjectsStr; + fillObjectsStr.Printf("fill_objects%d", whichAngle); + + expr1 = clause->AttributeValue(fillObjectsStr); + if (expr1) + { + wxExpr *eachExpr = expr1->GetFirst(); + while (eachExpr) + { + m_fillColours.Append((wxObject *)eachExpr->IntegerValue()); + eachExpr = eachExpr->GetNext(); + } + } +} +#endif + +// Does the copying for this object +void wxPseudoMetaFile::Copy(wxPseudoMetaFile& copy) +{ + copy.Clear(); + + copy.m_currentRotation = m_currentRotation; + copy.m_width = m_width; + copy.m_height = m_height; + copy.m_rotateable = m_rotateable; + copy.m_fillBrush = m_fillBrush; + copy.m_outlinePen = m_outlinePen; + copy.m_outlineOp = m_outlineOp; + + // Copy the GDI objects + wxNode *node = m_gdiObjects.First(); + while (node) + { + wxObject *obj = (wxObject *)node->Data(); + copy.m_gdiObjects.Append(obj); + node = node->Next(); + } + + // Copy the operations + node = m_ops.First(); + while (node) + { + wxDrawOp *op = (wxDrawOp *)node->Data(); + copy.m_ops.Append(op->Copy(©)); + node = node->Next(); + } + + // Copy the outline/fill operations + node = m_outlineColours.First(); + while (node) + { + copy.m_outlineColours.Append((wxObject *)node->Data()); + node = node->Next(); + } + node = m_fillColours.First(); + while (node) + { + copy.m_fillColours.Append((wxObject *)node->Data()); + node = node->Next(); + } +} + +/* + * Pass size of existing image; scale height to + * fit width and return new width and height. + * + */ + +bool wxPseudoMetaFile::LoadFromMetaFile(char *filename, double *rwidth, double *rheight) +{ + if (!FileExists(filename)) + return NULL; + + wxXMetaFile *metaFile = new wxXMetaFile; + + if (!metaFile->ReadFile(filename)) + { + delete metaFile; + return FALSE; + } + + double lastX = 0.0; + double lastY = 0.0; + + // Convert from metafile records to wxDrawnShape records + wxNode *node = metaFile->metaRecords.First(); + while (node) + { + wxMetaRecord *record = (wxMetaRecord *)node->Data(); + switch (record->metaFunction) + { + case META_SETBKCOLOR: + { + wxOpSetGDI *op = new wxOpSetGDI(DRAWOP_SET_BK_COLOUR, this, 0); + op->m_r = (unsigned char)record->param1; + op->m_g = (unsigned char)record->param2; + op->m_b = (unsigned char)record->param3; + m_ops.Append(op); + break; + } + case META_SETBKMODE: + { + wxOpSetGDI *op = new wxOpSetGDI(DRAWOP_SET_BK_MODE, this, 0, (int)record->param1); + m_ops.Append(op); + break; + } + case META_SETMAPMODE: + { + break; + } +// case META_SETROP2: +// case META_SETRELABS: +// case META_SETPOLYFILLMODE: +// case META_SETSTRETCHBLTMODE: +// case META_SETTEXTCHAREXTRA: + case META_SETTEXTCOLOR: + { + wxOpSetGDI *op = new wxOpSetGDI(DRAWOP_SET_TEXT_COLOUR, this, 0); + op->m_r = (unsigned char)record->param1; + op->m_g = (unsigned char)record->param2; + op->m_b = (unsigned char)record->param3; + m_ops.Append(op); + break; + } +// case META_SETTEXTJUSTIFICATION: +// case META_SETWINDOWORG: +// case META_SETWINDOWEXT: +// case META_SETVIEWPORTORG: +// case META_SETVIEWPORTEXT: +// case META_OFFSETWINDOWORG: +// case META_SCALEWINDOWEXT: +// case META_OFFSETVIEWPORTORG: +// case META_SCALEVIEWPORTEXT: + case META_LINETO: + { + wxOpDraw *op = new wxOpDraw(DRAWOP_DRAW_LINE, (double)lastX, (double)lastY, + (double)record->param1, (double)record->param2); + m_ops.Append(op); + break; + } + case META_MOVETO: + { + lastX = (double)record->param1; + lastY = (double)record->param2; + break; + } + case META_EXCLUDECLIPRECT: + { +/* + wxMetaRecord *rec = new wxMetaRecord(META_EXCLUDECLIPRECT); + rec->param4 = getshort(handle); // m_y2 + rec->param3 = getshort(handle); // x2 + rec->param2 = getshort(handle); // y1 + rec->param1 = getshort(handle); // x1 +*/ + break; + } + case META_INTERSECTCLIPRECT: + { +/* + rec->param4 = getshort(handle); // m_y2 + rec->param3 = getshort(handle); // x2 + rec->param2 = getshort(handle); // y1 + rec->param1 = getshort(handle); // x1 +*/ + break; + } +// case META_ARC: // DO!!! + case META_ELLIPSE: + { + wxOpDraw *op = new wxOpDraw(DRAWOP_DRAW_ELLIPSE, + (double)record->param1, (double)record->param2, + (double)(record->param3 - record->param1), + (double)(record->param4 - record->param2)); + m_ops.Append(op); + break; + } +// case META_FLOODFILL: +// case META_PIE: // DO!!! + case META_RECTANGLE: + { + wxOpDraw *op = new wxOpDraw(DRAWOP_DRAW_RECT, + (double)record->param1, (double)record->param2, + (double)(record->param3 - record->param1), + (double)(record->param4 - record->param2)); + m_ops.Append(op); + break; + } + case META_ROUNDRECT: + { + wxOpDraw *op = new wxOpDraw(DRAWOP_DRAW_ROUNDED_RECT, + (double)record->param1, (double)record->param2, + (double)(record->param3 - record->param1), + (double)(record->param4 - record->param2), (double)record->param5); + m_ops.Append(op); + break; + } +// case META_PATBLT: +// case META_SAVEDC: + case META_SETPIXEL: + { + wxOpDraw *op = new wxOpDraw(DRAWOP_DRAW_POINT, + (double)record->param1, (double)record->param2, + 0.0, 0.0); + +// SHOULD SET THE COLOUR - SET PEN? +// rec->param3 = getint(handle); // COLORREF + m_ops.Append(op); + break; + } +// case META_OFFSETCLIPRGN: + case META_TEXTOUT: + { + wxOpDraw *op = new wxOpDraw(DRAWOP_DRAW_TEXT, + (double)record->param1, (double)record->param2, + 0.0, 0.0, 0.0, record->stringParam); + m_ops.Append(op); + break; + } +// case META_BITBLT: +// case META_STRETCHBLT: + case META_POLYGON: + { + int n = (int)record->param1; + wxRealPoint *newPoints = new wxRealPoint[n]; + for (int i = 0; i < n; i++) + { + newPoints[i].x = record->points[i].x; + newPoints[i].y = record->points[i].y; + } + + wxOpPolyDraw *op = new wxOpPolyDraw(DRAWOP_DRAW_POLYGON, n, newPoints); + m_ops.Append(op); + break; + } + case META_POLYLINE: + { + int n = (int)record->param1; + wxRealPoint *newPoints = new wxRealPoint[n]; + for (int i = 0; i < n; i++) + { + newPoints[i].x = record->points[i].x; + newPoints[i].y = record->points[i].y; + } + + wxOpPolyDraw *op = new wxOpPolyDraw(DRAWOP_DRAW_POLYLINE, n, newPoints); + m_ops.Append(op); + break; + } +// case META_ESCAPE: +// case META_RESTOREDC: +// case META_FILLREGION: +// case META_FRAMEREGION: +// case META_INVERTREGION: +// case META_PAINTREGION: +// case META_SELECTCLIPREGION: // DO THIS! + case META_SELECTOBJECT: + { + // The pen, brush etc. has already been created when the metafile + // was read in, so we don't create it - we set it. + wxNode *recNode = metaFile->gdiObjects.Nth((int)record->param2); + if (recNode) + { + wxMetaRecord *gdiRec = (wxMetaRecord *)recNode->Data(); + if (gdiRec && (gdiRec->param1 != 0)) + { + wxObject *obj = (wxObject *)gdiRec->param1; + if (obj->IsKindOf(CLASSINFO(wxPen))) + { + wxOpSetGDI *op = new wxOpSetGDI(DRAWOP_SET_PEN, this, (int)record->param2); + m_ops.Append(op); + } + else if (obj->IsKindOf(CLASSINFO(wxBrush))) + { + wxOpSetGDI *op = new wxOpSetGDI(DRAWOP_SET_BRUSH, this, (int)record->param2); + m_ops.Append(op); + } + else if (obj->IsKindOf(CLASSINFO(wxFont))) + { + wxOpSetGDI *op = new wxOpSetGDI(DRAWOP_SET_FONT, this, (int)record->param2); + m_ops.Append(op); + } + } + } + break; + } +// case META_SETTEXTALIGN: +// case META_DRAWTEXT: +// case META_CHORD: +// case META_SETMAPPERFLAGS: +// case META_EXTTEXTOUT: +// case META_SETDIBTODEV: +// case META_SELECTPALETTE: +// case META_REALIZEPALETTE: +// case META_ANIMATEPALETTE: +// case META_SETPALENTRIES: +// case META_POLYPOLYGON: +// case META_RESIZEPALETTE: +// case META_DIBBITBLT: +// case META_DIBSTRETCHBLT: + case META_DIBCREATEPATTERNBRUSH: + { + // Place holder + m_gdiObjects.Append(NULL); + break; + } +// case META_STRETCHDIB: +// case META_EXTFLOODFILL: +// case META_RESETDC: +// case META_STARTDOC: +// case META_STARTPAGE: +// case META_ENDPAGE: +// case META_ABORTDOC: +// case META_ENDDOC: +// case META_DELETEOBJECT: // DO!! + case META_CREATEPALETTE: + { + // Place holder + m_gdiObjects.Append(NULL); + break; + } + case META_CREATEBRUSH: + { + // Place holder + m_gdiObjects.Append(NULL); + break; + } + case META_CREATEPATTERNBRUSH: + { + // Place holder + m_gdiObjects.Append(NULL); + break; + } + case META_CREATEPENINDIRECT: + { + // The pen is created when the metafile is read in. + // We keep track of all the GDI objects needed for this + // image so when reading the wxDrawnShape from file, + // we can read in all the GDI objects, then refer + // to them by an index starting from zero thereafter. + m_gdiObjects.Append((wxObject *)record->param1); + break; + } + case META_CREATEFONTINDIRECT: + { + m_gdiObjects.Append((wxObject *)record->param1); + break; + } + case META_CREATEBRUSHINDIRECT: + { + // Don't have to do anything here: the pen is created + // when the metafile is read in. + m_gdiObjects.Append((wxObject *)record->param1); + break; + } + case META_CREATEBITMAPINDIRECT: + { + // Place holder + m_gdiObjects.Append(NULL); + break; + } + case META_CREATEBITMAP: + { + // Place holder + m_gdiObjects.Append(NULL); + break; + } + case META_CREATEREGION: + { + // Place holder + m_gdiObjects.Append(NULL); + break; + } + default: + { + break; + } + } + node = node->Next(); + } + double actualWidth = (double)fabs(metaFile->right - metaFile->left); + double actualHeight = (double)fabs(metaFile->bottom - metaFile->top); + + double initialScaleX = 1.0; + double initialScaleY = 1.0; + + double xoffset, yoffset; + + // Translate so origin is at centre of rectangle + if (metaFile->bottom > metaFile->top) + yoffset = - (double)((metaFile->bottom - metaFile->top)/2.0); + else + yoffset = - (double)((metaFile->top - metaFile->bottom)/2.0); + + if (metaFile->right > metaFile->left) + xoffset = - (double)((metaFile->right - metaFile->left)/2.0); + else + xoffset = - (double)((metaFile->left - metaFile->right)/2.0); + + Translate(xoffset, yoffset); + + // Scale to a reasonable size (take the width of this wxDrawnShape + // as a guide) + if (actualWidth != 0.0) + { + initialScaleX = (double)((*rwidth) / actualWidth); + initialScaleY = initialScaleX; + (*rheight) = initialScaleY*actualHeight; + } + Scale(initialScaleX, initialScaleY); + + m_width = (actualWidth*initialScaleX); + m_height = *rheight; + + delete metaFile; + return TRUE; +} + +// Scale to fit size +void wxPseudoMetaFile::ScaleTo(double w, double h) +{ + double scaleX = (double)(w/m_width); + double scaleY = (double)(h/m_height); + + // Do the scaling + Scale(scaleX, scaleY); +} + +void wxPseudoMetaFile::GetBounds(double *boundMinX, double *boundMinY, double *boundMaxX, double *boundMaxY) +{ + double maxX = (double) -99999.9; + double maxY = (double) -99999.9; + double minX = (double) 99999.9; + double minY = (double) 99999.9; + + wxNode *node = m_ops.First(); + while (node) + { + wxDrawOp *op = (wxDrawOp *)node->Data(); + switch (op->GetOp()) + { + case DRAWOP_DRAW_LINE: + case DRAWOP_DRAW_RECT: + case DRAWOP_DRAW_ROUNDED_RECT: + case DRAWOP_DRAW_ELLIPSE: + case DRAWOP_DRAW_POINT: + case DRAWOP_DRAW_TEXT: + { + wxOpDraw *opDraw = (wxOpDraw *)op; + if (opDraw->m_x1 < minX) minX = opDraw->m_x1; + if (opDraw->m_x1 > maxX) maxX = opDraw->m_x1; + if (opDraw->m_y1 < minY) minY = opDraw->m_y1; + if (opDraw->m_y1 > maxY) maxY = opDraw->m_y1; + if (op->GetOp() == DRAWOP_DRAW_LINE) + { + if (opDraw->m_x2 < minX) minX = opDraw->m_x2; + if (opDraw->m_x2 > maxX) maxX = opDraw->m_x2; + if (opDraw->m_y2 < minY) minY = opDraw->m_y2; + if (opDraw->m_y2 > maxY) maxY = opDraw->m_y2; + } + else if (op->GetOp() == DRAWOP_DRAW_RECT || + op->GetOp() == DRAWOP_DRAW_ROUNDED_RECT || + op->GetOp() == DRAWOP_DRAW_ELLIPSE) + { + if ((opDraw->m_x1 + opDraw->m_x2) < minX) minX = (opDraw->m_x1 + opDraw->m_x2); + if ((opDraw->m_x1 + opDraw->m_x2) > maxX) maxX = (opDraw->m_x1 + opDraw->m_x2); + if ((opDraw->m_y1 + opDraw->m_y2) < minY) minY = (opDraw->m_y1 + opDraw->m_y2); + if ((opDraw->m_y1 + opDraw->m_y2) > maxY) maxY = (opDraw->m_y1 + opDraw->m_y2); + } + break; + } + case DRAWOP_DRAW_ARC: + { + // TODO: don't yet know how to calculate the bounding box + // for an arc. So pretend it's a line; to get a correct + // bounding box, draw a blank rectangle first, of the correct + // size. + wxOpDraw *opDraw = (wxOpDraw *)op; + if (opDraw->m_x1 < minX) minX = opDraw->m_x1; + if (opDraw->m_x1 > maxX) maxX = opDraw->m_x1; + if (opDraw->m_y1 < minY) minY = opDraw->m_y1; + if (opDraw->m_y1 > maxY) maxY = opDraw->m_y1; + if (opDraw->m_x2 < minX) minX = opDraw->m_x2; + if (opDraw->m_x2 > maxX) maxX = opDraw->m_x2; + if (opDraw->m_y2 < minY) minY = opDraw->m_y2; + if (opDraw->m_y2 > maxY) maxY = opDraw->m_y2; + break; + } + case DRAWOP_DRAW_POLYLINE: + case DRAWOP_DRAW_POLYGON: + case DRAWOP_DRAW_SPLINE: + { + wxOpPolyDraw *poly = (wxOpPolyDraw *)op; + for (int i = 0; i < poly->m_noPoints; i++) + { + if (poly->m_points[i].x < minX) minX = poly->m_points[i].x; + if (poly->m_points[i].x > maxX) maxX = poly->m_points[i].x; + if (poly->m_points[i].y < minY) minY = poly->m_points[i].y; + if (poly->m_points[i].y > maxY) maxY = poly->m_points[i].y; + } + break; + } + default: + break; + } + node = node->Next(); + } + + *boundMinX = minX; + *boundMinY = minY; + *boundMaxX = maxX; + *boundMaxY = maxY; +/* + *w = (double)fabs(maxX - minX); + *h = (double)fabs(maxY - minY); +*/ +} + +// Calculate size from current operations +void wxPseudoMetaFile::CalculateSize(wxDrawnShape* shape) +{ + double boundMinX, boundMinY, boundMaxX, boundMaxY; + + GetBounds(& boundMinX, & boundMinY, & boundMaxX, & boundMaxY); + + SetSize(boundMaxX - boundMinX, boundMaxY - boundMinY); + + if (shape) + { + shape->SetWidth(m_width); + shape->SetHeight(m_height); + } +} + +// Set of functions for drawing into a pseudo metafile. +// They use integers, but doubles are used internally for accuracy +// when scaling. + +void wxPseudoMetaFile::DrawLine(const wxPoint& pt1, const wxPoint& pt2) +{ + wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_LINE, + (double) pt1.x, (double) pt1.y, (double) pt2.x, (double) pt2.y); + + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::DrawRectangle(const wxRect& rect) +{ + wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_RECT, + (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height); + + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::DrawRoundedRectangle(const wxRect& rect, double radius) +{ + wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_ROUNDED_RECT, + (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height); + + theOp->m_radius = radius; + + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::DrawEllipse(const wxRect& rect) +{ + wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_ELLIPSE, + (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height); + + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::DrawArc(const wxPoint& centrePt, const wxPoint& startPt, const wxPoint& endPt) +{ + wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_ARC, + (double) centrePt.x, (double) centrePt.y, (double) startPt.x, (double) startPt.y); + + theOp->m_x3 = (double) endPt.x; + theOp->m_y3 = (double) endPt.y; + + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::DrawEllipticArc(const wxRect& rect, double startAngle, double endAngle) +{ + const double pi = 3.1415926535897932384626433832795 ; + + double startAngleRadians = startAngle* (pi*2.0/360.0); + double endAngleRadians = endAngle* (pi*2.0/360.0); + + wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_ELLIPTIC_ARC, + (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height); + + theOp->m_x3 = startAngleRadians; + theOp->m_y3 = endAngleRadians; + + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::DrawPoint(const wxPoint& pt) +{ + wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_POINT, + (double) pt.x, (double) pt.y, 0.0, 0.0); + + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::DrawText(const wxString& text, const wxPoint& pt) +{ + wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_TEXT, + (double) pt.x, (double) pt.y, 0.0, 0.0); + + theOp->m_textString = copystring(text); + + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::DrawLines(int n, wxPoint pts[]) +{ + wxRealPoint* realPoints = new wxRealPoint[n]; + int i; + for (i = 0; i < n; i++) + { + realPoints[i].x = pts[i].x; + realPoints[i].y = pts[i].y; + } + wxOpPolyDraw* theOp = new wxOpPolyDraw(DRAWOP_DRAW_POLYLINE, n, realPoints); + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::DrawPolygon(int n, wxPoint pts[], int flags) +{ + wxRealPoint* realPoints = new wxRealPoint[n]; + int i; + for (i = 0; i < n; i++) + { + realPoints[i].x = pts[i].x; + realPoints[i].y = pts[i].y; + } + wxOpPolyDraw* theOp = new wxOpPolyDraw(DRAWOP_DRAW_POLYGON, n, realPoints); + m_ops.Append(theOp); + + if (flags & oglMETAFLAGS_OUTLINE) + m_outlineOp = (m_ops.Number() - 1); +} + +void wxPseudoMetaFile::DrawSpline(int n, wxPoint pts[]) +{ + wxRealPoint* realPoints = new wxRealPoint[n]; + int i; + for (i = 0; i < n; i++) + { + realPoints[i].x = pts[i].x; + realPoints[i].y = pts[i].y; + } + wxOpPolyDraw* theOp = new wxOpPolyDraw(DRAWOP_DRAW_SPLINE, n, realPoints); + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::SetClippingRect(const wxRect& rect) +{ + wxOpSetClipping* theOp = new wxOpSetClipping(DRAWOP_SET_CLIPPING_RECT, + (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height); +} + +void wxPseudoMetaFile::DestroyClippingRect() +{ + wxOpSetClipping* theOp = new wxOpSetClipping(DRAWOP_DESTROY_CLIPPING_RECT, + 0.0, 0.0, 0.0, 0.0); + + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::SetPen(wxPen* pen, bool isOutline) +{ + m_gdiObjects.Append(pen); + int n = m_gdiObjects.Number(); + + wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_PEN, this, n - 1); + + m_ops.Append(theOp); + + if (isOutline) + { + m_outlineColours.Append((wxObject*) (n - 1)); + } +} + +void wxPseudoMetaFile::SetBrush(wxBrush* brush, bool isFill) +{ + m_gdiObjects.Append(brush); + int n = m_gdiObjects.Number(); + + wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_BRUSH, this, n - 1); + + m_ops.Append(theOp); + + if (isFill) + { + m_fillColours.Append((wxObject*) (n - 1)); + } +} + +void wxPseudoMetaFile::SetFont(wxFont* font) +{ + m_gdiObjects.Append(font); + int n = m_gdiObjects.Number(); + + wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_FONT, this, n - 1); + + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::SetTextColour(const wxColour& colour) +{ + wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_TEXT_COLOUR, this, 0); + theOp->m_r = colour.Red(); + theOp->m_g = colour.Green(); + theOp->m_b = colour.Blue(); + + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::SetBackgroundColour(const wxColour& colour) +{ + wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_BK_COLOUR, this, 0); + theOp->m_r = colour.Red(); + theOp->m_g = colour.Green(); + theOp->m_b = colour.Blue(); + + m_ops.Append(theOp); +} + +void wxPseudoMetaFile::SetBackgroundMode(int mode) +{ + wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_BK_MODE, this, 0, mode); + + m_ops.Append(theOp); +} + diff --git a/src/ogl/lines.cpp b/src/ogl/lines.cpp new file mode 100644 index 0000000000..069a4eda4a --- /dev/null +++ b/src/ogl/lines.cpp @@ -0,0 +1,2515 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: lines.cpp +// Purpose: wxLineShape +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "lines.h" +#pragma implementation "linesp.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#if wxUSE_IOSTREAMH +#include +#else +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// Line shape +IMPLEMENT_DYNAMIC_CLASS(wxLineShape, wxShape) + +wxLineShape::wxLineShape() +{ + m_sensitivity = OP_CLICK_LEFT | OP_CLICK_RIGHT; + m_draggable = FALSE; + m_attachmentTo = 0; + m_attachmentFrom = 0; +/* + m_actualTextWidth = 0.0; + m_actualTextHeight = 0.0; +*/ + m_from = NULL; + m_to = NULL; + m_erasing = FALSE; + m_arrowSpacing = 5.0; // For the moment, don't bother saving this to file. + m_ignoreArrowOffsets = FALSE; + m_isSpline = FALSE; + m_maintainStraightLines = FALSE; + m_alignmentStart = 0; + m_alignmentEnd = 0; + + m_lineControlPoints = NULL; + + // Clear any existing regions (created in an earlier constructor) + // and make the three line regions. + ClearRegions(); + wxShapeRegion *newRegion = new wxShapeRegion; + newRegion->SetName("Middle"); + newRegion->SetSize(150, 50); + m_regions.Append((wxObject *)newRegion); + + newRegion = new wxShapeRegion; + newRegion->SetName("Start"); + newRegion->SetSize(150, 50); + m_regions.Append((wxObject *)newRegion); + + newRegion = new wxShapeRegion; + newRegion->SetName("End"); + newRegion->SetSize(150, 50); + m_regions.Append((wxObject *)newRegion); + + for (int i = 0; i < 3; i++) + m_labelObjects[i] = NULL; +} + +wxLineShape::~wxLineShape() +{ + if (m_lineControlPoints) + { + ClearPointList(*m_lineControlPoints); + delete m_lineControlPoints; + } + for (int i = 0; i < 3; i++) + { + if (m_labelObjects[i]) + { + m_labelObjects[i]->Select(FALSE); + m_labelObjects[i]->RemoveFromCanvas(m_canvas); + delete m_labelObjects[i]; + m_labelObjects[i] = NULL; + } + } + ClearArrowsAtPosition(-1); +} + +void wxLineShape::MakeLineControlPoints(int n) +{ + if (m_lineControlPoints) + { + ClearPointList(*m_lineControlPoints); + delete m_lineControlPoints; + } + m_lineControlPoints = new wxList; + + int i = 0; + for (i = 0; i < n; i++) + { + wxRealPoint *point = new wxRealPoint(-999, -999); + m_lineControlPoints->Append((wxObject*) point); + } +} + +wxNode *wxLineShape::InsertLineControlPoint(wxDC* dc) +{ + if (dc) + Erase(*dc); + + wxNode *last = m_lineControlPoints->Last(); + wxNode *second_last = last->Previous(); + wxRealPoint *last_point = (wxRealPoint *)last->Data(); + wxRealPoint *second_last_point = (wxRealPoint *)second_last->Data(); + + // Choose a point half way between the last and penultimate points + double line_x = ((last_point->x + second_last_point->x)/2); + double line_y = ((last_point->y + second_last_point->y)/2); + + wxRealPoint *point = new wxRealPoint(line_x, line_y); + wxNode *node = m_lineControlPoints->Insert(last, (wxObject*) point); + return node; +} + +bool wxLineShape::DeleteLineControlPoint() +{ + if (m_lineControlPoints->Number() < 3) + return FALSE; + + wxNode *last = m_lineControlPoints->Last(); + wxNode *second_last = last->Previous(); + + wxRealPoint *second_last_point = (wxRealPoint *)second_last->Data(); + delete second_last_point; + delete second_last; + + return TRUE; +} + +void wxLineShape::Initialise() +{ + if (m_lineControlPoints) + { + // Just move the first and last control points + wxNode *first = m_lineControlPoints->First(); + wxRealPoint *first_point = (wxRealPoint *)first->Data(); + + wxNode *last = m_lineControlPoints->Last(); + wxRealPoint *last_point = (wxRealPoint *)last->Data(); + + // If any of the line points are at -999, we must + // initialize them by placing them half way between the first + // and the last. + wxNode *node = first->Next(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + if (point->x == -999) + { + double x1, y1, x2, y2; + if (first_point->x < last_point->x) + { x1 = first_point->x; x2 = last_point->x; } + else + { x2 = first_point->x; x1 = last_point->x; } + + if (first_point->y < last_point->y) + { y1 = first_point->y; y2 = last_point->y; } + else + { y2 = first_point->y; y1 = last_point->y; } + + point->x = ((x2 - x1)/2 + x1); + point->y = ((y2 - y1)/2 + y1); + } + node = node->Next(); + } + } +} + +// Format a text string according to the region size, adding +// strings with positions to region text list +void wxLineShape::FormatText(wxDC& dc, const wxString& s, int i) +{ + double w, h; + ClearText(i); + + if (m_regions.Number() < 1) + return; + wxNode *node = m_regions.Nth(i); + if (!node) + return; + + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + region->SetText(s); + dc.SetFont(* region->GetFont()); + + region->GetSize(&w, &h); + // Initialize the size if zero + if (((w == 0) || (h == 0)) && (strlen(s) > 0)) + { + w = 100; h = 50; + region->SetSize(w, h); + } + + wxStringList *string_list = oglFormatText(dc, s, (w-5), (h-5), region->GetFormatMode()); + node = string_list->First(); + while (node) + { + char *s = (char *)node->Data(); + wxShapeTextLine *line = new wxShapeTextLine(0.0, 0.0, s); + region->GetFormattedText().Append((wxObject *)line); + node = node->Next(); + } + delete string_list; + double actualW = w; + double actualH = h; + if (region->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS) + { + oglGetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH); + if ((actualW != w ) || (actualH != h)) + { + double xx, yy; + GetLabelPosition(i, &xx, &yy); + EraseRegion(dc, region, xx, yy); + if (m_labelObjects[i]) + { + m_labelObjects[i]->Select(FALSE, &dc); + m_labelObjects[i]->Erase(dc); + m_labelObjects[i]->SetSize(actualW, actualH); + } + + region->SetSize(actualW, actualH); + + if (m_labelObjects[i]) + { + m_labelObjects[i]->Select(TRUE, & dc); + m_labelObjects[i]->Draw(dc); + } + } + } + oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW, actualH, region->GetFormatMode()); + m_formatted = TRUE; +} + +void wxLineShape::DrawRegion(wxDC& dc, wxShapeRegion *region, double x, double y) +{ + if (GetDisableLabel()) + return; + + double w, h; + double xx, yy; + region->GetSize(&w, &h); + + // Get offset from x, y + region->GetPosition(&xx, &yy); + + double xp = xx + x; + double yp = yy + y; + + // First, clear a rectangle for the text IF there is any + if (region->GetFormattedText().Number() > 0) + { + dc.SetPen(* g_oglWhiteBackgroundPen); + dc.SetBrush(* g_oglWhiteBackgroundBrush); + + // Now draw the text + if (region->GetFont()) dc.SetFont(* region->GetFont()); + + dc.DrawRectangle((long)(xp - w/2.0), (long)(yp - h/2.0), (long)w, (long)h); + + if (m_pen) dc.SetPen(* m_pen); + dc.SetTextForeground(* region->GetActualColourObject()); + +#ifdef __WXMSW__ + dc.SetTextBackground(g_oglWhiteBackgroundBrush->GetColour()); +#endif + + oglDrawFormattedText(dc, &(region->GetFormattedText()), xp, yp, w, h, region->GetFormatMode()); + } +} + +void wxLineShape::EraseRegion(wxDC& dc, wxShapeRegion *region, double x, double y) +{ + if (GetDisableLabel()) + return; + + double w, h; + double xx, yy; + region->GetSize(&w, &h); + + // Get offset from x, y + region->GetPosition(&xx, &yy); + + double xp = xx + x; + double yp = yy + y; + + if (region->GetFormattedText().Number() > 0) + { + dc.SetPen(* g_oglWhiteBackgroundPen); + dc.SetBrush(* g_oglWhiteBackgroundBrush); + + dc.DrawRectangle((long)(xp - w/2.0), (long)(yp - h/2.0), (long)w, (long)h); + } +} + +// Get the reference point for a label. Region x and y +// are offsets from this. +// position is 0, 1, 2 +void wxLineShape::GetLabelPosition(int position, double *x, double *y) +{ + switch (position) + { + case 0: + { + // Want to take the middle section for the label + int n = m_lineControlPoints->Number(); + int half_way = (int)(n/2); + + // Find middle of this line + wxNode *node = m_lineControlPoints->Nth(half_way - 1); + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxNode *next_node = node->Next(); + wxRealPoint *next_point = (wxRealPoint *)next_node->Data(); + + double dx = (next_point->x - point->x); + double dy = (next_point->y - point->y); + *x = (double)(point->x + dx/2.0); + *y = (double)(point->y + dy/2.0); + break; + } + case 1: + { + wxNode *node = m_lineControlPoints->First(); + *x = ((wxRealPoint *)node->Data())->x; + *y = ((wxRealPoint *)node->Data())->y; + break; + } + case 2: + { + wxNode *node = m_lineControlPoints->Last(); + *x = ((wxRealPoint *)node->Data())->x; + *y = ((wxRealPoint *)node->Data())->y; + break; + } + default: + break; + } +} + +/* + * Find whether line is supposed to be vertical or horizontal and + * make it so. + * + */ +void GraphicsStraightenLine(wxRealPoint *point1, wxRealPoint *point2) +{ + double dx = point2->x - point1->x; + double dy = point2->y - point1->y; + + if (dx == 0.0) + return; + else if (fabs(dy/dx) > 1.0) + { + point2->x = point1->x; + } + else point2->y = point1->y; +} + +void wxLineShape::Straighten(wxDC *dc) +{ + if (!m_lineControlPoints || m_lineControlPoints->Number() < 3) + return; + + if (dc) + Erase(* dc); + + wxNode *first_point_node = m_lineControlPoints->First(); + wxNode *last_point_node = m_lineControlPoints->Last(); + wxNode *second_last_point_node = last_point_node->Previous(); + + wxRealPoint *last_point = (wxRealPoint *)last_point_node->Data(); + wxRealPoint *second_last_point = (wxRealPoint *)second_last_point_node->Data(); + + GraphicsStraightenLine(last_point, second_last_point); + + wxNode *node = first_point_node; + while (node && (node != second_last_point_node)) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxRealPoint *next_point = (wxRealPoint *)(node->Next()->Data()); + + GraphicsStraightenLine(point, next_point); + node = node->Next(); + } + + if (dc) + Draw(* dc); +} + + +void wxLineShape::Unlink() +{ + if (m_to) + m_to->GetLines().DeleteObject(this); + if (m_from) + m_from->GetLines().DeleteObject(this); + m_to = NULL; + m_from = NULL; +} + +void wxLineShape::SetEnds(double x1, double y1, double x2, double y2) +{ + // Find centre point + wxNode *first_point_node = m_lineControlPoints->First(); + wxNode *last_point_node = m_lineControlPoints->Last(); + wxRealPoint *first_point = (wxRealPoint *)first_point_node->Data(); + wxRealPoint *last_point = (wxRealPoint *)last_point_node->Data(); + + first_point->x = x1; + first_point->y = y1; + last_point->x = x2; + last_point->y = y2; + + m_xpos = (double)((x1 + x2)/2.0); + m_ypos = (double)((y1 + y2)/2.0); +} + +// Get absolute positions of ends +void wxLineShape::GetEnds(double *x1, double *y1, double *x2, double *y2) +{ + wxNode *first_point_node = m_lineControlPoints->First(); + wxNode *last_point_node = m_lineControlPoints->Last(); + wxRealPoint *first_point = (wxRealPoint *)first_point_node->Data(); + wxRealPoint *last_point = (wxRealPoint *)last_point_node->Data(); + + *x1 = first_point->x; *y1 = first_point->y; + *x2 = last_point->x; *y2 = last_point->y; +} + +void wxLineShape::SetAttachments(int from_attach, int to_attach) +{ + m_attachmentFrom = from_attach; + m_attachmentTo = to_attach; +} + +bool wxLineShape::HitTest(double x, double y, int *attachment, double *distance) +{ + if (!m_lineControlPoints) + return FALSE; + + // Look at label regions in case mouse is over a label + bool inLabelRegion = FALSE; + for (int i = 0; i < 3; i ++) + { + wxNode *regionNode = m_regions.Nth(i); + if (regionNode) + { + wxShapeRegion *region = (wxShapeRegion *)regionNode->Data(); + if (region->m_formattedText.Number() > 0) + { + double xp, yp, cx, cy, cw, ch; + GetLabelPosition(i, &xp, &yp); + // Offset region from default label position + region->GetPosition(&cx, &cy); + region->GetSize(&cw, &ch); + cx += xp; + cy += yp; + double rLeft = (double)(cx - (cw/2.0)); + double rTop = (double)(cy - (ch/2.0)); + double rRight = (double)(cx + (cw/2.0)); + double rBottom = (double)(cy + (ch/2.0)); + if (x > rLeft && x < rRight && y > rTop && y < rBottom) + { + inLabelRegion = TRUE; + i = 3; + } + } + } + } + + wxNode *node = m_lineControlPoints->First(); + + while (node && node->Next()) + { + wxRealPoint *point1 = (wxRealPoint *)node->Data(); + wxRealPoint *point2 = (wxRealPoint *)node->Next()->Data(); + + // Allow for inaccurate mousing or vert/horiz lines + int extra = 4; + double left = wxMin(point1->x, point2->x) - extra; + double right = wxMax(point1->x, point2->x) + extra; + + double bottom = wxMin(point1->y, point2->y) - extra; + double top = wxMax(point1->y, point2->y) + extra; + + if ((x > left && x < right && y > bottom && y < top) || inLabelRegion) + { + // Work out distance from centre of line + double centre_x = (double)(left + (right - left)/2.0); + double centre_y = (double)(bottom + (top - bottom)/2.0); + + *attachment = 0; + *distance = (double)sqrt((centre_x - x)*(centre_x - x) + (centre_y - y)*(centre_y - y)); + return TRUE; + } + + node = node->Next(); + } + return FALSE; +} + +void wxLineShape::DrawArrows(wxDC& dc) +{ + // Distance along line of each arrow: space them out evenly. + double startArrowPos = 0.0; + double endArrowPos = 0.0; + double middleArrowPos = 0.0; + + wxNode *node = m_arcArrows.First(); + while (node) + { + wxArrowHead *arrow = (wxArrowHead *)node->Data(); + switch (arrow->GetArrowEnd()) + { + case ARROW_POSITION_START: + { + if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets) + // If specified, x offset is proportional to line length + DrawArrow(dc, arrow, arrow->GetXOffset(), TRUE); + else + { + DrawArrow(dc, arrow, startArrowPos, FALSE); // Absolute distance + startArrowPos += arrow->GetSize() + arrow->GetSpacing(); + } + break; + } + case ARROW_POSITION_END: + { + if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets) + DrawArrow(dc, arrow, arrow->GetXOffset(), TRUE); + else + { + DrawArrow(dc, arrow, endArrowPos, FALSE); + endArrowPos += arrow->GetSize() + arrow->GetSpacing(); + } + break; + } + case ARROW_POSITION_MIDDLE: + { + arrow->SetXOffset(middleArrowPos); + if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets) + DrawArrow(dc, arrow, arrow->GetXOffset(), TRUE); + else + { + DrawArrow(dc, arrow, middleArrowPos, FALSE); + middleArrowPos += arrow->GetSize() + arrow->GetSpacing(); + } + break; + } + } + node = node->Next(); + } +} + +void wxLineShape::DrawArrow(wxDC& dc, wxArrowHead *arrow, double xOffset, bool proportionalOffset) +{ + wxNode *first_line_node = m_lineControlPoints->First(); + wxRealPoint *first_line_point = (wxRealPoint *)first_line_node->Data(); + wxNode *second_line_node = first_line_node->Next(); + wxRealPoint *second_line_point = (wxRealPoint *)second_line_node->Data(); + + wxNode *last_line_node = m_lineControlPoints->Last(); + wxRealPoint *last_line_point = (wxRealPoint *)last_line_node->Data(); + wxNode *second_last_line_node = last_line_node->Previous(); + wxRealPoint *second_last_line_point = (wxRealPoint *)second_last_line_node->Data(); + + // Position where we want to start drawing + double positionOnLineX, positionOnLineY; + + // Position of start point of line, at the end of which we draw the arrow. + double startPositionX, startPositionY; + + switch (arrow->GetPosition()) + { + case ARROW_POSITION_START: + { + // If we're using a proportional offset, calculate just where this will + // be on the line. + double realOffset = xOffset; + if (proportionalOffset) + { + double totalLength = + (double)sqrt((second_line_point->x - first_line_point->x)*(second_line_point->x - first_line_point->x) + + (second_line_point->y - first_line_point->y)*(second_line_point->y - first_line_point->y)); + realOffset = (double)(xOffset * totalLength); + } + GetPointOnLine(second_line_point->x, second_line_point->y, + first_line_point->x, first_line_point->y, + realOffset, &positionOnLineX, &positionOnLineY); + startPositionX = second_line_point->x; + startPositionY = second_line_point->y; + break; + } + case ARROW_POSITION_END: + { + // If we're using a proportional offset, calculate just where this will + // be on the line. + double realOffset = xOffset; + if (proportionalOffset) + { + double totalLength = + (double)sqrt((second_last_line_point->x - last_line_point->x)*(second_last_line_point->x - last_line_point->x) + + (second_last_line_point->y - last_line_point->y)*(second_last_line_point->y - last_line_point->y)); + realOffset = (double)(xOffset * totalLength); + } + GetPointOnLine(second_last_line_point->x, second_last_line_point->y, + last_line_point->x, last_line_point->y, + realOffset, &positionOnLineX, &positionOnLineY); + startPositionX = second_last_line_point->x; + startPositionY = second_last_line_point->y; + break; + } + case ARROW_POSITION_MIDDLE: + { + // Choose a point half way between the last and penultimate points + double x = ((last_line_point->x + second_last_line_point->x)/2); + double y = ((last_line_point->y + second_last_line_point->y)/2); + + // If we're using a proportional offset, calculate just where this will + // be on the line. + double realOffset = xOffset; + if (proportionalOffset) + { + double totalLength = + (double)sqrt((second_last_line_point->x - x)*(second_last_line_point->x - x) + + (second_last_line_point->y - y)*(second_last_line_point->y - y)); + realOffset = (double)(xOffset * totalLength); + } + + GetPointOnLine(second_last_line_point->x, second_last_line_point->y, + x, y, realOffset, &positionOnLineX, &positionOnLineY); + startPositionX = second_last_line_point->x; + startPositionY = second_last_line_point->y; + break; + } + } + + /* + * Add yOffset to arrow, if any + */ + + const double myPi = (double) 3.14159265; + // The translation that the y offset may give + double deltaX = 0.0; + double deltaY = 0.0; + if ((arrow->GetYOffset() != 0.0) && !m_ignoreArrowOffsets) + { + /* + |(x4, y4) + |d + | + (x1, y1)--------------(x3, y3)------------------(x2, y2) + x4 = x3 - d * sin(theta) + y4 = y3 + d * cos(theta) + + Where theta = tan(-1) of (y3-y1)/(x3-x1) + */ + double x1 = startPositionX; + double y1 = startPositionY; + double x3 = positionOnLineX; + double y3 = positionOnLineY; + double d = -arrow->GetYOffset(); // Negate so +offset is above line + + double theta = 0.0; + if (x3 == x1) + theta = (double)(myPi/2.0); + else + theta = (double)atan((y3-y1)/(x3-x1)); + + double x4 = (double)(x3 - (d*sin(theta))); + double y4 = (double)(y3 + (d*cos(theta))); + + deltaX = x4 - positionOnLineX; + deltaY = y4 - positionOnLineY; + } + + switch (arrow->_GetType()) + { + case ARROW_ARROW: + { + double arrowLength = arrow->GetSize(); + double arrowWidth = (double)(arrowLength/3.0); + + double tip_x, tip_y, side1_x, side1_y, side2_x, side2_y; + oglGetArrowPoints(startPositionX+deltaX, startPositionY+deltaY, + positionOnLineX+deltaX, positionOnLineY+deltaY, + arrowLength, arrowWidth, &tip_x, &tip_y, + &side1_x, &side1_y, &side2_x, &side2_y); + + wxPoint points[4]; + points[0].x = (int) tip_x; points[0].y = (int) tip_y; + points[1].x = (int) side1_x; points[1].y = (int) side1_y; + points[2].x = (int) side2_x; points[2].y = (int) side2_y; + points[3].x = (int) tip_x; points[3].y = (int) tip_y; + + dc.SetPen(* m_pen); + dc.SetBrush(* m_brush); + dc.DrawPolygon(4, points); + break; + } + case ARROW_HOLLOW_CIRCLE: + case ARROW_FILLED_CIRCLE: + { + // Find point on line of centre of circle, which is a radius away + // from the end position + double diameter = (double)(arrow->GetSize()); + double x, y; + GetPointOnLine(startPositionX+deltaX, startPositionY+deltaY, + positionOnLineX+deltaX, positionOnLineY+deltaY, + (double)(diameter/2.0), + &x, &y); + + // Convert ellipse centre to top-left coordinates + double x1 = (double)(x - (diameter/2.0)); + double y1 = (double)(y - (diameter/2.0)); + + dc.SetPen(* m_pen); + if (arrow->_GetType() == ARROW_HOLLOW_CIRCLE) + dc.SetBrush(* g_oglWhiteBackgroundBrush); + else + dc.SetBrush(* m_brush); + + dc.DrawEllipse((long) x1, (long) y1, (long) diameter, (long) diameter); + break; + } + case ARROW_SINGLE_OBLIQUE: + { + break; + } + case ARROW_METAFILE: + { + if (arrow->GetMetaFile()) + { + // Find point on line of centre of object, which is a half-width away + // from the end position + /* + * width + * <-- start pos <-----><-- positionOnLineX + * _____ + * --------------| x | <-- e.g. rectangular arrowhead + * ----- + */ + double x, y; + GetPointOnLine(startPositionX, startPositionY, + positionOnLineX, positionOnLineY, + (double)(arrow->GetMetaFile()->m_width/2.0), + &x, &y); + + // Calculate theta for rotating the metafile. + /* + | + | o(x2, y2) 'o' represents the arrowhead. + | / + | / + | /theta + | /(x1, y1) + |______________________ + */ + double theta = 0.0; + double x1 = startPositionX; + double y1 = startPositionY; + double x2 = positionOnLineX; + double y2 = positionOnLineY; + + if ((x1 == x2) && (y1 == y2)) + theta = 0.0; + + else if ((x1 == x2) && (y1 > y2)) + theta = (double)(3.0*myPi/2.0); + + else if ((x1 == x2) && (y2 > y1)) + theta = (double)(myPi/2.0); + + else if ((x2 > x1) && (y2 >= y1)) + theta = (double)atan((y2 - y1)/(x2 - x1)); + + else if (x2 < x1) + theta = (double)(myPi + atan((y2 - y1)/(x2 - x1))); + + else if ((x2 > x1) && (y2 < y1)) + theta = (double)(2*myPi + atan((y2 - y1)/(x2 - x1))); + + else + { + wxFatalError("Unknown arrowhead rotation case in lines.cc"); + } + + // Rotate about the centre of the object, then place + // the object on the line. + if (arrow->GetMetaFile()->GetRotateable()) + arrow->GetMetaFile()->Rotate(0.0, 0.0, theta); + + if (m_erasing) + { + // If erasing, just draw a rectangle. + double minX, minY, maxX, maxY; + arrow->GetMetaFile()->GetBounds(&minX, &minY, &maxX, &maxY); + // Make erasing rectangle slightly bigger or you get droppings. + int extraPixels = 4; + dc.DrawRectangle((long)(deltaX + x + minX - (extraPixels/2.0)), (long)(deltaY + y + minY - (extraPixels/2.0)), + (long)(maxX - minX + extraPixels), (long)(maxY - minY + extraPixels)); + } + else + arrow->GetMetaFile()->Draw(dc, x+deltaX, y+deltaY); + } + break; + } + default: + { + } + } +} + +void wxLineShape::OnErase(wxDC& dc) +{ + wxPen *old_pen = m_pen; + wxBrush *old_brush = m_brush; + SetPen(g_oglWhiteBackgroundPen); + SetBrush(g_oglWhiteBackgroundBrush); + + double bound_x, bound_y; + GetBoundingBoxMax(&bound_x, &bound_y); + if (m_font) dc.SetFont(* m_font); + + // Undraw text regions + for (int i = 0; i < 3; i++) + { + wxNode *node = m_regions.Nth(i); + if (node) + { + double x, y; + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + GetLabelPosition(i, &x, &y); + EraseRegion(dc, region, x, y); + } + } + + // Undraw line + dc.SetPen(* g_oglWhiteBackgroundPen); + dc.SetBrush(* g_oglWhiteBackgroundBrush); + + // Drawing over the line only seems to work if the line has a thickness + // of 1. + if (old_pen && (old_pen->GetWidth() > 1)) + { + dc.DrawRectangle((long)(m_xpos - (bound_x/2.0) - 2.0), (long)(m_ypos - (bound_y/2.0) - 2.0), + (long)(bound_x+4.0), (long)(bound_y+4.0)); + } + else + { + m_erasing = TRUE; + GetEventHandler()->OnDraw(dc); + GetEventHandler()->OnEraseControlPoints(dc); + m_erasing = FALSE; + } + + if (old_pen) SetPen(old_pen); + if (old_brush) SetBrush(old_brush); +} + +void wxLineShape::GetBoundingBoxMin(double *w, double *h) +{ + double x1 = 10000; + double y1 = 10000; + double x2 = -10000; + double y2 = -10000; + + wxNode *node = m_lineControlPoints->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + + if (point->x < x1) x1 = point->x; + if (point->y < y1) y1 = point->y; + if (point->x > x2) x2 = point->x; + if (point->y > y2) y2 = point->y; + + node = node->Next(); + } + *w = (double)(x2 - x1); + *h = (double)(y2 - y1); +} + +/* + * For a node image of interest, finds the position of this arc + * amongst all the arcs which are attached to THIS SIDE of the node image, + * and the number of same. + */ +void wxLineShape::FindNth(wxShape *image, int *nth, int *no_arcs, bool incoming) +{ + int n = -1; + int num = 0; + wxNode *node = image->GetLines().First(); + int this_attachment; + if (image == m_to) + this_attachment = m_attachmentTo; + else + this_attachment = m_attachmentFrom; + + // Find number of lines going into/out of this particular attachment point + while (node) + { + wxLineShape *line = (wxLineShape *)node->Data(); + + if (line->m_from == image) + { + // This is the nth line attached to 'image' + if ((line == this) && !incoming) + n = num; + + // Increment num count if this is the same side (attachment number) + if (line->m_attachmentFrom == this_attachment) + num ++; + } + + if (line->m_to == image) + { + // This is the nth line attached to 'image' + if ((line == this) && incoming) + n = num; + + // Increment num count if this is the same side (attachment number) + if (line->m_attachmentTo == this_attachment) + num ++; + } + + node = node->Next(); + } + *nth = n; + *no_arcs = num; +} + +void wxLineShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h) +{ + wxPen *old_pen = m_pen; + wxBrush *old_brush = m_brush; + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + SetPen(& dottedPen); + SetBrush( wxTRANSPARENT_BRUSH ); + + GetEventHandler()->OnDraw(dc); + + if (old_pen) SetPen(old_pen); + else SetPen(NULL); + if (old_brush) SetBrush(old_brush); + else SetBrush(NULL); +} + +bool wxLineShape::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display) +{ + double x_offset = x - old_x; + double y_offset = y - old_y; + + if (m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0)) + { + wxNode *node = m_lineControlPoints->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + point->x += x_offset; + point->y += y_offset; + node = node->Next(); + } + + } + + // Move temporary label rectangles if necessary + for (int i = 0; i < 3; i++) + { + if (m_labelObjects[i]) + { + m_labelObjects[i]->Erase(dc); + double xp, yp, xr, yr; + GetLabelPosition(i, &xp, &yp); + wxNode *node = m_regions.Nth(i); + if (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + region->GetPosition(&xr, &yr); + } + else + { + xr = 0.0; yr = 0.0; + } + + m_labelObjects[i]->Move(dc, xp+xr, yp+yr); + } + } + return TRUE; +} + +void wxLineShape::OnMoveLink(wxDC& dc, bool moveControlPoints) +{ + if (!m_from || !m_to) + return; + + if (m_lineControlPoints->Number() > 2) + Initialise(); + + // Do each end - nothing in the middle. User has to move other points + // manually if necessary. + double end_x, end_y; + double other_end_x, other_end_y; + + FindLineEndPoints(&end_x, &end_y, &other_end_x, &other_end_y); + + wxNode *first = m_lineControlPoints->First(); + wxRealPoint *first_point = (wxRealPoint *)first->Data(); + wxNode *last = m_lineControlPoints->Last(); + wxRealPoint *last_point = (wxRealPoint *)last->Data(); + +/* This is redundant, surely? Done by SetEnds. + first_point->x = end_x; first_point->y = end_y; + last_point->x = other_end_x; last_point->y = other_end_y; +*/ + + double oldX = m_xpos; + double oldY = m_ypos; + + SetEnds(end_x, end_y, other_end_x, other_end_y); + + // Do a second time, because one may depend on the other. + FindLineEndPoints(&end_x, &end_y, &other_end_x, &other_end_y); + SetEnds(end_x, end_y, other_end_x, other_end_y); + + // Try to move control points with the arc + double x_offset = m_xpos - oldX; + double y_offset = m_ypos - oldY; + +// if (moveControlPoints && m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0)) + // Only move control points if it's a self link. And only works if attachment mode is ON. + if ((m_from == m_to) && (m_from->GetAttachmentMode() != ATTACHMENT_MODE_NONE) && moveControlPoints && m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0)) + { + wxNode *node = m_lineControlPoints->First(); + while (node) + { + if ((node != m_lineControlPoints->First()) && (node != m_lineControlPoints->Last())) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + point->x += x_offset; + point->y += y_offset; + } + node = node->Next(); + } + } + + Move(dc, m_xpos, m_ypos); +} + +// Finds the x, y points at the two ends of the line. +// This function can be used by e.g. line-routing routines to +// get the actual points on the two node images where the lines will be drawn +// to/from. +void wxLineShape::FindLineEndPoints(double *fromX, double *fromY, double *toX, double *toY) +{ + if (!m_from || !m_to) + return; + + // Do each end - nothing in the middle. User has to move other points + // manually if necessary. + double end_x, end_y; + double other_end_x, other_end_y; + + wxNode *first = m_lineControlPoints->First(); + wxRealPoint *first_point = (wxRealPoint *)first->Data(); + wxNode *last = m_lineControlPoints->Last(); + wxRealPoint *last_point = (wxRealPoint *)last->Data(); + + wxNode *second = first->Next(); + wxRealPoint *second_point = (wxRealPoint *)second->Data(); + + wxNode *second_last = last->Previous(); + wxRealPoint *second_last_point = (wxRealPoint *)second_last->Data(); + + if (m_lineControlPoints->Number() > 2) + { + if (m_from->GetAttachmentMode() != ATTACHMENT_MODE_NONE) + { + int nth, no_arcs; + FindNth(m_from, &nth, &no_arcs, FALSE); // Not incoming + m_from->GetAttachmentPosition(m_attachmentFrom, &end_x, &end_y, nth, no_arcs, this); + } + else + (void) m_from->GetPerimeterPoint(m_from->GetX(), m_from->GetY(), + (double)second_point->x, (double)second_point->y, + &end_x, &end_y); + + if (m_to->GetAttachmentMode() != ATTACHMENT_MODE_NONE) + { + int nth, no_arcs; + FindNth(m_to, &nth, &no_arcs, TRUE); // Incoming + m_to->GetAttachmentPosition(m_attachmentTo, &other_end_x, &other_end_y, nth, no_arcs, this); + } + else + (void) m_to->GetPerimeterPoint(m_to->GetX(), m_to->GetY(), + (double)second_last_point->x, (double)second_last_point->y, + &other_end_x, &other_end_y); + } + else + { + double fromX = m_from->GetX(); + double fromY = m_from->GetY(); + double toX = m_to->GetX(); + double toY = m_to->GetY(); + + if (m_from->GetAttachmentMode() != ATTACHMENT_MODE_NONE) + { + int nth, no_arcs; + FindNth(m_from, &nth, &no_arcs, FALSE); + m_from->GetAttachmentPosition(m_attachmentFrom, &end_x, &end_y, nth, no_arcs, this); + fromX = end_x; + fromY = end_y; + } + + if (m_to->GetAttachmentMode() != ATTACHMENT_MODE_NONE) + { + int nth, no_arcs; + FindNth(m_to, &nth, &no_arcs, TRUE); + m_to->GetAttachmentPosition(m_attachmentTo, &other_end_x, &other_end_y, nth, no_arcs, this); + toX = other_end_x; + toY = other_end_y; + } + + if (m_from->GetAttachmentMode() == ATTACHMENT_MODE_NONE) + (void) m_from->GetPerimeterPoint(m_from->GetX(), m_from->GetY(), + toX, toY, + &end_x, &end_y); + + if (m_to->GetAttachmentMode() == ATTACHMENT_MODE_NONE) + (void) m_to->GetPerimeterPoint(m_to->GetX(), m_to->GetY(), + fromX, fromY, + &other_end_x, &other_end_y); + } + *fromX = end_x; + *fromY = end_y; + *toX = other_end_x; + *toY = other_end_y; +} + +void wxLineShape::OnDraw(wxDC& dc) +{ + if (m_lineControlPoints) + { + if (m_pen) + dc.SetPen(* m_pen); + if (m_brush) + dc.SetBrush(* m_brush); + + int n = m_lineControlPoints->Number(); + wxPoint *points = new wxPoint[n]; + int i; + for (i = 0; i < n; i++) + { + wxRealPoint* point = (wxRealPoint*) m_lineControlPoints->Nth(i)->Data(); + points[i].x = WXROUND(point->x); + points[i].y = WXROUND(point->y); + } + + if (m_isSpline) + dc.DrawSpline(n, points); + else + dc.DrawLines(n, points); + +#ifdef __WXMSW__ + // For some reason, last point isn't drawn under Windows. + dc.DrawPoint(points[n-1]); +#endif + + delete[] points; + + + // Problem with pen - if not a solid pen, does strange things + // to the arrowhead. So make (get) a new pen that's solid. + if (m_pen && (m_pen->GetStyle() != wxSOLID)) + { + wxPen *solid_pen = + wxThePenList->FindOrCreatePen(m_pen->GetColour(), 1, wxSOLID); + if (solid_pen) + dc.SetPen(* solid_pen); + } + DrawArrows(dc); + } +} + +void wxLineShape::OnDrawControlPoints(wxDC& dc) +{ + if (!m_drawHandles) + return; + + // Draw temporary label rectangles if necessary + for (int i = 0; i < 3; i++) + { + if (m_labelObjects[i]) + m_labelObjects[i]->Draw(dc); + } + wxShape::OnDrawControlPoints(dc); +} + +void wxLineShape::OnEraseControlPoints(wxDC& dc) +{ + // Erase temporary label rectangles if necessary + for (int i = 0; i < 3; i++) + { + if (m_labelObjects[i]) + m_labelObjects[i]->Erase(dc); + } + wxShape::OnEraseControlPoints(dc); +} + +void wxLineShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment) +{ +} + +void wxLineShape::OnBeginDragLeft(double x, double y, int keys, int attachment) +{ +} + +void wxLineShape::OnEndDragLeft(double x, double y, int keys, int attachment) +{ +} + +/* +void wxLineShape::SetArrowSize(double length, double width) +{ + arrow_length = length; + arrow_width = width; +} + +void wxLineShape::SetStartArrow(int style) +{ + start_style = style; +} + +void wxLineShape::SetMiddleArrow(int style) +{ + middle_style = style; +} + +void wxLineShape::SetEndArrow(int style) +{ + end_style = style; +} +*/ + +void wxLineShape::OnDrawContents(wxDC& dc) +{ + if (GetDisableLabel()) + return; + + for (int i = 0; i < 3; i++) + { + wxNode *node = m_regions.Nth(i); + if (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + double x, y; + GetLabelPosition(i, &x, &y); + DrawRegion(dc, region, x, y); + } + } +} + +void wxLineShape::SetTo(wxShape *object) +{ + m_to = object; +} + +void wxLineShape::SetFrom(wxShape *object) +{ + m_from = object; +} + +void wxLineShape::MakeControlPoints() +{ + if (m_canvas && m_lineControlPoints) + { + wxNode *first = m_lineControlPoints->First(); + wxNode *last = m_lineControlPoints->Last(); + wxRealPoint *first_point = (wxRealPoint *)first->Data(); + wxRealPoint *last_point = (wxRealPoint *)last->Data(); + + wxLineControlPoint *control = new wxLineControlPoint(m_canvas, this, CONTROL_POINT_SIZE, + first_point->x, first_point->y, + CONTROL_POINT_ENDPOINT_FROM); + control->m_point = first_point; + m_canvas->AddShape(control); + m_controlPoints.Append(control); + + + wxNode *node = first->Next(); + while (node != last) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + + control = new wxLineControlPoint(m_canvas, this, CONTROL_POINT_SIZE, + point->x, point->y, + CONTROL_POINT_LINE); + control->m_point = point; + + m_canvas->AddShape(control); + m_controlPoints.Append(control); + + node = node->Next(); + } + control = new wxLineControlPoint(m_canvas, this, CONTROL_POINT_SIZE, + last_point->x, last_point->y, + CONTROL_POINT_ENDPOINT_TO); + control->m_point = last_point; + m_canvas->AddShape(control); + m_controlPoints.Append(control); + + } + +} + +void wxLineShape::ResetControlPoints() +{ + if (m_canvas && m_lineControlPoints && m_controlPoints.Number() > 0) + { + wxNode *node = m_controlPoints.First(); + wxNode *control_node = m_lineControlPoints->First(); + while (node && control_node) + { + wxRealPoint *point = (wxRealPoint *)control_node->Data(); + wxLineControlPoint *control = (wxLineControlPoint *)node->Data(); + control->SetX(point->x); + control->SetY(point->y); + + node = node->Next(); + control_node = control_node->Next(); + } + } +} + +#ifdef PROLOGIO +void wxLineShape::WriteAttributes(wxExpr *clause) +{ + wxShape::WriteAttributes(clause); + + if (m_from) + clause->AddAttributeValue("from", m_from->GetId()); + if (m_to) + clause->AddAttributeValue("to", m_to->GetId()); + + if (m_attachmentTo != 0) + clause->AddAttributeValue("attachment_to", (long)m_attachmentTo); + if (m_attachmentFrom != 0) + clause->AddAttributeValue("attachment_from", (long)m_attachmentFrom); + + if (m_alignmentStart != 0) + clause->AddAttributeValue("align_start", (long)m_alignmentStart); + if (m_alignmentEnd != 0) + clause->AddAttributeValue("align_end", (long)m_alignmentEnd); + + clause->AddAttributeValue("is_spline", (long)m_isSpline); + if (m_maintainStraightLines) + clause->AddAttributeValue("keep_lines_straight", (long)m_maintainStraightLines); + + // Make a list of lists for the (sp)line controls + wxExpr *list = new wxExpr(wxExprList); + wxNode *node = m_lineControlPoints->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxExpr *point_list = new wxExpr(wxExprList); + wxExpr *x_expr = new wxExpr((double) point->x); + wxExpr *y_expr = new wxExpr((double) point->y); + point_list->Append(x_expr); + point_list->Append(y_expr); + list->Append(point_list); + + node = node->Next(); + } + clause->AddAttributeValue("controls", list); + + // Write arc arrows in new OGL format, if there are any. + // This is a list of lists. Each sublist comprises: + // (arrowType arrowEnd xOffset arrowSize) + if (m_arcArrows.Number() > 0) + { + wxExpr *arrow_list = new wxExpr(wxExprList); + node = m_arcArrows.First(); + while (node) + { + wxArrowHead *head = (wxArrowHead *)node->Data(); + wxExpr *head_list = new wxExpr(wxExprList); + head_list->Append(new wxExpr((long)head->_GetType())); + head_list->Append(new wxExpr((long)head->GetArrowEnd())); + head_list->Append(new wxExpr(head->GetXOffset())); + head_list->Append(new wxExpr(head->GetArrowSize())); + head_list->Append(new wxExpr(wxExprString, head->GetName())); + head_list->Append(new wxExpr(head->GetId())); + + // New members of wxArrowHead + head_list->Append(new wxExpr(head->GetYOffset())); + head_list->Append(new wxExpr(head->GetSpacing())); + + arrow_list->Append(head_list); + + node = node->Next(); + } + clause->AddAttributeValue("arrows", arrow_list); + } +} + +void wxLineShape::ReadAttributes(wxExpr *clause) +{ + wxShape::ReadAttributes(clause); + + int iVal = (int) m_isSpline; + clause->AssignAttributeValue("is_spline", &iVal); + m_isSpline = (iVal != 0); + + iVal = (int) m_maintainStraightLines; + clause->AssignAttributeValue("keep_lines_straight", &iVal); + m_maintainStraightLines = (iVal != 0); + + clause->AssignAttributeValue("align_start", &m_alignmentStart); + clause->AssignAttributeValue("align_end", &m_alignmentEnd); + + // Compatibility: check for no regions. + if (m_regions.Number() == 0) + { + wxShapeRegion *newRegion = new wxShapeRegion; + newRegion->SetName("Middle"); + newRegion->SetSize(150, 50); + m_regions.Append((wxObject *)newRegion); + if (m_text.Number() > 0) + { + newRegion->ClearText(); + wxNode *node = m_text.First(); + while (node) + { + wxShapeTextLine *textLine = (wxShapeTextLine *)node->Data(); + wxNode *next = node->Next(); + newRegion->GetFormattedText().Append((wxObject *)textLine); + delete node; + node = next; + } + } + + newRegion = new wxShapeRegion; + newRegion->SetName("Start"); + newRegion->SetSize(150, 50); + m_regions.Append((wxObject *)newRegion); + + newRegion = new wxShapeRegion; + newRegion->SetName("End"); + newRegion->SetSize(150, 50); + m_regions.Append((wxObject *)newRegion); + } + + m_attachmentTo = 0; + m_attachmentFrom = 0; + + clause->AssignAttributeValue("attachment_to", &m_attachmentTo); + clause->AssignAttributeValue("attachment_from", &m_attachmentFrom); + + wxExpr *line_list = NULL; + + // When image is created, there are default control points. Override + // them if there are some in the file. + clause->AssignAttributeValue("controls", &line_list); + + if (line_list) + { + // Read a list of lists for the spline controls + if (m_lineControlPoints) + { + ClearPointList(*m_lineControlPoints); + } + else + m_lineControlPoints = new wxList; + + wxExpr *node = line_list->value.first; + + while (node) + { + wxExpr *xexpr = node->value.first; + double x = xexpr->RealValue(); + + wxExpr *yexpr = xexpr->next; + double y = yexpr->RealValue(); + + wxRealPoint *point = new wxRealPoint(x, y); + m_lineControlPoints->Append((wxObject*) point); + + node = node->next; + } + } + + // Read arrow list, for new OGL code + wxExpr *arrow_list = NULL; + + clause->AssignAttributeValue("arrows", &arrow_list); + if (arrow_list) + { + wxExpr *node = arrow_list->value.first; + + while (node) + { + WXTYPE arrowType = ARROW_ARROW; + int arrowEnd = 0; + double xOffset = 0.0; + double arrowSize = 0.0; + wxString arrowName(""); + long arrowId = -1; + + wxExpr *type_expr = node->Nth(0); + wxExpr *end_expr = node->Nth(1); + wxExpr *dist_expr = node->Nth(2); + wxExpr *size_expr = node->Nth(3); + wxExpr *name_expr = node->Nth(4); + wxExpr *id_expr = node->Nth(5); + + // New members of wxArrowHead + wxExpr *yOffsetExpr = node->Nth(6); + wxExpr *spacingExpr = node->Nth(7); + + if (type_expr) + arrowType = (int)type_expr->IntegerValue(); + if (end_expr) + arrowEnd = (int)end_expr->IntegerValue(); + if (dist_expr) + xOffset = dist_expr->RealValue(); + if (size_expr) + arrowSize = size_expr->RealValue(); + if (name_expr) + arrowName = name_expr->StringValue(); + if (id_expr) + arrowId = id_expr->IntegerValue(); + + if (arrowId == -1) + arrowId = wxNewId(); + else + wxRegisterId(arrowId); + + wxArrowHead *arrowHead = AddArrow(arrowType, arrowEnd, arrowSize, xOffset, (char*) (const char*) arrowName, NULL, arrowId); + if (yOffsetExpr) + arrowHead->SetYOffset(yOffsetExpr->RealValue()); + if (spacingExpr) + arrowHead->SetSpacing(spacingExpr->RealValue()); + + node = node->next; + } + } +} +#endif + +void wxLineShape::Copy(wxShape& copy) +{ + wxShape::Copy(copy); + + wxASSERT( copy.IsKindOf(CLASSINFO(wxLineShape)) ); + + wxLineShape& lineCopy = (wxLineShape&) copy; + + lineCopy.m_to = m_to; + lineCopy.m_from = m_from; + lineCopy.m_attachmentTo = m_attachmentTo; + lineCopy.m_attachmentFrom = m_attachmentFrom; + lineCopy.m_isSpline = m_isSpline; + lineCopy.m_alignmentStart = m_alignmentStart; + lineCopy.m_alignmentEnd = m_alignmentEnd; + lineCopy.m_maintainStraightLines = m_maintainStraightLines; + lineCopy.m_lineOrientations.Clear(); + + wxNode *node = m_lineOrientations.First(); + while (node) + { + lineCopy.m_lineOrientations.Append(node->Data()); + node = node->Next(); + } + + if (lineCopy.m_lineControlPoints) + { + ClearPointList(*lineCopy.m_lineControlPoints); + delete lineCopy.m_lineControlPoints; + } + + lineCopy.m_lineControlPoints = new wxList; + + node = m_lineControlPoints->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + wxRealPoint *new_point = new wxRealPoint(point->x, point->y); + lineCopy.m_lineControlPoints->Append((wxObject*) new_point); + node = node->Next(); + } + + // Copy arrows + lineCopy.ClearArrowsAtPosition(-1); + node = m_arcArrows.First(); + while (node) + { + wxArrowHead *arrow = (wxArrowHead *)node->Data(); + lineCopy.m_arcArrows.Append(new wxArrowHead(*arrow)); + node = node->Next(); + } +} + +// Override select, to create/delete temporary label-moving objects +void wxLineShape::Select(bool select, wxDC* dc) +{ + wxShape::Select(select, dc); + if (select) + { + for (int i = 0; i < 3; i++) + { + wxNode *node = m_regions.Nth(i); + if (node) + { + wxShapeRegion *region = (wxShapeRegion *)node->Data(); + if (region->m_formattedText.Number() > 0) + { + double w, h, x, y, xx, yy; + region->GetSize(&w, &h); + region->GetPosition(&x, &y); + GetLabelPosition(i, &xx, &yy); + if (m_labelObjects[i]) + { + m_labelObjects[i]->Select(FALSE); + m_labelObjects[i]->RemoveFromCanvas(m_canvas); + delete m_labelObjects[i]; + } + m_labelObjects[i] = OnCreateLabelShape(this, region, w, h); + m_labelObjects[i]->AddToCanvas(m_canvas); + m_labelObjects[i]->Show(TRUE); + if (dc) + m_labelObjects[i]->Move(*dc, (double)(x + xx), (double)(y + yy)); + m_labelObjects[i]->Select(TRUE, dc); + } + } + } + } + else + { + for (int i = 0; i < 3; i++) + { + if (m_labelObjects[i]) + { + m_labelObjects[i]->Select(FALSE, dc); + m_labelObjects[i]->Erase(*dc); + m_labelObjects[i]->RemoveFromCanvas(m_canvas); + delete m_labelObjects[i]; + m_labelObjects[i] = NULL; + } + } + } +} + +/* + * Line control point + * + */ + +IMPLEMENT_DYNAMIC_CLASS(wxLineControlPoint, wxControlPoint) + +wxLineControlPoint::wxLineControlPoint(wxShapeCanvas *theCanvas, wxShape *object, double size, double x, double y, int the_type): + wxControlPoint(theCanvas, object, size, x, y, the_type) +{ + m_xpos = x; + m_ypos = y; + m_type = the_type; + m_point = NULL; +} + +wxLineControlPoint::~wxLineControlPoint() +{ +} + +void wxLineControlPoint::OnDraw(wxDC& dc) +{ + wxRectangleShape::OnDraw(dc); +} + +// Implement movement of Line point +void wxLineControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment) +{ + m_shape->GetEventHandler()->OnSizingDragLeft(this, draw, x, y, keys, attachment); +} + +void wxLineControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment) +{ + m_shape->GetEventHandler()->OnSizingBeginDragLeft(this, x, y, keys, attachment); +} + +void wxLineControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment) +{ + m_shape->GetEventHandler()->OnSizingEndDragLeft(this, x, y, keys, attachment); +} + +// Control points ('handles') redirect control to the actual shape, to make it easier +// to override sizing behaviour. +void wxLineShape::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment) +{ + wxLineControlPoint* lpt = (wxLineControlPoint*) pt; + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + dc.SetLogicalFunction(OGLRBLF); + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + dc.SetPen(dottedPen); + dc.SetBrush((* wxTRANSPARENT_BRUSH)); + + if (lpt->m_type == CONTROL_POINT_LINE) + { + m_canvas->Snap(&x, &y); + + lpt->SetX(x); lpt->SetY(y); + lpt->m_point->x = x; lpt->m_point->y = y; + + wxLineShape *lineShape = (wxLineShape *)this; + + wxPen *old_pen = lineShape->GetPen(); + wxBrush *old_brush = lineShape->GetBrush(); + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + lineShape->SetPen(& dottedPen); + lineShape->SetBrush(wxTRANSPARENT_BRUSH); + + lineShape->GetEventHandler()->OnMoveLink(dc, FALSE); + + lineShape->SetPen(old_pen); + lineShape->SetBrush(old_brush); + } + + if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM || lpt->m_type == CONTROL_POINT_ENDPOINT_TO) + { +// lpt->SetX(x); lpt->SetY(y); + } + +} + +void wxLineShape::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment) +{ + wxLineControlPoint* lpt = (wxLineControlPoint*) pt; + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + wxLineShape *lineShape = (wxLineShape *)this; + if (lpt->m_type == CONTROL_POINT_LINE) + { + lpt->m_originalPos = * (lpt->m_point); + m_canvas->Snap(&x, &y); + + this->Erase(dc); + + // Redraw start and end objects because we've left holes + // when erasing the line + lineShape->GetFrom()->OnDraw(dc); + lineShape->GetFrom()->OnDrawContents(dc); + lineShape->GetTo()->OnDraw(dc); + lineShape->GetTo()->OnDrawContents(dc); + + this->SetDisableLabel(TRUE); + dc.SetLogicalFunction(OGLRBLF); + + lpt->m_xpos = x; lpt->m_ypos = y; + lpt->m_point->x = x; lpt->m_point->y = y; + + wxPen *old_pen = lineShape->GetPen(); + wxBrush *old_brush = lineShape->GetBrush(); + + wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); + lineShape->SetPen(& dottedPen); + lineShape->SetBrush(wxTRANSPARENT_BRUSH); + + lineShape->GetEventHandler()->OnMoveLink(dc, FALSE); + + lineShape->SetPen(old_pen); + lineShape->SetBrush(old_brush); + } + + if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM || lpt->m_type == CONTROL_POINT_ENDPOINT_TO) + { + m_canvas->SetCursor(* g_oglBullseyeCursor); + lpt->m_oldCursor = wxSTANDARD_CURSOR; + } +} + +void wxLineShape::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment) +{ + wxLineControlPoint* lpt = (wxLineControlPoint*) pt; + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + this->SetDisableLabel(FALSE); + wxLineShape *lineShape = (wxLineShape *)this; + + if (lpt->m_type == CONTROL_POINT_LINE) + { + m_canvas->Snap(&x, &y); + + wxRealPoint pt = wxRealPoint(x, y); + + // Move the control point back to where it was; + // MoveControlPoint will move it to the new position + // if it decides it wants. We only moved the position + // during user feedback so we could redraw the line + // as it changed shape. + lpt->m_xpos = lpt->m_originalPos.x; lpt->m_ypos = lpt->m_originalPos.y; + lpt->m_point->x = lpt->m_originalPos.x; lpt->m_point->y = lpt->m_originalPos.y; + + OnMoveMiddleControlPoint(dc, lpt, pt); + } + if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM) + { + if (lpt->m_oldCursor) + m_canvas->SetCursor(* lpt->m_oldCursor); + +// this->Erase(dc); + +// lpt->m_xpos = x; lpt->m_ypos = y; + + if (lineShape->GetFrom()) + { + lineShape->GetFrom()->MoveLineToNewAttachment(dc, lineShape, x, y); + } + } + if (lpt->m_type == CONTROL_POINT_ENDPOINT_TO) + { + if (lpt->m_oldCursor) + m_canvas->SetCursor(* lpt->m_oldCursor); + +// lpt->m_xpos = x; lpt->m_ypos = y; + + if (lineShape->GetTo()) + { + lineShape->GetTo()->MoveLineToNewAttachment(dc, lineShape, x, y); + } + } + + // Needed? +#if 0 + int i = 0; + for (i = 0; i < lineShape->GetLineControlPoints()->Number(); i++) + if (((wxRealPoint *)(lineShape->GetLineControlPoints()->Nth(i)->Data())) == lpt->m_point) + break; + + // N.B. in OnMoveControlPoint, an event handler in Hardy could have deselected + // the line and therefore deleted 'this'. -> GPF, intermittently. + // So assume at this point that we've been blown away. + + lineShape->OnMoveControlPoint(i+1, x, y); +#endif +} + +// This is called only when a non-end control point is moved. +bool wxLineShape::OnMoveMiddleControlPoint(wxDC& dc, wxLineControlPoint* lpt, const wxRealPoint& pt) +{ + lpt->m_xpos = pt.x; lpt->m_ypos = pt.y; + lpt->m_point->x = pt.x; lpt->m_point->y = pt.y; + + GetEventHandler()->OnMoveLink(dc); + + return TRUE; +} + +// Implement movement of endpoint to a new attachment +// OBSOLETE: done by dragging with the left button. + +#if 0 +void wxLineControlPoint::OnDragRight(bool draw, double x, double y, int keys, int attachment) +{ + if (m_type == CONTROL_POINT_ENDPOINT_FROM || m_type == CONTROL_POINT_ENDPOINT_TO) + { + m_xpos = x; m_ypos = y; + } +} + +void wxLineControlPoint::OnBeginDragRight(double x, double y, int keys, int attachment) +{ + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + wxLineShape *lineShape = (wxLineShape *)m_shape; + if (m_type == CONTROL_POINT_ENDPOINT_FROM || m_type == CONTROL_POINT_ENDPOINT_TO) + { + Erase(dc); + lineShape->GetEventHandler()->OnDraw(dc); + if (m_type == CONTROL_POINT_ENDPOINT_FROM) + { + lineShape->GetFrom()->GetEventHandler()->OnDraw(dc); + lineShape->GetFrom()->GetEventHandler()->OnDrawContents(dc); + } + else + { + lineShape->GetTo()->GetEventHandler()->OnDraw(dc); + lineShape->GetTo()->GetEventHandler()->OnDrawContents(dc); + } + m_canvas->SetCursor(g_oglBullseyeCursor); + m_oldCursor = wxSTANDARD_CURSOR; + } +} + +void wxLineControlPoint::OnEndDragRight(double x, double y, int keys, int attachment) +{ + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + wxLineShape *lineShape = (wxLineShape *)m_shape; + if (m_type == CONTROL_POINT_ENDPOINT_FROM) + { + if (m_oldCursor) + m_canvas->SetCursor(m_oldCursor); + + m_xpos = x; m_ypos = y; + + if (lineShape->GetFrom()) + { + lineShape->GetFrom()->EraseLinks(dc); + + int new_attachment; + double distance; + + if (lineShape->GetFrom()->HitTest(x, y, &new_attachment, &distance)) + lineShape->SetAttachments(new_attachment, lineShape->GetAttachmentTo()); + + lineShape->GetFrom()->MoveLinks(dc); + } + } + if (m_type == CONTROL_POINT_ENDPOINT_TO) + { + if (m_oldCursor) + m_canvas->SetCursor(m_oldCursor); + m_shape->Erase(dc); + + m_xpos = x; m_ypos = y; + + if (lineShape->GetTo()) + { + lineShape->GetTo()->EraseLinks(dc); + + int new_attachment; + double distance; + if (lineShape->GetTo()->HitTest(x, y, &new_attachment, &distance)) + lineShape->SetAttachments(lineShape->GetAttachmentFrom(), new_attachment); + + lineShape->GetTo()->MoveLinks(dc); + } + } + int i = 0; + for (i = 0; i < lineShape->GetLineControlPoints()->Number(); i++) + if (((wxRealPoint *)(lineShape->GetLineControlPoints()->Nth(i)->Data())) == m_point) + break; + lineShape->OnMoveControlPoint(i+1, x, y); + if (!m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc); +} +#endif + +/* + * Get the point on the given line (x1, y1) (x2, y2) + * distance 'length' along from the end, + * returned values in x and y + */ + +void GetPointOnLine(double x1, double y1, double x2, double y2, + double length, double *x, double *y) +{ + double l = (double)sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)); + + if (l < 0.01) + l = (double) 0.01; + + double i_bar = (x2 - x1)/l; + double j_bar = (y2 - y1)/l; + + *x = (- length*i_bar) + x2; + *y = (- length*j_bar) + y2; +} + +wxArrowHead *wxLineShape::AddArrow(WXTYPE type, int end, double size, double xOffset, + const wxString& name, wxPseudoMetaFile *mf, long arrowId) +{ + wxArrowHead *arrow = new wxArrowHead(type, end, size, xOffset, name, mf, arrowId); + m_arcArrows.Append(arrow); + return arrow; +} + +/* + * Add arrowhead at a particular position in the arrowhead list. + */ +bool wxLineShape::AddArrowOrdered(wxArrowHead *arrow, wxList& referenceList, int end) +{ + wxNode *refNode = referenceList.First(); + wxNode *currNode = m_arcArrows.First(); + wxString targetName(arrow->GetName()); + if (!refNode) return FALSE; + + // First check whether we need to insert in front of list, + // because this arrowhead is the first in the reference + // list and should therefore be first in the current list. + wxArrowHead *refArrow = (wxArrowHead *)refNode->Data(); + if (refArrow->GetName() == targetName) + { + m_arcArrows.Insert(arrow); + return TRUE; + } + + while (refNode && currNode) + { + wxArrowHead *currArrow = (wxArrowHead *)currNode->Data(); + refArrow = (wxArrowHead *)refNode->Data(); + + // Matching: advance current arrow pointer + if ((currArrow->GetArrowEnd() == end) && + (currArrow->GetName() == refArrow->GetName())) + { + currNode = currNode->Next(); // Could be NULL now + if (currNode) + currArrow = (wxArrowHead *)currNode->Data(); + } + + // Check if we're at the correct position in the + // reference list + if (targetName == refArrow->GetName()) + { + if (currNode) + m_arcArrows.Insert(currNode, arrow); + else + m_arcArrows.Append(arrow); + return TRUE; + } + refNode = refNode->Next(); + } + m_arcArrows.Append(arrow); + return TRUE; +} + +void wxLineShape::ClearArrowsAtPosition(int end) +{ + wxNode *node = m_arcArrows.First(); + while (node) + { + wxArrowHead *arrow = (wxArrowHead *)node->Data(); + wxNode *next = node->Next(); + switch (end) + { + case -1: + { + delete arrow; + delete node; + break; + } + case ARROW_POSITION_START: + { + if (arrow->GetArrowEnd() == ARROW_POSITION_START) + { + delete arrow; + delete node; + } + break; + } + case ARROW_POSITION_END: + { + if (arrow->GetArrowEnd() == ARROW_POSITION_END) + { + delete arrow; + delete node; + } + break; + } + case ARROW_POSITION_MIDDLE: + { + if (arrow->GetArrowEnd() == ARROW_POSITION_MIDDLE) + { + delete arrow; + delete node; + } + break; + } + } + node = next; + } +} + +bool wxLineShape::ClearArrow(const wxString& name) +{ + wxNode *node = m_arcArrows.First(); + while (node) + { + wxArrowHead *arrow = (wxArrowHead *)node->Data(); + if (arrow->GetName() == name) + { + delete arrow; + delete node; + return TRUE; + } + node = node->Next(); + } + return FALSE; +} + +/* + * Finds an arrowhead at the given position (if -1, any position) + * + */ + +wxArrowHead *wxLineShape::FindArrowHead(int position, const wxString& name) +{ + wxNode *node = m_arcArrows.First(); + while (node) + { + wxArrowHead *arrow = (wxArrowHead *)node->Data(); + if (((position == -1) || (position == arrow->GetArrowEnd())) && + (arrow->GetName() == name)) + return arrow; + node = node->Next(); + } + return NULL; +} + +wxArrowHead *wxLineShape::FindArrowHead(long arrowId) +{ + wxNode *node = m_arcArrows.First(); + while (node) + { + wxArrowHead *arrow = (wxArrowHead *)node->Data(); + if (arrowId == arrow->GetId()) + return arrow; + node = node->Next(); + } + return NULL; +} + +/* + * Deletes an arrowhead at the given position (if -1, any position) + * + */ + +bool wxLineShape::DeleteArrowHead(int position, const wxString& name) +{ + wxNode *node = m_arcArrows.First(); + while (node) + { + wxArrowHead *arrow = (wxArrowHead *)node->Data(); + if (((position == -1) || (position == arrow->GetArrowEnd())) && + (arrow->GetName() == name)) + { + delete arrow; + delete node; + return TRUE; + } + node = node->Next(); + } + return FALSE; +} + +// Overloaded DeleteArrowHead: pass arrowhead id. +bool wxLineShape::DeleteArrowHead(long id) +{ + wxNode *node = m_arcArrows.First(); + while (node) + { + wxArrowHead *arrow = (wxArrowHead *)node->Data(); + if (arrow->GetId() == id) + { + delete arrow; + delete node; + return TRUE; + } + node = node->Next(); + } + return FALSE; +} + +/* + * Calculate the minimum width a line + * occupies, for the purposes of drawing lines in tools. + * + */ + +double wxLineShape::FindMinimumWidth() +{ + double minWidth = 0.0; + wxNode *node = m_arcArrows.First(); + while (node) + { + wxArrowHead *arrowHead = (wxArrowHead *)node->Data(); + minWidth += arrowHead->GetSize(); + if (node->Next()) + minWidth += arrowHead->GetSpacing(); + + node = node->Next(); + } + // We have ABSOLUTE minimum now. So + // scale it to give it reasonable aesthetics + // when drawing with line. + if (minWidth > 0.0) + minWidth = (double)(minWidth * 1.4); + else + minWidth = 20.0; + + SetEnds(0.0, 0.0, minWidth, 0.0); + Initialise(); + + return minWidth; +} + +// Find which position we're talking about at this (x, y). +// Returns ARROW_POSITION_START, ARROW_POSITION_MIDDLE, ARROW_POSITION_END +int wxLineShape::FindLinePosition(double x, double y) +{ + double startX, startY, endX, endY; + GetEnds(&startX, &startY, &endX, &endY); + + // Find distances from centre, start and end. The smallest wins. + double centreDistance = (double)(sqrt((x - m_xpos)*(x - m_xpos) + (y - m_ypos)*(y - m_ypos))); + double startDistance = (double)(sqrt((x - startX)*(x - startX) + (y - startY)*(y - startY))); + double endDistance = (double)(sqrt((x - endX)*(x - endX) + (y - endY)*(y - endY))); + + if (centreDistance < startDistance && centreDistance < endDistance) + return ARROW_POSITION_MIDDLE; + else if (startDistance < endDistance) + return ARROW_POSITION_START; + else + return ARROW_POSITION_END; +} + +// Set alignment flags +void wxLineShape::SetAlignmentOrientation(bool isEnd, bool isHoriz) +{ + if (isEnd) + { + if (isHoriz && ((m_alignmentEnd & LINE_ALIGNMENT_HORIZ) != LINE_ALIGNMENT_HORIZ)) + m_alignmentEnd |= LINE_ALIGNMENT_HORIZ; + else if (!isHoriz && ((m_alignmentEnd & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ)) + m_alignmentEnd -= LINE_ALIGNMENT_HORIZ; + } + else + { + if (isHoriz && ((m_alignmentStart & LINE_ALIGNMENT_HORIZ) != LINE_ALIGNMENT_HORIZ)) + m_alignmentStart |= LINE_ALIGNMENT_HORIZ; + else if (!isHoriz && ((m_alignmentStart & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ)) + m_alignmentStart -= LINE_ALIGNMENT_HORIZ; + } +} + +void wxLineShape::SetAlignmentType(bool isEnd, int alignType) +{ + if (isEnd) + { + if (alignType == LINE_ALIGNMENT_TO_NEXT_HANDLE) + { + if ((m_alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE) != LINE_ALIGNMENT_TO_NEXT_HANDLE) + m_alignmentEnd |= LINE_ALIGNMENT_TO_NEXT_HANDLE; + } + else if ((m_alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE) == LINE_ALIGNMENT_TO_NEXT_HANDLE) + m_alignmentEnd -= LINE_ALIGNMENT_TO_NEXT_HANDLE; + } + else + { + if (alignType == LINE_ALIGNMENT_TO_NEXT_HANDLE) + { + if ((m_alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE) != LINE_ALIGNMENT_TO_NEXT_HANDLE) + m_alignmentStart |= LINE_ALIGNMENT_TO_NEXT_HANDLE; + } + else if ((m_alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE) == LINE_ALIGNMENT_TO_NEXT_HANDLE) + m_alignmentStart -= LINE_ALIGNMENT_TO_NEXT_HANDLE; + } +} + +bool wxLineShape::GetAlignmentOrientation(bool isEnd) +{ + if (isEnd) + return ((m_alignmentEnd & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ); + else + return ((m_alignmentStart & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ); +} + +int wxLineShape::GetAlignmentType(bool isEnd) +{ + if (isEnd) + return (m_alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE); + else + return (m_alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE); +} + +wxRealPoint *wxLineShape::GetNextControlPoint(wxShape *nodeObject) +{ + int n = m_lineControlPoints->Number(); + int nn = 0; + if (m_to == nodeObject) + { + // Must be END of line, so we want (n - 1)th control point. + // But indexing ends at n-1, so subtract 2. + nn = n - 2; + } + else nn = 1; + wxNode *node = m_lineControlPoints->Nth(nn); + if (node) + { + return (wxRealPoint *)node->Data(); + } + else + return FALSE; +} + +/* + * Arrowhead + * + */ + +IMPLEMENT_DYNAMIC_CLASS(wxArrowHead, wxObject) + +wxArrowHead::wxArrowHead(WXTYPE type, int end, double size, double dist, const wxString& name, + wxPseudoMetaFile *mf, long arrowId) +{ + m_arrowType = type; m_arrowEnd = end; m_arrowSize = size; + m_xOffset = dist; + m_yOffset = 0.0; + m_spacing = 5.0; + + m_arrowName = name; + m_metaFile = mf; + m_id = arrowId; + if (m_id == -1) + m_id = wxNewId(); +} + +wxArrowHead::wxArrowHead(wxArrowHead& toCopy) +{ + m_arrowType = toCopy.m_arrowType; m_arrowEnd = toCopy.GetArrowEnd(); + m_arrowSize = toCopy.m_arrowSize; + m_xOffset = toCopy.m_xOffset; + m_yOffset = toCopy.m_yOffset; + m_spacing = toCopy.m_spacing; + m_arrowName = toCopy.m_arrowName ; + if (toCopy.m_metaFile) + m_metaFile = new wxPseudoMetaFile(*(toCopy.m_metaFile)); + else + m_metaFile = NULL; + m_id = wxNewId(); +} + +wxArrowHead::~wxArrowHead() +{ + if (m_metaFile) delete m_metaFile; +} + +void wxArrowHead::SetSize(double size) +{ + m_arrowSize = size; + if ((m_arrowType == ARROW_METAFILE) && m_metaFile) + { + double oldWidth = m_metaFile->m_width; + if (oldWidth == 0.0) + return; + + double scale = (double)(size/oldWidth); + if (scale != 1.0) + m_metaFile->Scale(scale, scale); + } +} + +// Can override this to create a different class of label shape +wxLabelShape* wxLineShape::OnCreateLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h) +{ + return new wxLabelShape(parent, region, w, h); +} + +/* + * Label object + * + */ + +IMPLEMENT_DYNAMIC_CLASS(wxLabelShape, wxRectangleShape) + +wxLabelShape::wxLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h):wxRectangleShape(w, h) +{ + m_lineShape = parent; + m_shapeRegion = region; + SetPen(wxThePenList->FindOrCreatePen(wxColour(0, 0, 0), 1, wxDOT)); +} + +wxLabelShape::~wxLabelShape() +{ +} + +void wxLabelShape::OnDraw(wxDC& dc) +{ + if (m_lineShape && !m_lineShape->GetDrawHandles()) + return; + + double x1 = (double)(m_xpos - m_width/2.0); + double y1 = (double)(m_ypos - m_height/2.0); + + if (m_pen) + { + if (m_pen->GetWidth() == 0) + dc.SetPen(* g_oglTransparentPen); + else + dc.SetPen(* m_pen); + } + dc.SetBrush(* wxTRANSPARENT_BRUSH); + + if (m_cornerRadius > 0.0) + dc.DrawRoundedRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height), m_cornerRadius); + else + dc.DrawRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height)); +} + +void wxLabelShape::OnDrawContents(wxDC& dc) +{ +} + +void wxLabelShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment) +{ + wxRectangleShape::OnDragLeft(draw, x, y, keys, attachment); +} + +void wxLabelShape::OnBeginDragLeft(double x, double y, int keys, int attachment) +{ + wxRectangleShape::OnBeginDragLeft(x, y, keys, attachment); +} + +void wxLabelShape::OnEndDragLeft(double x, double y, int keys, int attachment) +{ + wxRectangleShape::OnEndDragLeft(x, y, keys, attachment); +} + +bool wxLabelShape::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display) +{ + return m_lineShape->OnLabelMovePre(dc, this, x, y, old_x, old_y, display); +} + +bool wxLineShape::OnLabelMovePre(wxDC& dc, wxLabelShape* labelShape, double x, double y, double old_x, double old_y, bool display) +{ + labelShape->m_shapeRegion->SetSize(labelShape->GetWidth(), labelShape->GetHeight()); + + // Find position in line's region list + int i = 0; + wxNode *node = GetRegions().First(); + while (node) + { + if (labelShape->m_shapeRegion == (wxShapeRegion *)node->Data()) + node = NULL; + else + { + node = node->Next(); + i ++; + } + } + double xx, yy; + GetLabelPosition(i, &xx, &yy); + // Set the region's offset, relative to the default position for + // each region. + labelShape->m_shapeRegion->SetPosition((double)(x - xx), (double)(y - yy)); + + labelShape->SetX(x); + labelShape->SetY(y); + + // Need to reformat to fit region. + if (labelShape->m_shapeRegion->GetText()) + { + + wxString s(labelShape->m_shapeRegion->GetText()); + labelShape->FormatText(dc, s, i); + DrawRegion(dc, labelShape->m_shapeRegion, xx, yy); + } + return TRUE; +} + +// Divert left and right clicks to line object +void wxLabelShape::OnLeftClick(double x, double y, int keys, int attachment) +{ + m_lineShape->GetEventHandler()->OnLeftClick(x, y, keys, attachment); +} + +void wxLabelShape::OnRightClick(double x, double y, int keys, int attachment) +{ + m_lineShape->GetEventHandler()->OnRightClick(x, y, keys, attachment); +} + diff --git a/src/ogl/makefile.b32 b/src/ogl/makefile.b32 new file mode 100644 index 0000000000..0b5356ac42 --- /dev/null +++ b/src/ogl/makefile.b32 @@ -0,0 +1,18 @@ +# +# File: makefile.b32 +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: +# +# Makefile : Builds OGL library for 32-bit BC++ + +WXDIR = $(WXWIN) + +LIBTARGET=$(WXDIR)\lib\ogl.lib + +OBJECTS = basic.obj basic2.obj canvas.obj ogldiag.obj lines.obj misc.obj divided.obj constrnt.obj\ + composit.obj drawn.obj bmpshape.obj mfutils.obj + +!include $(WXDIR)\src\makelib.b32 + diff --git a/src/ogl/makefile.bcc b/src/ogl/makefile.bcc new file mode 100644 index 0000000000..94177e6b17 --- /dev/null +++ b/src/ogl/makefile.bcc @@ -0,0 +1,21 @@ +# +# File: makefile.bcc +# Author: Julian Smart +# Created: 1998 +# Updated: +# +# Builds OGL library for BC++, 16-bit + +!if "$(WXWIN)" == "" +!error You must define the WXWIN variable in autoexec.bat, e.g. WXWIN=c:\wx +!endif + +WXDIR = $(WXWIN) + +LIBTARGET=$(WXDIR)\lib\ogl.lib + +OBJECTS = basic.obj basic2.obj canvas.obj ogldiag.obj lines.obj misc.obj divided.obj constrnt.obj\ + composit.obj drawn.obj bmpshape.obj mfutils.obj + +!include $(WXDIR)\src\makelib.bcc + diff --git a/src/ogl/makefile.dos b/src/ogl/makefile.dos new file mode 100644 index 0000000000..f5cfb71f30 --- /dev/null +++ b/src/ogl/makefile.dos @@ -0,0 +1,159 @@ +# +# File: makefile.dos +# Author: Julian Smart +# Created: 1993 +# Updated: +# Copyright: (c) 1993, AIAI, University of Edinburgh +# +# "%W% %G%" +# +# Makefile: Builds object graphics library (DOS). +# Use FINAL=1 argument to nmake to build final version with no debugging +# info + +# Set WXDIR for your system +WXDIR = $(WXWIN) + +!include $(WXDIR)\src\makemsc.env + +OGLDIR = $(WXDIR)\src\ogl +THISDIR = $(OGLDIR)\src +DOCDIR = $(WXDIR)\docs\latex\ogl + +GRAPHICSLIB = $(WXDIR)\lib\ogl.lib +INC = /I$(WXDIR)\include + +# Normally set OPTIONS = +# to disable PROLOGIO-dependent code +OPTIONS = -DPROLOGIO + +OBJECTS = basic.obj basic2.obj canvas.obj ogldiag.obj lines.obj misc.obj divided.obj constrnt.obj\ + composit.obj drawn.obj bitmap.obj mfutils.obj + +all: $(GRAPHICSLIB) + +wx: + cd $(WXDIR)\src\msw + nmake -f makefile.dos $(WXLIB) FINAL=$(FINAL) + cd $(THISDIR) + +$(GRAPHICSLIB): $(OBJECTS) + erase $(GRAPHICSLIB) + lib /PAGESIZE:128 @<< +$(GRAPHICSLIB) +y +$(OBJECTS) +nul +; +<< + +# NOTE: This causes a floating point stack error when optimized, +# so DON'T optimize! + +basic.obj: basic.$(SRCSUFF) basic.h lines.h misc.h canvas.h + cl @<< +$(CPPFLAGS) /Od /c /Tp $*.$(SRCSUFF) +<< + +basic2.obj: basic2.$(SRCSUFF) basic.h lines.h misc.h canvas.h + cl @<< +$(CPPFLAGS) /Od /c /Tp $*.$(SRCSUFF) +<< + +canvas.obj: canvas.$(SRCSUFF) basic.h misc.h canvas.h + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +ogldiag.obj: ogldiag.$(SRCSUFF) ogldiag.h canvas.h basic.h + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +lines.obj: lines.$(SRCSUFF) basic.h misc.h canvas.h lines.h basicp.h linesp.h + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +misc.obj: misc.$(SRCSUFF) basic.h misc.h constrnt.h basicp.h + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +divided.obj: divided.$(SRCSUFF) basic.h misc.h canvas.h divided.h basicp.h + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +constrnt.obj: constrnt.$(SRCSUFF) basic.h constrnt.h + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +composit.obj: composit.$(SRCSUFF) basic.h misc.h canvas.h constrnt.h composit.h basicp.h + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +drawn.obj: drawn.$(SRCSUFF) basic.h misc.h canvas.h drawn.h drawnp.h basicp.h + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +bitmap.obj: bitmap.$(SRCSUFF) basic.h misc.h canvas.h bitmap.h + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +mfutils.obj: mfutils.$(SRCSUFF) mfutils.h + cl @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) +<< + +# Making documents +docs: hlp +hlp: $(DOCDIR)/ogl.hlp +hlp32: $(DOCDIR)/hlp32/ogl.hlp +rtf: $(DOCDIR)/ogl.rtf + +$(DOCDIR)/ogl.hlp: $(DOCDIR)/ogl.rtf $(DOCDIR)/ogl.hpj + cd $(DOCDIR) + -erase ogl.ph + hc ogl + cd $(THISDIR) + +$(DOCDIR)/hlp32/ogl.hlp: $(DOCDIR)/hlp32/ogl.rtf $(DOCDIR)/hlp32/ogl.hpj + cd $(DOCDIR)/hlp32 + -erase ogl.ph + start /w hcw /c /e ogl.hpj + cd $(THISDIR) + +$(DOCDIR)/ogl.rtf: $(DOCDIR)/classes.tex $(DOCDIR)/intro.tex $(DOCDIR)/ogl.tex + cd $(DOCDIR) + start /w tex2rtf $(DOCDIR)/ogl.tex $(DOCDIR)/ogl.rtf -twice -winhelp + cd $(THISDIR) + +$(DOCDIR)/hlp32/ogl.rtf: $(DOCDIR)/classes.tex $(DOCDIR)/intro.tex $(DOCDIR)/ogl.tex + cd $(DOCDIR) + start /w tex2rtf $(DOCDIR)/ogl.tex $(DOCDIR)/hlp32/ogl.rtf -twice -winhelp -macros $(DOCDIR)/t2rtf32.ini + cd $(THISDIR) + +wordrtf: + cd $(DOCDIR) + -wx /W tex2rtf $(DOCDIR)/ogl.tex $(DOCDIR)/ogl.rtf -twice -rtf + cd $(THISDIR) + +clean: + -erase *.obj + -erase *.sbr + -erase *.exe + -erase *.res + -erase *.map + -erase *.pdb + -erase *.lib + -erase ..\lib\*.lib + +wxclean: + cd $(WXDIR)\src\msw + nmake -f makefile.dos clean + cd $(THISDIR) diff --git a/src/ogl/makefile.g95 b/src/ogl/makefile.g95 new file mode 100644 index 0000000000..addf4414d7 --- /dev/null +++ b/src/ogl/makefile.g95 @@ -0,0 +1,17 @@ +# +# File: makefile.g95 +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: (c) Julian Smart, 1999 +# +# Makefile for wxWindows OGL library Cygwin/Mingw32). + +WXDIR = ../.. + +LIBTARGET=$(WXDIR)/lib/libogl.a +OBJECTS = basic.o basic2.o canvas.o ogldiag.o lines.o misc.o divided.o constrnt.o\ + composit.o drawn.o bmpshape.o mfutils.o + +include $(WXDIR)/src/makelib.g95 + diff --git a/src/ogl/makefile.unx b/src/ogl/makefile.unx new file mode 100644 index 0000000000..5141fb6766 --- /dev/null +++ b/src/ogl/makefile.unx @@ -0,0 +1,42 @@ +# +# File: makefile.unx +# Author: Julian Smart +# Created: 1998 +# Updated: +# Copyright: (c) 1998 +# +# +# Makefile for OGL library, Unix + +include ../../src/make.env + +OGLLIB=$(WXDIR)/lib/libogl$(GUISUFFIX).a + +LIB_CPP_SRC=\ +\ + basic.o\ + basic2.o\ + canvas.o\ + ogldiag.o\ + lines.o\ + misc.o\ + divided.o\ + constrnt.o\ + composit.o\ + drawn.o\ + bmpshape.o\ + mfutils.o + +all: $(OGLLIB) + +# Define library objects +OBJECTS=\ + $(LIB_CPP_SRC:.cpp=.o) + +$(OGLLIB) : $(OBJECTS) + ar $(AROPTIONS) $@ $(OBJECTS) + $(RANLIB) $@ + +clean: + rm -f $(OBJECTS) $(OGLLIB) + diff --git a/src/ogl/makefile.vc b/src/ogl/makefile.vc new file mode 100644 index 0000000000..e57f365749 --- /dev/null +++ b/src/ogl/makefile.vc @@ -0,0 +1,195 @@ + +# File: makefile.vc +# Author: Julian Smart +# Created: 1993 +# Updated: +# Copyright: (c) 1993, AIAI, University of Edinburgh +# +# "%W% %G%" +# +# Makefile : Builds OGL classes library (MS VC++). +# Use FINAL=1 argument to nmake to build final version with no debugging +# info + + +# Set WXDIR for your system +WXDIR = $(WXWIN) +OGLDIR = $(WXDIR)\src\ogl +THISDIR = $(WXDIR)\src\ogl +EXTRAFLAGS=/DPROLOGIO=1 +DOCDIR=$(WXDIR)\docs +LOCALDOCDIR=$(WXDIR)\docs\latex\ogl + +!include $(WXDIR)\src\makevc.env + +PROGRAM=test + +OBJECTS = $(D)\basic.obj $(D)\basic2.obj $(D)\canvas.obj $(D)\ogldiag.obj $(D)\lines.obj $(D)\misc.obj $(D)\divided.obj $(D)\constrnt.obj\ + $(D)\composit.obj $(D)\drawn.obj $(D)\bmpshape.obj $(D)\mfutils.obj + +LIBTARGET=$(WXDIR)\lib\ogl$(LIBEXT).lib + +all: $(D) $(LIBTARGET) + +$(PROGRAM): $(PROGRAM).exe + +$(D) : + mkdir $(D) + +wx: + cd $(WXDIR)\src\msw + nmake -f makefile.vc FINAL=$(FINAL) + cd $(THISDIR) + +wxclean: + cd $(WXDIR)\src\msw + nmake -f makefile.vc clean + cd $(THISDIR) + +$(LIBTARGET): $(OBJECTS) + -erase $(LIBTARGET) + $(implib) @<< +-out:$(LIBTARGET) +-machine:$(CPU) +$(OBJECTS) +<< + +# NOTE: This causes a floating point stack error when optimized, +# so DON'T optimize! +$(D)\basic.obj: basic.$(SRCSUFF) basic.h lines.h misc.h canvas.h + cl @<< +$(CPPFLAGS) /Od /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + +$(D)\basic2.obj: basic2.$(SRCSUFF) basic.h lines.h misc.h canvas.h + cl @<< +$(CPPFLAGS) /Od /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + +$(D)\canvas.obj: canvas.$(SRCSUFF) basic.h misc.h canvas.h + cl @<< +$(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + +$(D)\ogldiag.obj: ogldiag.$(SRCSUFF) ogldiag.h canvas.h basic.h + cl @<< +$(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + +$(D)\lines.obj: lines.$(SRCSUFF) basic.h misc.h canvas.h lines.h basicp.h linesp.h + cl @<< +$(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + +$(D)\misc.obj: misc.$(SRCSUFF) basic.h misc.h constrnt.h basicp.h + cl @<< +$(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + +$(D)\divided.obj: divided.$(SRCSUFF) basic.h misc.h canvas.h divided.h basicp.h + cl @<< +$(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + +$(D)\constrnt.obj: constrnt.$(SRCSUFF) basic.h constrnt.h + cl @<< +$(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + +$(D)\composit.obj: composit.$(SRCSUFF) basic.h misc.h canvas.h constrnt.h composit.h basicp.h + cl @<< +$(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + +$(D)\drawn.obj: drawn.$(SRCSUFF) basic.h misc.h canvas.h drawn.h drawnp.h basicp.h + cl @<< +$(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + +$(D)\bmpshape.obj: bmpshape.$(SRCSUFF) basic.h misc.h canvas.h bmpshape.h + cl @<< +$(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + +$(D)\mfutils.obj: mfutils.$(SRCSUFF) mfutils.h + cl @<< +$(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF) +<< + +clean: + -erase $(D)\*.obj + -erase *.sbr + -erase *.exe + -erase *.res + -erase *.map + -erase *.pdb + -erase $(LIBTARGET) + +DOCSOURCES=$(LOCALDOCDIR)\ogl.tex \ + $(LOCALDOCDIR)\bugs.tex $(LOCALDOCDIR)\changes.tex\ + $(LOCALDOCDIR)\classes.tex $(LOCALDOCDIR)\intro.tex\ + $(LOCALDOCDIR)\topics.tex $(LOCALDOCDIR)\sample.tex + +html: $(DOCDIR)\html\ogl\ogl.htm +htmlhelp: $(DOCDIR)\html\ogl\ogl.chm +hlp: $(DOCDIR)\winhelp\ogl.hlp +pdfrtf: $(DOCDIR)\pdf\ogl.rtf +ps: $(DOCDIR)\ps\ogl.ps + +touchmanual: + touch $(LOCALDOCDIR)\ogl.tex + + +$(DOCDIR)\winhelp\ogl.hlp: $(LOCALDOCDIR)\ogl.rtf $(LOCALDOCDIR)\ogl.hpj + cd $(LOCALDOCDIR) + -erase ogl.ph + hc ogl + move ogl.hlp $(DOCDIR)\winhelp\ogl.hlp + move ogl.cnt $(DOCDIR)\winhelp\ogl.cnt + cd $(THISDIR) + +$(LOCALDOCDIR)\ogl.rtf: $(DOCSOURCES) + cd $(LOCALDOCDIR) + -start $(WAITFLAG) tex2rtf $(LOCALDOCDIR)\ogl.tex $(LOCALDOCDIR)\ogl.rtf -twice -winhelp + cd $(THISDIR) + +$(DOCDIR)\pdf\ogl.rtf: $(DOCSOURCES) + cd $(LOCALDOCDIR) + -copy *.bmp $(DOCDIR)\pdf + -start $(WAITFLAG) tex2rtf $(LOCALDOCDIR)\ogl.tex $(DOCDIR)\pdf\ogl.rtf -twice -rtf + cd $(THISDIR) + +$(DOCDIR)\html\ogl\ogl.htm: $(DOCSOURCES) + cd $(LOCALDOCDIR) + -mkdir $(DOCDIR)\html\ogl + copy *.gif $(DOCDIR)\html\ogl + -start $(WAITFLAG) tex2rtf $(LOCALDOCDIR)\ogl.tex $(DOCDIR)\html\ogl\ogl.htm -twice -html + -erase $(DOCDIR)\html\ogl\*.con + -erase *.con + -erase $(DOCDIR)\html\ogl\*.ref + cd $(THISDIR) + + +$(DOCDIR)\html\ogl\ogl.chm: $(DOCDIR)\html\ogl\ogl.htm $(DOCDIR)\html\ogl\ogl.hhp + cd $(DOCDIR)\html\ogl + -hhc ogl.hhp + cd $(THISDIR) + + +$(LOCALDOCDIR)\ogl.dvi: $(DOCSOURCES) + cd $(LOCALDOCDIR) + -latex ogl + -latex ogl + -makeindx ogl + -bibtex ogl + -latex ogl + -latex ogl + cd $(THISDIR) + +$(WXDIR)\docs\ps\ogl.ps: $(LOCALDOCDIR)\ogl.dvi + cd $(LOCALDOCDIR) + -dvips32 -o ogl.ps ogl + move ogl.ps $(WXDIR)\docs\ps\ogl.ps + cd $(THISDIR) + + diff --git a/src/ogl/makefile.wat b/src/ogl/makefile.wat new file mode 100644 index 0000000000..a78d986ff4 --- /dev/null +++ b/src/ogl/makefile.wat @@ -0,0 +1,26 @@ +# Objects makefile + +WXDIR = ..\.. + +!include $(WXDIR)\src\makewat.env + +EXTRACPPFLAGS=/DPROLOGIO + +OGLLIB = $(WXDIR)\lib\ogl.lib +THISDIR = $(WXDIR)\src\ogl + +NAME = ogl +LNK = $(name).lnk + +IFLAGS = -i=$(WXINC) -i=$(WXBASEINC) + +OBJECTS = basic.obj basic2.obj canvas.obj lines.obj misc.obj divided.obj constrnt.obj composit.obj drawn.obj bitmap.obj + +all: $(OGLLIB) + +$(OGLLIB): $(OBJECTS) + *wlib /b /c /n /P=256 $(OGLLIB) $(OBJECTS) + +clean: .SYMBOLIC + -erase *.obj *.bak *.err *.pch $(OGLLIB) *.lbc + diff --git a/src/ogl/mfutils.cpp b/src/ogl/mfutils.cpp new file mode 100644 index 0000000000..b2684836a1 --- /dev/null +++ b/src/ogl/mfutils.cpp @@ -0,0 +1,1085 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mfutils.cpp +// Purpose: Metafile utillities +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "mfutils.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include +#include + +#include +#include + +static char hexArray[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F' }; + +static void DecToHex(int dec, char *buf) +{ + int firstDigit = (int)(dec/16.0); + int secondDigit = (int)(dec - (firstDigit*16.0)); + buf[0] = hexArray[firstDigit]; + buf[1] = hexArray[secondDigit]; + buf[2] = 0; +} + +// 16-bit unsigned integer +static unsigned int getshort(FILE *fp) +{ + int c, c1; + c = getc(fp); c1 = getc(fp); + unsigned int res = ((unsigned int) c) + (((unsigned int) c1) << 8); + return res; +} + +// 16-bit signed integer +static int getsignedshort(FILE *fp) +{ + int c, c1; + c = getc(fp); c1 = getc(fp); + int testRes = ((unsigned int) c) + (((unsigned int) c1) << 8); + unsigned long res1 = ((unsigned int) c) + (((unsigned int) c1) << 8); + int res = 0; + if (res1 > 32767) + res = (int)(res1 - 65536); + else + res = (int)(res1); + return res; +} + +// 32-bit integer +static long getint(FILE *fp) +{ + int c, c1, c2, c3; + c = getc(fp); c1 = getc(fp); c2 = getc(fp); c3 = getc(fp); + long res = (long)((long) c) + + (((long) c1) << 8) + + (((long) c2) << 16) + + (((long) c3) << 24); + return res; +} + + +/* Placeable metafile header +struct mfPLACEABLEHEADER { + DWORD key; // 32-bit + HANDLE hmf; // 16-bit + RECT bbox; // 4x16 bit + WORD inch; // 16-bit + DWORD reserved; // 32-bit + WORD checksum; // 16-bit +}; +*/ + +wxMetaRecord::~wxMetaRecord(void) +{ + if (points) delete[] points; + if (stringParam) delete[] stringParam; +} + +wxXMetaFile::wxXMetaFile(char *file) +{ + ok = FALSE; + top = 0.0; + bottom = 0.0; + left = 0.0; + right = 0.0; + + if (file) + ok = ReadFile(file); +} + +/* + Handle table gdiObjects + ------------ ---------- + [0] wxPen + [1]----param2--- wxBrush + [2] | wxFont + [3] | -> wxPen + + The handle table works as follows. + When a GDI object is created whilst reading in the + metafile, the (e.g.) createpen record is added to the + first free entry in the handle table. The createpen + record's param1 is a pointer to the actual wxPen, and + its param2 is the index into the gdiObjects list, which only + grows and never shrinks (unlike the handle table.) + + When SelectObject(index) is found, the index in the file + refers to the position in the handle table. BUT we then + set param2 to be the position of the wxPen in gdiObjects, + i.e. to param2 of the CreatePen record, itself found in + the handle table. + + When an object is deleted, the entry in the handletable is + NULLed but the gdiObjects entry is not removed (no point, and + allows us to create all GDI objects in advance of playing the + metafile). +*/ + + +static wxMetaRecord *HandleTable[100]; +static int HandleTableSize = 0; + +void DeleteMetaRecordHandle(int index) +{ + HandleTable[index] = NULL; +} + +int AddMetaRecordHandle(wxMetaRecord *record) +{ + for (int i = 0; i < HandleTableSize; i++) + if (!HandleTable[i]) + { + HandleTable[i] = record; + return i; + } + // No free spaces in table, so append. + + HandleTable[HandleTableSize] = record; + HandleTableSize ++; + return (HandleTableSize - 1); +} + +bool wxXMetaFile::ReadFile(char *file) +{ + HandleTableSize = 0; + + FILE *handle = fopen(file, "rb"); + if (!handle) return FALSE; + + // Read placeable metafile header, if any + long key = getint(handle); + + if (key == (long) 0x9AC6CDD7) + { + long hmf = getshort(handle); + int iLeft, iTop, iRight, iBottom; + iLeft = getsignedshort(handle); + iTop = getsignedshort(handle); + iRight = getsignedshort(handle); + iBottom = getsignedshort(handle); + + left = (double)iLeft; + top = (double)iTop; + right = (double)iRight; + bottom = (double)iBottom; + + int inch = getshort(handle); + long reserved = getint(handle); + int checksum = getshort(handle); +/* + double widthInUnits = (double)right - left; + double heightInUnits = (double)bottom - top; + *width = (int)((widthInUnits*1440.0)/inch); + *height = (int)((heightInUnits*1440.0)/inch); +*/ + } + else rewind(handle); + + // Read METAHEADER + int mtType = getshort(handle); + + if (mtType != 1 && mtType != 2) + { + fclose(handle); + return FALSE; + } + + int mtHeaderSize = getshort(handle); + int mtVersion = getshort(handle); + + if (mtVersion != 0x0300 && mtVersion != 0x0100) + { + fclose(handle); + return FALSE; + } + + long mtSize = getint(handle); + int mtNoObjects = getshort(handle); + long mtMaxRecord = getint(handle); + int mtNoParameters = getshort(handle); + + while (!feof(handle)) + { + long rdSize = getint(handle); // 4 bytes + int rdFunction = getshort(handle); // 2 bytes + if (feof(handle)) + break; + + switch (rdFunction) + { + case META_SETBKCOLOR: + { + wxMetaRecord *rec = new wxMetaRecord(META_SETBKCOLOR); + long colorref = getint(handle); // COLORREF + rec->param1 = GetRValue(colorref); + rec->param2 = GetGValue(colorref); + rec->param3 = GetBValue(colorref); + metaRecords.Append(rec); + break; + } + case META_SETBKMODE: + { + wxMetaRecord *rec = new wxMetaRecord(META_SETBKMODE); + rec->param1 = getshort(handle); // Background mode + if (rec->param1 == OPAQUE) rec->param1 = wxSOLID; + else rec->param1 = wxTRANSPARENT; + metaRecords.Append(rec); + break; + } + case META_SETMAPMODE: + { + wxMetaRecord *rec = new wxMetaRecord(META_SETMAPMODE); + rec->param1 = getshort(handle); + metaRecords.Append(rec); + break; + } +// case META_SETROP2: +// case META_SETRELABS: +// case META_SETPOLYFILLMODE: +// case META_SETSTRETCHBLTMODE: +// case META_SETTEXTCHAREXTRA: + case META_SETTEXTCOLOR: + { + wxMetaRecord *rec = new wxMetaRecord(META_SETTEXTCOLOR); + long colorref = getint(handle); // COLORREF + rec->param1 = GetRValue(colorref); + rec->param2 = GetGValue(colorref); + rec->param3 = GetBValue(colorref); + metaRecords.Append(rec); + break; + } +// case META_SETTEXTJUSTIFICATION: + case META_SETWINDOWORG: + { + wxMetaRecord *rec = new wxMetaRecord(META_SETWINDOWORG); + rec->param2 = getshort(handle); + rec->param1 = getshort(handle); + metaRecords.Append(rec); + break; + } + case META_SETWINDOWEXT: + { + wxMetaRecord *rec = new wxMetaRecord(META_SETWINDOWEXT); + rec->param2 = getshort(handle); + rec->param1 = getshort(handle); + metaRecords.Append(rec); + break; + } +// case META_SETVIEWPORTORG: +// case META_SETVIEWPORTEXT: +// case META_OFFSETWINDOWORG: +// case META_SCALEWINDOWEXT: +// case META_OFFSETVIEWPORTORG: +// case META_SCALEVIEWPORTEXT: + case META_LINETO: + { + wxMetaRecord *rec = new wxMetaRecord(META_LINETO); + rec->param1 = getshort(handle); // x1 + rec->param2 = getshort(handle); // y1 + metaRecords.Append(rec); + break; + } + case META_MOVETO: + { + wxMetaRecord *rec = new wxMetaRecord(META_MOVETO); + rec->param1 = getshort(handle); // x1 + rec->param2 = getshort(handle); // y1 + metaRecords.Append(rec); + break; + } + case META_EXCLUDECLIPRECT: + { + wxMetaRecord *rec = new wxMetaRecord(META_EXCLUDECLIPRECT); + rec->param4 = getshort(handle); // y2 + rec->param3 = getshort(handle); // x2 + rec->param2 = getshort(handle); // y1 + rec->param1 = getshort(handle); // x1 + metaRecords.Append(rec); + break; + } + case META_INTERSECTCLIPRECT: + { + wxMetaRecord *rec = new wxMetaRecord(META_INTERSECTCLIPRECT); + rec->param4 = getshort(handle); // y2 + rec->param3 = getshort(handle); // x2 + rec->param2 = getshort(handle); // y1 + rec->param1 = getshort(handle); // x1 + metaRecords.Append(rec); + break; + } +// case META_ARC: // DO!!! + case META_ELLIPSE: + { + wxMetaRecord *rec = new wxMetaRecord(META_ELLIPSE); + rec->param4 = getshort(handle); // y2 + rec->param3 = getshort(handle); // x2 + rec->param2 = getshort(handle); // y1 + rec->param1 = getshort(handle); // x1 + metaRecords.Append(rec); + break; + } +// case META_FLOODFILL: +// case META_PIE: // DO!!! + case META_RECTANGLE: + { + wxMetaRecord *rec = new wxMetaRecord(META_RECTANGLE); + rec->param4 = getshort(handle); // y2 + rec->param3 = getshort(handle); // x2 + rec->param2 = getshort(handle); // y1 + rec->param1 = getshort(handle); // x1 + metaRecords.Append(rec); + break; + } + case META_ROUNDRECT: + { + wxMetaRecord *rec = new wxMetaRecord(META_ROUNDRECT); + rec->param6 = getshort(handle); // width + rec->param5 = getshort(handle); // height + rec->param4 = getshort(handle); // y2 + rec->param3 = getshort(handle); // x2 + rec->param2 = getshort(handle); // y1 + rec->param1 = getshort(handle); // x1 + metaRecords.Append(rec); + break; + } +// case META_PATBLT: +// case META_SAVEDC: + case META_SETPIXEL: + { + wxMetaRecord *rec = new wxMetaRecord(META_SETPIXEL); + rec->param1 = getshort(handle); // x1 + rec->param2 = getshort(handle); // y1 + rec->param3 = getint(handle); // COLORREF + metaRecords.Append(rec); + break; + } +// case META_OFFSETCLIPRGN: + case META_TEXTOUT: + { + wxMetaRecord *rec = new wxMetaRecord(META_TEXTOUT); + int count = getshort(handle); + rec->stringParam = new char[count+1]; + fread((void *)rec->stringParam, sizeof(char), count, handle); + rec->stringParam[count] = 0; + rec->param2 = getshort(handle); // Y + rec->param1 = getshort(handle); // X + metaRecords.Append(rec); + break; + } +/* + case META_EXTTEXTOUT: + { + wxMetaRecord *rec = new wxMetaRecord(META_EXTTEXTOUT); + int cellSpacing = getshort(handle); + int count = getshort(handle); + rec->stringParam = new char[count+1]; + fread((void *)rec->stringParam, sizeof(char), count, handle); + rec->stringParam[count] = 0; + // Rectangle + int rectY2 = getshort(handle); + int rectX2 = getshort(handle); + int rectY1 = getshort(handle); + int rectX1 = getshort(handle); + int rectType = getshort(handle); + rec->param2 = getshort(handle); // Y + rec->param1 = getshort(handle); // X + metaRecords.Append(rec); + break; + } +*/ +// case META_BITBLT: +// case META_STRETCHBLT: + case META_POLYGON: + { + wxMetaRecord *rec = new wxMetaRecord(META_POLYGON); + rec->param1 = getshort(handle); + rec->points = new wxRealPoint[(int)rec->param1]; + for (int i = 0; i < rec->param1; i++) + { + rec->points[i].x = getshort(handle); + rec->points[i].y = getshort(handle); + } + + metaRecords.Append(rec); + break; + } + case META_POLYLINE: + { + wxMetaRecord *rec = new wxMetaRecord(META_POLYLINE); + rec->param1 = (long)getshort(handle); + rec->points = new wxRealPoint[(int)rec->param1]; + for (int i = 0; i < rec->param1; i++) + { + rec->points[i].x = getshort(handle); + rec->points[i].y = getshort(handle); + } + + metaRecords.Append(rec); + break; + } +// case META_ESCAPE: +// case META_RESTOREDC: +// case META_FILLREGION: +// case META_FRAMEREGION: +// case META_INVERTREGION: +// case META_PAINTREGION: +// case META_SELECTCLIPREGION: // DO THIS! + case META_SELECTOBJECT: + { + wxMetaRecord *rec = new wxMetaRecord(META_SELECTOBJECT); + rec->param1 = (long)getshort(handle); // Position of object in gdiObjects list + metaRecords.Append(rec); + // param2 gives the index into gdiObjects, which is different from + // the index into the handle table. + rec->param2 = HandleTable[(int)rec->param1]->param2; + break; + } +// case META_SETTEXTALIGN: +// case META_DRAWTEXT: +// case META_CHORD: +// case META_SETMAPPERFLAGS: +// case META_EXTTEXTOUT: +// case META_SETDIBTODEV: +// case META_SELECTPALETTE: +// case META_REALIZEPALETTE: +// case META_ANIMATEPALETTE: +// case META_SETPALENTRIES: +// case META_POLYPOLYGON: +// case META_RESIZEPALETTE: +// case META_DIBBITBLT: +// case META_DIBSTRETCHBLT: + case META_DIBCREATEPATTERNBRUSH: + { + wxMetaRecord *rec = new wxMetaRecord(META_DIBCREATEPATTERNBRUSH); + fread((void *)wxBuffer, sizeof(char), (int)((2*rdSize) - 6), handle); + + metaRecords.Append(rec); + gdiObjects.Append(rec); + AddMetaRecordHandle(rec); + rec->param2 = (long)(gdiObjects.Number() - 1); + break; + } +// case META_STRETCHDIB: +// case META_EXTFLOODFILL: +// case META_RESETDC: +// case META_STARTDOC: +// case META_STARTPAGE: +// case META_ENDPAGE: +// case META_ABORTDOC: +// case META_ENDDOC: + case META_DELETEOBJECT: + { + int index = getshort(handle); + DeleteMetaRecordHandle(index); + break; + } + case META_CREATEPALETTE: + { + wxMetaRecord *rec = new wxMetaRecord(META_CREATEPALETTE); + fread((void *)wxBuffer, sizeof(char), (int)((2*rdSize) - 6), handle); + + metaRecords.Append(rec); + gdiObjects.Append(rec); + AddMetaRecordHandle(rec); + rec->param2 = (long)(gdiObjects.Number() - 1); + break; + } + case META_CREATEBRUSH: + { + wxMetaRecord *rec = new wxMetaRecord(META_CREATEBRUSH); + fread((void *)wxBuffer, sizeof(char), (int)((2*rdSize) - 6), handle); + metaRecords.Append(rec); + gdiObjects.Append(rec); + AddMetaRecordHandle(rec); + rec->param2 = (long)(gdiObjects.Number() - 1); + break; + } + case META_CREATEPATTERNBRUSH: + { + wxMetaRecord *rec = new wxMetaRecord(META_CREATEPATTERNBRUSH); + fread((void *)wxBuffer, sizeof(char), (int)((2*rdSize) - 6), handle); + metaRecords.Append(rec); + gdiObjects.Append(rec); + AddMetaRecordHandle(rec); + rec->param2 = (long)(gdiObjects.Number() - 1); + break; + } + case META_CREATEPENINDIRECT: + { + wxMetaRecord *rec = new wxMetaRecord(META_CREATEPENINDIRECT); + int msStyle = getshort(handle); // Style: 2 bytes + int x = getshort(handle); // X: 2 bytes + int y = getshort(handle); // Y: 2 bytes + long colorref = getint(handle); // COLORREF 4 bytes + + int style; + if (msStyle == PS_DOT) + style = wxDOT; + else if (msStyle == PS_DASH) + style = wxSHORT_DASH; + else if (msStyle == PS_NULL) + style = wxTRANSPARENT; + else style = wxSOLID; + + wxColour colour(GetRValue(colorref), GetGValue(colorref), GetBValue(colorref)); + rec->param1 = (long)wxThePenList->FindOrCreatePen(colour, x, style); + metaRecords.Append(rec); + gdiObjects.Append(rec); + + AddMetaRecordHandle(rec); + rec->param2 = (long)(gdiObjects.Number() - 1); + + // For some reason, the size of this record is sometimes 9 words!!! + // instead of the usual 8. So read 2 characters extra. + if (rdSize == 9) + { + (void) getshort(handle); + } + break; + } + case META_CREATEFONTINDIRECT: + { + wxMetaRecord *rec = new wxMetaRecord(META_CREATEFONTINDIRECT); + int lfHeight = getshort(handle); // 2 bytes + int lfWidth = getshort(handle); // 2 bytes + int lfEsc = getshort(handle); // 2 bytes + int lfOrient = getshort(handle); // 2 bytes + int lfWeight = getshort(handle); // 2 bytes + char lfItalic = getc(handle); // 1 byte + char lfUnderline = getc(handle); // 1 byte + char lfStrikeout = getc(handle); // 1 byte + char lfCharSet = getc(handle); // 1 byte + char lfOutPrecision = getc(handle); // 1 byte + char lfClipPrecision = getc(handle); // 1 byte + char lfQuality = getc(handle); // 1 byte + char lfPitchAndFamily = getc(handle); // 1 byte (18th) + char lfFacename[32]; + // Read the rest of the record, which is total record size + // minus the number of bytes already read (18 record, 6 metarecord + // header) + fread((void *)lfFacename, sizeof(char), (int)((2*rdSize) - 18 - 6), handle); + + int family; + if (lfPitchAndFamily & FF_MODERN) + family = wxMODERN; + else if (lfPitchAndFamily & FF_MODERN) + family = wxMODERN; + else if (lfPitchAndFamily & FF_ROMAN) + family = wxROMAN; + else if (lfPitchAndFamily & FF_SWISS) + family = wxSWISS; + else if (lfPitchAndFamily & FF_DECORATIVE) + family = wxDECORATIVE; + else + family = wxDEFAULT; + + int weight; + if (lfWeight == 300) + weight = wxLIGHT; + else if (lfWeight == 400) + weight = wxNORMAL; + else if (lfWeight == 900) + weight = wxBOLD; + else weight = wxNORMAL; + + int style; + if (lfItalic != 0) + style = wxITALIC; + else + style = wxNORMAL; + + // About how many pixels per inch??? + int logPixelsY = 100; + int pointSize = (int)(lfHeight*72.0/logPixelsY); + + wxFont *theFont = + wxTheFontList->FindOrCreateFont(pointSize, family, style, weight, (lfUnderline != 0)); + + rec->param1 = (long) theFont; + metaRecords.Append(rec); + gdiObjects.Append(rec); + AddMetaRecordHandle(rec); + rec->param2 = (long)(gdiObjects.Number() - 1); + break; + } + case META_CREATEBRUSHINDIRECT: + { + wxMetaRecord *rec = new wxMetaRecord(META_CREATEBRUSHINDIRECT); + int msStyle = getshort(handle); // Style: 2 bytes + long colorref = getint(handle); // COLORREF: 4 bytes + int hatchStyle = getshort(handle); // Hatch style 2 bytes + + int style; + switch (msStyle) + { + case BS_HATCHED: + { + switch (hatchStyle) + { + case HS_BDIAGONAL: + style = wxBDIAGONAL_HATCH; + break; + case HS_DIAGCROSS: + style = wxCROSSDIAG_HATCH; + break; + case HS_FDIAGONAL: + style = wxFDIAGONAL_HATCH; + break; + case HS_HORIZONTAL: + style = wxHORIZONTAL_HATCH; + break; + case HS_VERTICAL: + style = wxVERTICAL_HATCH; + break; + default: + case HS_CROSS: + style = wxCROSS_HATCH; + break; + } + break; + } + case BS_SOLID: + default: + style = wxSOLID; + break; + } + if (msStyle == PS_DOT) + style = wxDOT; + else if (msStyle == PS_DASH) + style = wxSHORT_DASH; + else if (msStyle == PS_NULL) + style = wxTRANSPARENT; + else style = wxSOLID; + + wxColour colour(GetRValue(colorref), GetGValue(colorref), GetBValue(colorref)); + rec->param1 = (long)wxTheBrushList->FindOrCreateBrush(colour, style); + metaRecords.Append(rec); + gdiObjects.Append(rec); + AddMetaRecordHandle(rec); + rec->param2 = (long)(gdiObjects.Number() - 1); + break; + } + case META_CREATEBITMAPINDIRECT: + { + wxMetaRecord *rec = new wxMetaRecord(META_CREATEBITMAPINDIRECT); + fread((void *)wxBuffer, sizeof(char), (int)((2*rdSize) - 6), handle); + + metaRecords.Append(rec); + gdiObjects.Append(rec); + AddMetaRecordHandle(rec); + rec->param2 = (long)(gdiObjects.Number() - 1); + break; + } + case META_CREATEBITMAP: + { + wxMetaRecord *rec = new wxMetaRecord(META_CREATEBITMAP); + fread((void *)wxBuffer, sizeof(char), (int)((2*rdSize) - 6), handle); + + metaRecords.Append(rec); + gdiObjects.Append(rec); + AddMetaRecordHandle(rec); + rec->param2 = (long)(gdiObjects.Number() - 1); + break; + } + case META_CREATEREGION: + { + wxMetaRecord *rec = new wxMetaRecord(META_CREATEREGION); + fread((void *)wxBuffer, sizeof(char), (int)((2*rdSize) - 6), handle); + + metaRecords.Append(rec); + gdiObjects.Append(rec); + AddMetaRecordHandle(rec); + rec->param2 = (long)(gdiObjects.Number() - 1); + break; + } + default: + { + fread((void *)wxBuffer, sizeof(char), (int)((2*rdSize) - 6), handle); + break; + } + } + } + fclose(handle); + return TRUE; +} + +wxXMetaFile::~wxXMetaFile(void) +{ + wxNode *node = metaRecords.First(); + while (node) + { + wxMetaRecord *rec = (wxMetaRecord *)node->Data(); + delete rec; + wxNode *next = node->Next(); + delete node; + node = next; + } +} + +bool wxXMetaFile::SetClipboard(int width, int height) +{ + return FALSE; +} + +bool wxXMetaFile::Play(wxDC *dc) +{ + wxNode *node = metaRecords.First(); + while (node) + { + wxMetaRecord *rec = (wxMetaRecord *)node->Data(); + int rdFunction = rec->metaFunction; + + switch (rdFunction) + { + case META_SETBKCOLOR: + { + break; + } + case META_SETBKMODE: + { + break; + } + case META_SETMAPMODE: + { + break; + } +// case META_SETROP2: +// case META_SETRELABS: +// case META_SETPOLYFILLMODE: +// case META_SETSTRETCHBLTMODE: +// case META_SETTEXTCHAREXTRA: + case META_SETTEXTCOLOR: + { + break; + } +// case META_SETTEXTJUSTIFICATION: + case META_SETWINDOWORG: + { + break; + } + case META_SETWINDOWEXT: + { + break; + } +// case META_SETVIEWPORTORG: +// case META_SETVIEWPORTEXT: +// case META_OFFSETWINDOWORG: +// case META_SCALEWINDOWEXT: +// case META_OFFSETVIEWPORTORG: +// case META_SCALEVIEWPORTEXT: + case META_LINETO: + { + long x1 = rec->param1; + long y1 = rec->param2; + dc->DrawLine((long) lastX, (long) lastY, x1, y1); + break; + } + case META_MOVETO: + { + lastX = (double)rec->param1; + lastY = (double)rec->param2; + break; + } + case META_EXCLUDECLIPRECT: + { + break; + } + case META_INTERSECTCLIPRECT: + { + break; + } +// case META_ARC: // DO!!! + case META_ELLIPSE: + { + break; + } +// case META_FLOODFILL: +// case META_PIE: // DO!!! + case META_RECTANGLE: + { + dc->DrawRectangle((long)rec->param1, (long)rec->param2, + (long)rec->param3 - rec->param1, + (long)rec->param4 - rec->param2); + break; + } + case META_ROUNDRECT: + { + dc->DrawRoundedRectangle((long)rec->param1, (long)rec->param2, + (long)rec->param3 - rec->param1, + (long)rec->param4 - rec->param2, + (long)rec->param5); + break; + } +// case META_PATBLT: +// case META_SAVEDC: + case META_SETPIXEL: + { +// rec->param1 = getshort(handle); // x1 +// rec->param2 = getshort(handle); // y1 +// rec->param3 = getint(handle); // COLORREF + break; + } +// case META_OFFSETCLIPRGN: + case META_TEXTOUT: + { +/* + int count = getshort(handle); + rec->stringParam = new char[count+1]; + fread((void *)rec->stringParam, sizeof(char), count, handle); + rec->stringParam[count] = 0; + rec->param2 = getshort(handle); // Y + rec->param1 = getshort(handle); // X +*/ + break; + } +// case META_BITBLT: +// case META_STRETCHBLT: + case META_POLYGON: + { +/* + rec->param1 = getshort(handle); + rec->points = new wxRealPoint[(int)rec->param1]; + for (int i = 0; i < rec->param1; i++) + { + rec->points[i].x = getshort(handle); + rec->points[i].y = getshort(handle); + } +*/ + break; + } + case META_POLYLINE: + { +/* + wxMetaRecord *rec = new wxMetaRecord(META_POLYLINE); + rec->param1 = (long)getshort(handle); + rec->points = new wxRealPoint[(int)rec->param1]; + for (int i = 0; i < rec->param1; i++) + { + rec->points[i].x = getshort(handle); + rec->points[i].y = getshort(handle); + } +*/ + break; + } +// case META_ESCAPE: +// case META_RESTOREDC: +// case META_FILLREGION: +// case META_FRAMEREGION: +// case META_INVERTREGION: +// case META_PAINTREGION: +// case META_SELECTCLIPREGION: // DO THIS! + case META_SELECTOBJECT: + { +/* + wxMetaRecord *rec = new wxMetaRecord(META_SELECTOBJECT); + rec->param1 = (long)getshort(handle); // Position of object in gdiObjects list +*/ + break; + } +// case META_SETTEXTALIGN: +// case META_DRAWTEXT: +// case META_CHORD: +// case META_SETMAPPERFLAGS: +// case META_EXTTEXTOUT: +// case META_SETDIBTODEV: +// case META_SELECTPALETTE: +// case META_REALIZEPALETTE: +// case META_ANIMATEPALETTE: +// case META_SETPALENTRIES: +// case META_POLYPOLYGON: +// case META_RESIZEPALETTE: +// case META_DIBBITBLT: +// case META_DIBSTRETCHBLT: + case META_DIBCREATEPATTERNBRUSH: + { +/* + fread((void *)wxBuffer, sizeof(char), (int)(rdSize - 3), handle); +*/ + break; + } +// case META_STRETCHDIB: +// case META_EXTFLOODFILL: +// case META_RESETDC: +// case META_STARTDOC: +// case META_STARTPAGE: +// case META_ENDPAGE: +// case META_ABORTDOC: +// case META_ENDDOC: +// case META_DELETEOBJECT: // DO!! + case META_CREATEPALETTE: + { +/* + wxMetaRecord *rec = new wxMetaRecord(META_CREATEPALETTE); + fread((void *)wxBuffer, sizeof(char), (int)(rdSize - 3), handle); +*/ + break; + } + case META_CREATEBRUSH: + { +/* + fread((void *)wxBuffer, sizeof(char), (int)(rdSize - 3), handle); +*/ + break; + } + case META_CREATEPATTERNBRUSH: + { +/* + fread((void *)wxBuffer, sizeof(char), (int)(rdSize - 3), handle); +*/ + break; + } + case META_CREATEPENINDIRECT: + { +/* + int msStyle = getshort(handle); // Style: 2 bytes + int x = getshort(handle); // X: 2 bytes + int y = getshort(handle); // Y: 2 bytes + int colorref = getint(handle); // COLORREF 4 bytes + + int style; + if (msStyle == PS_DOT) + style = wxDOT; + else if (msStyle == PS_DASH) + style = wxSHORT_DASH; + else if (msStyle == PS_NULL) + style = wxTRANSPARENT; + else style = wxSOLID; + + wxColour colour(GetRValue(colorref), GetGValue(colorref), GetBValue(colorref)); + rec->param1 = (long)wxThePenList->FindOrCreatePen(&colour, x, style); +*/ + break; + } + case META_CREATEFONTINDIRECT: + { +/* + int lfHeight = getshort(handle); + int lfWidth = getshort(handle); + int lfEsc = getshort(handle); + int lfOrient = getshort(handle); + int lfWeight = getshort(handle); + char lfItalic = getc(handle); + char lfUnderline = getc(handle); + char lfStrikeout = getc(handle); + char lfCharSet = getc(handle); + char lfOutPrecision = getc(handle); + char lfClipPrecision = getc(handle); + char lfQuality = getc(handle); + char lfPitchAndFamily = getc(handle); + char lfFacename[32]; + fread((void *)lfFacename, sizeof(char), 32, handle); + + int family; + if (lfPitchAndFamily & FF_MODERN) + family = wxMODERN; + else if (lfPitchAndFamily & FF_MODERN) + family = wxMODERN; + else if (lfPitchAndFamily & FF_ROMAN) + family = wxROMAN; + else if (lfPitchAndFamily & FF_SWISS) + family = wxSWISS; + else if (lfPitchAndFamily & FF_DECORATIVE) + family = wxDECORATIVE; + else + family = wxDEFAULT; + + int weight; + if (lfWeight == 300) + weight = wxLIGHT; + else if (lfWeight == 400) + weight = wxNORMAL; + else if (lfWeight == 900) + weight = wxBOLD; + else weight = wxNORMAL; + + int style; + if ((bool)lfItalic) + style = wxITALIC; + else + style = wxNORMAL; + + // About how many pixels per inch??? + int logPixelsY = 100; + int pointSize = (int)(lfHeight*72.0/logPixelsY); + + wxFont *theFont = + wxTheFontList->FindOrCreateFont(pointSize, family, style, weight, (bool)lfUnderline); + + rec->param1 = (long)theFont; +*/ + break; + } + case META_CREATEBRUSHINDIRECT: + { +/* + int msStyle = getshort(handle); // Style: 2 bytes + int colorref = getint(handle); // COLORREF: 4 bytes + int hatchStyle = getshort(handle); // Hatch style 2 bytes + + int style; + if (msStyle == PS_DOT) + style = wxDOT; + else if (msStyle == PS_DASH) + style = wxSHORT_DASH; + else if (msStyle == PS_NULL) + style = wxTRANSPARENT; + else style = wxSOLID; + + wxColour colour(GetRValue(colorref), GetGValue(colorref), GetBValue(colorref)); + rec->param1 = (long)wxTheBrushList->FindOrCreateBrush(&colour, wxSOLID); +*/ + break; + } + case META_CREATEBITMAPINDIRECT: + { +/* + fread((void *)wxBuffer, sizeof(char), (int)(rdSize - 3), handle); +*/ + break; + } + case META_CREATEBITMAP: + { +/* + fread((void *)wxBuffer, sizeof(char), (int)(rdSize - 3), handle); +*/ + break; + } + case META_CREATEREGION: + { + dc->DestroyClippingRegion(); +/* + rec->param1 = getshort(handle); // Style: 2 bytes +*/ + break; + } + default: + { + break; + } + } + node = node->Next(); + } + return TRUE; +} + diff --git a/src/ogl/misc.cpp b/src/ogl/misc.cpp new file mode 100644 index 0000000000..4a2e766734 --- /dev/null +++ b/src/ogl/misc.cpp @@ -0,0 +1,894 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: misc.cpp +// Purpose: Miscellaneous OGL support functions +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "misc.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#include + +#if wxUSE_IOSTREAMH +#include +#else +#include +#endif +#include +#include +#include + +#include +#include +#include +#include +#include + +wxFont* g_oglNormalFont; +wxPen* g_oglBlackPen; +wxPen* g_oglWhiteBackgroundPen; +wxPen* g_oglTransparentPen; +wxBrush* g_oglWhiteBackgroundBrush; +wxPen* g_oglBlackForegroundPen; +wxCursor* g_oglBullseyeCursor = NULL; + +char* oglBuffer = NULL; + +wxList oglObjectCopyMapping(wxKEY_INTEGER); + + + +void wxOGLInitialize() +{ + g_oglBullseyeCursor = new wxCursor(wxCURSOR_BULLSEYE); + + g_oglNormalFont = new wxFont(10, wxSWISS, wxNORMAL, wxNORMAL); + + g_oglBlackPen = new wxPen("BLACK", 1, wxSOLID); + + g_oglWhiteBackgroundPen = new wxPen("WHITE", 1, wxSOLID); + g_oglTransparentPen = new wxPen("WHITE", 1, wxTRANSPARENT); + g_oglWhiteBackgroundBrush = new wxBrush("WHITE", wxSOLID); + g_oglBlackForegroundPen = new wxPen("BLACK", 1, wxSOLID); + + OGLInitializeConstraintTypes(); + + // Initialize big buffer used when writing images + oglBuffer = new char[3000]; + +} + +void wxOGLCleanUp() +{ + if (oglBuffer) + { + delete[] oglBuffer; + oglBuffer = NULL; + } + oglBuffer = NULL; + if (g_oglBullseyeCursor) + { + delete g_oglBullseyeCursor; + g_oglBullseyeCursor = NULL; + } + + if (g_oglNormalFont) + { + delete g_oglNormalFont; + g_oglNormalFont = NULL; + } + if (g_oglBlackPen) + { + delete g_oglBlackPen; + g_oglBlackPen = NULL; + } + if (g_oglWhiteBackgroundPen) + { + delete g_oglWhiteBackgroundPen; + g_oglWhiteBackgroundPen = NULL; + } + if (g_oglTransparentPen) + { + delete g_oglTransparentPen; + g_oglTransparentPen = NULL; + } + if (g_oglWhiteBackgroundBrush) + { + delete g_oglWhiteBackgroundBrush; + g_oglWhiteBackgroundBrush = NULL; + } + if (g_oglBlackForegroundPen) + { + delete g_oglBlackForegroundPen; + g_oglBlackForegroundPen = NULL; + } + + OGLCleanUpConstraintTypes(); +} + +wxFont *oglMatchFont(int point_size) +{ + wxFont *font = wxTheFontList->FindOrCreateFont(point_size, wxSWISS, wxNORMAL, wxNORMAL); +#if 0 + switch (point_size) + { + case 4: + font = swiss_font_4; + break; + case 6: + font = swiss_font_6; + break; + case 8: + font = swiss_font_8; + break; + case 12: + font = swiss_font_12; + break; + case 14: + font = swiss_font_14; + break; + case 18: + font = swiss_font_18; + break; + case 24: + font = swiss_font_24; + break; + default: + case 10: + font = swiss_font_10; + break; + } +#endif + return font; +} + +int FontSizeDialog(wxFrame *parent, int old_size) +{ + if (old_size <= 0) + old_size = 10; + char buf[40]; + sprintf(buf, "%d", old_size); + wxString ans = wxGetTextFromUser("Enter point size", "Font size", buf, parent); + if (ans == "") + return 0; + + int new_size = atoi(ans); + if ((new_size <= 0) || (new_size > 40)) + { + wxMessageBox("Invalid point size!", "Error", wxOK); + return 0; + } + return new_size; +/* + char *strings[8]; + strings[0] = "4"; + strings[1] = "6"; + strings[2] = "8"; + strings[3] = "10"; + strings[4] = "12"; + strings[5] = "14"; + strings[6] = "18"; + strings[7] = "24"; + char *ans = wxGetSingleChoice("Choose", "Choose a font size", 8, strings, parent); + if (ans) + { + int size; + sscanf(ans, "%d", &size); + return oglMatchFont(size); + } + else return NULL; +*/ +} + +// Centre a list of strings in the given box. xOffset and yOffset are the +// the positions that these lines should be relative to, and this might be +// the same as m_xpos, m_ypos, but might be zero if formatting from left-justifying. +void oglCentreText(wxDC& dc, wxList *text_list, + double m_xpos, double m_ypos, double width, double height, + int formatMode) +{ + int n = text_list->Number(); + + if (!text_list || (n == 0)) + return; + + // First, get maximum dimensions of box enclosing text + + long char_height = 0; + long max_width = 0; + long current_width = 0; + + // Store text extents for speed + double *widths = new double[n]; + + wxNode *current = text_list->First(); + int i = 0; + while (current) + { + wxShapeTextLine *line = (wxShapeTextLine *)current->Data(); + dc.GetTextExtent(line->GetText(), ¤t_width, &char_height); + widths[i] = current_width; + + if (current_width > max_width) + max_width = current_width; + current = current->Next(); + i ++; + } + + double max_height = n*char_height; + + double xoffset, yoffset, xOffset, yOffset; + + if (formatMode & FORMAT_CENTRE_VERT) + { + if (max_height < height) + yoffset = (double)(m_ypos - (height/2.0) + (height - max_height)/2.0); + else + yoffset = (double)(m_ypos - (height/2.0)); + yOffset = m_ypos; + } + else + { + yoffset = 0.0; + yOffset = 0.0; + } + + if (formatMode & FORMAT_CENTRE_HORIZ) + { + xoffset = (double)(m_xpos - width/2.0); + xOffset = m_xpos; + } + else + { + xoffset = 0.0; + xOffset = 0.0; + } + + current = text_list->First(); + i = 0; + + while (current) + { + wxShapeTextLine *line = (wxShapeTextLine *)current->Data(); + + double x; + if ((formatMode & FORMAT_CENTRE_HORIZ) && (widths[i] < width)) + x = (double)((width - widths[i])/2.0 + xoffset); + else + x = xoffset; + double y = (double)(i*char_height + yoffset); + + line->SetX( x - xOffset ); line->SetY( y - yOffset ); + current = current->Next(); + i ++; + } + + delete widths; +} + +// Centre a list of strings in the given box +void oglCentreTextNoClipping(wxDC& dc, wxList *text_list, + double m_xpos, double m_ypos, double width, double height) +{ + int n = text_list->Number(); + + if (!text_list || (n == 0)) + return; + + // First, get maximum dimensions of box enclosing text + + long char_height = 0; + long max_width = 0; + long current_width = 0; + + // Store text extents for speed + double *widths = new double[n]; + + wxNode *current = text_list->First(); + int i = 0; + while (current) + { + wxShapeTextLine *line = (wxShapeTextLine *)current->Data(); + dc.GetTextExtent(line->GetText(), ¤t_width, &char_height); + widths[i] = current_width; + + if (current_width > max_width) + max_width = current_width; + current = current->Next(); + i ++; + } + + double max_height = n*char_height; + + double yoffset = (double)(m_ypos - (height/2.0) + (height - max_height)/2.0); + + double xoffset = (double)(m_xpos - width/2.0); + + current = text_list->First(); + i = 0; + + while (current) + { + wxShapeTextLine *line = (wxShapeTextLine *)current->Data(); + + double x = (double)((width - widths[i])/2.0 + xoffset); + double y = (double)(i*char_height + yoffset); + + line->SetX( x - m_xpos ); line->SetY( y - m_ypos ); + current = current->Next(); + i ++; + } + delete widths; +} + +void oglGetCentredTextExtent(wxDC& dc, wxList *text_list, + double m_xpos, double m_ypos, double width, double height, + double *actual_width, double *actual_height) +{ + int n = text_list->Number(); + + if (!text_list || (n == 0)) + { + *actual_width = 0; + *actual_height = 0; + return; + } + + // First, get maximum dimensions of box enclosing text + + long char_height = 0; + long max_width = 0; + long current_width = 0; + + wxNode *current = text_list->First(); + int i = 0; + while (current) + { + wxShapeTextLine *line = (wxShapeTextLine *)current->Data(); + dc.GetTextExtent(line->GetText(), ¤t_width, &char_height); + + if (current_width > max_width) + max_width = current_width; + current = current->Next(); + i ++; + } + + *actual_height = n*char_height; + *actual_width = max_width; +} + +// Format a string to a list of strings that fit in the given box. +// Interpret %n and 10 or 13 as a new line. +wxStringList *oglFormatText(wxDC& dc, const wxString& text, double width, double height, int formatMode) +{ + // First, parse the string into a list of words + wxStringList word_list; + + // Make new lines into NULL strings at this point + int i = 0; int j = 0; int len = strlen(text); + char word[200]; word[0] = 0; + bool end_word = FALSE; bool new_line = FALSE; + while (i < len) + { + switch (text[i]) + { + case '%': + { + i ++; + if (i == len) + { word[j] = '%'; j ++; } + else + { + if (text[i] == 'n') + { new_line = TRUE; end_word = TRUE; i++; } + else + { word[j] = '%'; j ++; word[j] = text[i]; j ++; i ++; } + } + break; + } + case 10: + { + new_line = TRUE; end_word = TRUE; i++; + break; + } + case 13: + { + new_line = TRUE; end_word = TRUE; i++; + } + case ' ': + { + end_word = TRUE; + i ++; + break; + } + default: + { + word[j] = text[i]; + j ++; i ++; + break; + } + } + if (i == len) end_word = TRUE; + if (end_word) + { + word[j] = 0; + j = 0; + word_list.Add(word); + end_word = FALSE; + } + if (new_line) + { + word_list.Append(NULL); + new_line = FALSE; + } + } + // Now, make a list of strings which can fit in the box + wxStringList *string_list = new wxStringList; + + char buffer[400]; + buffer[0] = 0; + wxNode *node = word_list.First(); + long x, y; + + while (node) + { + wxString oldBuffer(buffer); + + char *s = (char *)node->Data(); + if (!s) + { + // FORCE NEW LINE + if (strlen(buffer) > 0) + string_list->Add(buffer); + + buffer[0] = 0; + } + else + { + if (buffer[0] != 0) + strcat(buffer, " "); + + strcat(buffer, s); + dc.GetTextExtent(buffer, &x, &y); + + // Don't fit within the bounding box if we're fitting shape to contents + if ((x > width) && !(formatMode & FORMAT_SIZE_TO_CONTENTS)) + { + // Deal with first word being wider than box + if (oldBuffer.Length() > 0) + string_list->Add(oldBuffer); + + buffer[0] = 0; + strcat(buffer, s); + } + } + + node = node->Next(); + } + if (buffer[0] != 0) + string_list->Add(buffer); + + return string_list; +} + +void oglDrawFormattedText(wxDC& dc, wxList *text_list, + double m_xpos, double m_ypos, double width, double height, + int formatMode) +{ + double xoffset, yoffset; + if (formatMode & FORMAT_CENTRE_HORIZ) + xoffset = m_xpos; + else + xoffset = (double)(m_xpos - (width / 2.0)); + + if (formatMode & FORMAT_CENTRE_VERT) + yoffset = m_ypos; + else + yoffset = (double)(m_ypos - (height / 2.0)); + + dc.SetClippingRegion( + (long)(m_xpos - width/2.0), (long)(m_ypos - height/2.0), + (long)width, (long)height); + + wxNode *current = text_list->First(); + while (current) + { + wxShapeTextLine *line = (wxShapeTextLine *)current->Data(); + + dc.DrawText(line->GetText(), WXROUND(xoffset + line->GetX()), WXROUND(yoffset + line->GetY())); + current = current->Next(); + } + + dc.DestroyClippingRegion(); +} + +/* + * Find centroid given list of points comprising polyline + * + */ + +void oglFindPolylineCentroid(wxList *points, double *x, double *y) +{ + double xcount = 0; + double ycount = 0; + + wxNode *node = points->First(); + while (node) + { + wxRealPoint *point = (wxRealPoint *)node->Data(); + xcount += point->x; + ycount += point->y; + node = node->Next(); + } + + *x = (xcount/points->Number()); + *y = (ycount/points->Number()); +} + +/* + * Check that (x1, y1) -> (x2, y2) hits (x3, y3) -> (x4, y4). + * If so, ratio1 gives the proportion along the first line + * that the intersection occurs (or something like that). + * Used by functions below. + * + */ +void oglCheckLineIntersection(double x1, double y1, double x2, double y2, + double x3, double y3, double x4, double y4, + double *ratio1, double *ratio2) +{ + double denominator_term = (y4 - y3)*(x2 - x1) - (y2 - y1)*(x4 - x3); + double numerator_term = (x3 - x1)*(y4 - y3) + (x4 - x3)*(y1 - y3); + + double line_constant; + double length_ratio = 1.0; + double k_line = 1.0; + + // Check for parallel lines + if ((denominator_term < 0.005) && (denominator_term > -0.005)) + line_constant = -1.0; + else + line_constant = numerator_term/denominator_term; + + // Check for intersection + if ((line_constant < 1.0) && (line_constant > 0.0)) + { + // Now must check that other line hits + if (((y4 - y3) < 0.005) && ((y4 - y3) > -0.005)) + k_line = ((x1 - x3) + line_constant*(x2 - x1))/(x4 - x3); + else + k_line = ((y1 - y3) + line_constant*(y2 - y1))/(y4 - y3); + + if ((k_line >= 0.0) && (k_line < 1.0)) + length_ratio = line_constant; + else + k_line = 1.0; + } + *ratio1 = length_ratio; + *ratio2 = k_line; +} + +/* + * Find where (x1, y1) -> (x2, y2) hits one of the lines in xvec, yvec. + * (*x3, *y3) is the point where it hits. + * + */ +void oglFindEndForPolyline(double n, double xvec[], double yvec[], + double x1, double y1, double x2, double y2, double *x3, double *y3) +{ + int i; + double lastx = xvec[0]; + double lasty = yvec[0]; + + double min_ratio = 1.0; + double line_ratio; + double other_ratio; + + for (i = 1; i < n; i++) + { + oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[i], yvec[i], + &line_ratio, &other_ratio); + lastx = xvec[i]; + lasty = yvec[i]; + + if (line_ratio < min_ratio) + min_ratio = line_ratio; + } + + // Do last (implicit) line if last and first doubles are not identical + if (!(xvec[0] == lastx && yvec[0] == lasty)) + { + oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[0], yvec[0], + &line_ratio, &other_ratio); + + if (line_ratio < min_ratio) + min_ratio = line_ratio; + } + + *x3 = (x1 + (x2 - x1)*min_ratio); + *y3 = (y1 + (y2 - y1)*min_ratio); + +} + +/* + * Find where the line hits the box. + * + */ + +void oglFindEndForBox(double width, double height, + double x1, double y1, // Centre of box (possibly) + double x2, double y2, // other end of line + double *x3, double *y3) // End on box edge +{ + double xvec[5]; + double yvec[5]; + + xvec[0] = (double)(x1 - width/2.0); + yvec[0] = (double)(y1 - height/2.0); + xvec[1] = (double)(x1 - width/2.0); + yvec[1] = (double)(y1 + height/2.0); + xvec[2] = (double)(x1 + width/2.0); + yvec[2] = (double)(y1 + height/2.0); + xvec[3] = (double)(x1 + width/2.0); + yvec[3] = (double)(y1 - height/2.0); + xvec[4] = (double)(x1 - width/2.0); + yvec[4] = (double)(y1 - height/2.0); + + oglFindEndForPolyline(5, xvec, yvec, x2, y2, x1, y1, x3, y3); +} + +/* + * Find where the line hits the circle. + * + */ + +void oglFindEndForCircle(double radius, + double x1, double y1, // Centre of circle + double x2, double y2, // Other end of line + double *x3, double *y3) +{ + double H = (double)sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)); + + if (H == 0.0) + { + *x3 = x1; + *y3 = y1; + } + else + { + *y3 = radius * (y2 - y1)/H + y1; + *x3 = radius * (x2 - x1)/H + x1; + } +} + +/* + * Given the line (x1, y1) -> (x2, y2), and an arrow size of given length and width, + * return the position of the tip of the arrow and the left and right vertices of the arrow. + * + */ + +void oglGetArrowPoints(double x1, double y1, double x2, double y2, + double length, double width, + double *tip_x, double *tip_y, + double *side1_x, double *side1_y, + double *side2_x, double *side2_y) +{ + double l = (double)sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)); + + if (l < 0.01) + l = (double) 0.01; + + double i_bar = (x2 - x1)/l; + double j_bar = (y2 - y1)/l; + + double x3 = (- length*i_bar) + x2; + double y3 = (- length*j_bar) + y2; + + *side1_x = width*(-j_bar) + x3; + *side1_y = width*i_bar + y3; + + *side2_x = -width*(-j_bar) + x3; + *side2_y = -width*i_bar + y3; + + *tip_x = x2; *tip_y = y2; +} + +/* + * Given an ellipse and endpoints of a line, returns the point at which + * the line touches the ellipse in values x4, y4. + * This function assumes that the centre of the ellipse is at x1, y1, and the + * ellipse has a width of width1 and a height of height1. It also assumes you are + * wanting to draw an arc FROM point x2, y2 TOWARDS point x3, y3. + * This function calculates the x,y coordinates of the intersection point of + * the arc with the ellipse. + * Author: Ian Harrison + */ + +void oglDrawArcToEllipse(double x1, double y1, double width1, double height1, double x2, double y2, double x3, double y3, + double *x4, double *y4) +{ + double a1 = (double)(width1/2.0); + double b1 = (double)(height1/2.0); + + // These are required to give top left x and y coordinates for DrawEllipse +// double top_left_x1 = (double)(x1 - a1); +// double top_left_y1 = (double)(y1 - b1); +/* + // Check for vertical line + if (fabs(x2 - x3) < 0.05) + { + *x4 = x3; + if (y2 < y3) + *y4 = (double)(y1 - b1); + else + *y4 = (double)(y1 + b1); + return; + } +*/ + // Check that x2 != x3 + if (fabs(x2 - x3) < 0.05) + { + *x4 = x2; + if (y3 > y2) + *y4 = (double)(y1 - sqrt((b1*b1 - (((x2-x1)*(x2-x1))*(b1*b1)/(a1*a1))))); + else + *y4 = (double)(y1 + sqrt((b1*b1 - (((x2-x1)*(x2-x1))*(b1*b1)/(a1*a1))))); + return; + } + + // Calculate the x and y coordinates of the point where arc intersects ellipse + + double A, B, C, D, E, F, G, H, K; + double ellipse1_x, ellipse1_y; + + A = (double)(1/(a1 * a1)); + B = (double)((y3 - y2) * (y3 - y2)) / ((x3 - x2) * (x3 - x2) * b1 * b1); + C = (double)(2 * (y3 - y2) * (y2 - y1)) / ((x3 - x2) * b1 * b1); + D = (double)((y2 - y1) * (y2 - y1)) / (b1 * b1); + E = (double)(A + B); + F = (double)(C - (2 * A * x1) - (2 * B * x2)); + G = (double)((A * x1 * x1) + (B * x2 * x2) - (C * x2) + D - 1); + H = (double)((y3 - y2) / (x3 - x2)); + K = (double)((F * F) - (4 * E * G)); + + if (K >= 0) + // In this case the line intersects the ellipse, so calculate intersection + { + if(x2 >= x1) + { + ellipse1_x = (double)(((F * -1) + sqrt(K)) / (2 * E)); + ellipse1_y = (double)((H * (ellipse1_x - x2)) + y2); + } + else + { + ellipse1_x = (double)(((F * -1) - sqrt(K)) / (2 * E)); + ellipse1_y = (double)((H * (ellipse1_x - x2)) + y2); + } + } + else + // in this case, arc does not intersect ellipse, so just draw arc + { + ellipse1_x = x3; + ellipse1_y = y3; + } + *x4 = ellipse1_x; + *y4 = ellipse1_y; + +/* + // Draw a little circle (radius = 2) at the end of the arc where it hits + // the ellipse . + + double circle_x = ellipse1_x - 2.0; + double circle_y = ellipse1_y - 2.0; + m_canvas->DrawEllipse(circle_x, circle_y, 4.0, 4.0); +*/ +} + +// Update a list item from a list of strings +void UpdateListBox(wxListBox *item, wxList *list) +{ + item->Clear(); + if (!list) + return; + + wxNode *node = list->First(); + while (node) + { + char *s = (char *)node->Data(); + item->Append(s); + node = node->Next(); + } +} + +bool oglRoughlyEqual(double val1, double val2, double tol) +{ + return ( (val1 < (val2 + tol)) && (val1 > (val2 - tol)) && + (val2 < (val1 + tol)) && (val2 > (val1 - tol))); +} + +/* + * Hex<->Dec conversion + */ + +// Array used in DecToHex conversion routine. +static char sg_HexArray[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F' }; + +// Convert 2-digit hex number to decimal +unsigned int oglHexToDec(char* buf) +{ + int firstDigit, secondDigit; + + if (buf[0] >= 'A') + firstDigit = buf[0] - 'A' + 10; + else + firstDigit = buf[0] - '0'; + + if (buf[1] >= 'A') + secondDigit = buf[1] - 'A' + 10; + else + secondDigit = buf[1] - '0'; + + return firstDigit * 16 + secondDigit; +} + +// Convert decimal integer to 2-character hex string +void oglDecToHex(unsigned int dec, char *buf) +{ + int firstDigit = (int)(dec/16.0); + int secondDigit = (int)(dec - (firstDigit*16.0)); + buf[0] = sg_HexArray[firstDigit]; + buf[1] = sg_HexArray[secondDigit]; + buf[2] = 0; +} + +// 3-digit hex to wxColour +wxColour oglHexToColour(const wxString& hex) +{ + if (hex.Length() == 6) + { + char buf[7]; + strncpy(buf, hex, 7); + unsigned int r = oglHexToDec((char *)buf); + unsigned int g = oglHexToDec((char *)(buf+2)); + unsigned int b = oglHexToDec((char *)(buf+4)); + return wxColour(r, g, b); + } + else + return wxColour(0,0,0); +} + +// RGB to 3-digit hex +wxString oglColourToHex(const wxColour& colour) +{ + char buf[7]; + unsigned int red = colour.Red(); + unsigned int green = colour.Green(); + unsigned int blue = colour.Blue(); + + oglDecToHex(red, buf); + oglDecToHex(green, buf+2); + oglDecToHex(blue, buf+4); + + return wxString(buf); +} + + diff --git a/src/ogl/ogldiag.cpp b/src/ogl/ogldiag.cpp new file mode 100644 index 0000000000..6698e5b143 --- /dev/null +++ b/src/ogl/ogldiag.cpp @@ -0,0 +1,756 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: ogldiag.cpp +// Purpose: wxDiagram +// Author: Julian Smart +// Modified by: +// Created: 12/07/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "ogldiag.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#if wxUSE_IOSTREAMH +#include +#include +#else +#include +#include +#ifdef _MSC_VER +using namespace std; +#endif +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +IMPLEMENT_DYNAMIC_CLASS(wxDiagram, wxObject) + +// Object canvas +wxDiagram::wxDiagram() +{ + m_diagramCanvas = NULL; + m_quickEditMode = FALSE; + m_snapToGrid = TRUE; + m_gridSpacing = 5.0; + m_shapeList = new wxList; + m_mouseTolerance = DEFAULT_MOUSE_TOLERANCE; +} + +wxDiagram::~wxDiagram() +{ + if (m_shapeList) + delete m_shapeList; +} + +void wxDiagram::SetSnapToGrid(bool snap) +{ + m_snapToGrid = snap; +} + +void wxDiagram::SetGridSpacing(double spacing) +{ + m_gridSpacing = spacing; +} + +void wxDiagram::Snap(double *x, double *y) +{ + if (m_snapToGrid) + { + *x = m_gridSpacing * ((int)(*x/m_gridSpacing + 0.5)); + *y = m_gridSpacing * ((int)(*y/m_gridSpacing + 0.5)); + } +} + + +void wxDiagram::Redraw(wxDC& dc) +{ + if (m_shapeList) + { + if (GetCanvas()) + GetCanvas()->SetCursor(* wxHOURGLASS_CURSOR); + wxNode *current = m_shapeList->First(); + + while (current) + { + wxShape *object = (wxShape *)current->Data(); + if (!object->GetParent()) + object->Draw(dc); + + current = current->Next(); + } + if (GetCanvas()) + GetCanvas()->SetCursor(* wxSTANDARD_CURSOR); + } +} + +void wxDiagram::Clear(wxDC& dc) +{ + dc.Clear(); +} + +// Insert object after addAfter, or at end of list. +void wxDiagram::AddShape(wxShape *object, wxShape *addAfter) +{ + wxNode *nodeAfter = NULL; + if (addAfter) + nodeAfter = m_shapeList->Member(addAfter); + + if (!m_shapeList->Member(object)) + { + if (nodeAfter) + { + if (nodeAfter->Next()) + m_shapeList->Insert(nodeAfter->Next(), object); + else + m_shapeList->Append(object); + } + else + m_shapeList->Append(object); + object->SetCanvas(GetCanvas()); + } +} + +void wxDiagram::InsertShape(wxShape *object) +{ + m_shapeList->Insert(object); + object->SetCanvas(GetCanvas()); +} + +void wxDiagram::RemoveShape(wxShape *object) +{ + m_shapeList->DeleteObject(object); +} + +// Should this delete the actual objects too? I think not. +void wxDiagram::RemoveAllShapes() +{ + m_shapeList->Clear(); +} + +void wxDiagram::DeleteAllShapes() +{ + wxNode *node = m_shapeList->First(); + while (node) + { + wxShape *shape = (wxShape *)node->Data(); + if (!shape->GetParent()) + { + RemoveShape(shape); + delete shape; + node = m_shapeList->First(); + } + else + node = node->Next(); + } +} + +void wxDiagram::ShowAll(bool show) +{ + wxNode *current = m_shapeList->First(); + + while (current) + { + wxShape *object = (wxShape *)current->Data(); + object->Show(show); + + current = current->Next(); + } +} + +void wxDiagram::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)); + + wxPoint points[5]; + + points[0].x = (int) x1; + points[0].y = (int) y1; + + points[1].x = (int) x2; + points[1].y = (int) y1; + + points[2].x = (int) x2; + points[2].y = (int) y2; + + points[3].x = (int) x1; + points[3].y = (int) y2; + + points[4].x = (int) x1; + points[4].y = (int) y1; + dc.DrawLines(5, points); +} + +// Make sure all text that should be centred, is centred. +void wxDiagram::RecentreAll(wxDC& dc) +{ + wxNode *object_node = m_shapeList->First(); + while (object_node) + { + wxShape *obj = (wxShape *)object_node->Data(); + obj->Recentre(dc); + object_node = object_node->Next(); + } +} + +// Input/output +#ifdef PROLOGIO +bool wxDiagram::SaveFile(const wxString& filename) +{ + wxBeginBusyCursor(); + + wxExprDatabase *database = new wxExprDatabase; + + // First write the diagram type + wxExpr *header = new wxExpr("diagram"); + OnHeaderSave(*database, *header); + + database->Append(header); + + wxNode *node = m_shapeList->First(); + while (node) + { + wxShape *shape = (wxShape *)node->Data(); + + if (!shape->IsKindOf(CLASSINFO(wxControlPoint))) + { + wxExpr *expr = NULL; + if (shape->IsKindOf(CLASSINFO(wxLineShape))) + expr = new wxExpr("line"); + else + expr = new wxExpr("shape"); + + OnShapeSave(*database, *shape, *expr); + } + node = node->Next(); + } + OnDatabaseSave(*database); + + char tempFile[400]; + wxGetTempFileName("diag", tempFile); + FILE* file = fopen(tempFile, "w"); + if (! file) + { + wxEndBusyCursor(); + delete database; + return FALSE; + } + + database->Write(file); + fclose(file); + delete database; + +/* + // Save backup + if (FileExists(filename)) + { + char buf[400]; +#ifdef __X__ + sprintf(buf, "%s.bak", filename); +#endif +#ifdef __WXMSW__ + sprintf(buf, "_diagram.bak"); +#endif + if (FileExists(buf)) wxRemoveFile(buf); + if (!wxRenameFile(filename, buf)) + { + wxCopyFile(filename, buf); + wxRemoveFile(filename); + } + } +*/ + + // Copy the temporary file to the correct filename + if (!wxRenameFile(tempFile, filename)) + { + wxCopyFile(tempFile, filename); + wxRemoveFile(tempFile); + } + + wxEndBusyCursor(); + return TRUE; +} + +bool wxDiagram::LoadFile(const wxString& filename) +{ + wxBeginBusyCursor(); + + wxExprDatabase database(wxExprInteger, "id"); + if (!database.Read(filename)) + { + wxEndBusyCursor(); + return FALSE; + } + + DeleteAllShapes(); + + database.BeginFind(); + wxExpr *header = database.FindClauseByFunctor("diagram"); + + if (header) + OnHeaderLoad(database, *header); + + // Scan through all clauses and register the ids + wxNode *node = database.First(); + while (node) + { + wxExpr *clause = (wxExpr *)node->Data(); + long id = -1; + clause->GetAttributeValue("id", id); + wxRegisterId(id); + node = node->Next(); + } + + ReadNodes(database); + ReadContainerGeometry(database); + ReadLines(database); + + OnDatabaseLoad(database); + + wxEndBusyCursor(); + + return TRUE; +} + +void wxDiagram::ReadNodes(wxExprDatabase& database) +{ + // Find and create the node images + database.BeginFind(); + wxExpr *clause = database.FindClauseByFunctor("shape"); + while (clause) + { + char *type = NULL; + long parentId = -1; + + clause->AssignAttributeValue("type", &type); + clause->AssignAttributeValue("parent", &parentId); + wxClassInfo *classInfo = wxClassInfo::FindClass(type); + if (classInfo) + { + wxShape *shape = (wxShape *)classInfo->CreateObject(); + OnShapeLoad(database, *shape, *clause); + + shape->SetCanvas(GetCanvas()); + shape->Show(TRUE); + + m_shapeList->Append(shape); + + // If child of composite, link up + if (parentId > -1) + { + wxExpr *parentExpr = database.HashFind("shape", parentId); + if (parentExpr && parentExpr->GetClientData()) + { + wxShape *parent = (wxShape *)parentExpr->GetClientData(); + shape->SetParent(parent); + parent->GetChildren().Append(shape); + } + } + + clause->SetClientData(shape); + } + if (type) + delete[] type; + + clause = database.FindClauseByFunctor("shape"); + } + return; +} + +void wxDiagram::ReadLines(wxExprDatabase& database) +{ + database.BeginFind(); + wxExpr *clause = database.FindClauseByFunctor("line"); + while (clause) + { + wxString type(""); + long parentId = -1; + + clause->GetAttributeValue("type", type); + clause->GetAttributeValue("parent", parentId); + wxClassInfo *classInfo = wxClassInfo::FindClass((char*) (const char*) type); + if (classInfo) + { + wxLineShape *shape = (wxLineShape *)classInfo->CreateObject(); + shape->Show(TRUE); + + OnShapeLoad(database, *shape, *clause); + shape->SetCanvas(GetCanvas()); + + long image_to = -1; long image_from = -1; + clause->GetAttributeValue("to", image_to); + clause->GetAttributeValue("from", image_from); + + wxExpr *image_to_expr = database.HashFind("shape", image_to); + + if (!image_to_expr) + { + // Error + } + wxExpr *image_from_expr = database.HashFind("shape", image_from); + + if (!image_from_expr) + { + // Error + } + + if (image_to_expr && image_from_expr) + { + wxShape *image_to_object = (wxShape *)image_to_expr->GetClientData(); + wxShape *image_from_object = (wxShape *)image_from_expr->GetClientData(); + + if (image_to_object && image_from_object) + { + image_from_object->AddLine(shape, image_to_object, shape->GetAttachmentFrom(), shape->GetAttachmentTo()); + } + } + clause->SetClientData(shape); + + m_shapeList->Append(shape); + } + + clause = database.FindClauseByFunctor("line"); + } +} + +// Containers have divisions that reference adjoining divisions, +// so we need a separate pass to link everything up. +// Also used by Symbol Library. +void wxDiagram::ReadContainerGeometry(wxExprDatabase& database) +{ + database.BeginFind(); + wxExpr *clause = database.FindClauseByFunctor("shape"); + while (clause) + { + wxShape *image = (wxShape *)clause->GetClientData(); + if (image && image->IsKindOf(CLASSINFO(wxCompositeShape))) + { + wxCompositeShape *composite = (wxCompositeShape *)image; + wxExpr *divisionExpr = NULL; + + // Find the list of divisions in the composite + clause->GetAttributeValue("divisions", &divisionExpr); + if (divisionExpr) + { + int i = 0; + wxExpr *idExpr = divisionExpr->Nth(i); + while (idExpr) + { + long divisionId = idExpr->IntegerValue(); + wxExpr *childExpr = database.HashFind("shape", divisionId); + if (childExpr && childExpr->GetClientData()) + { + wxDivisionShape *child = (wxDivisionShape *)childExpr->GetClientData(); + composite->GetDivisions().Append(child); + + // Find the adjoining shapes + long leftSideId = -1; + long topSideId = -1; + long rightSideId = -1; + long bottomSideId = -1; + childExpr->GetAttributeValue("left_side", leftSideId); + childExpr->GetAttributeValue("top_side", topSideId); + childExpr->GetAttributeValue("right_side", rightSideId); + childExpr->GetAttributeValue("bottom_side", bottomSideId); + if (leftSideId > -1) + { + wxExpr *leftExpr = database.HashFind("shape", leftSideId); + if (leftExpr && leftExpr->GetClientData()) + { + wxDivisionShape *leftSide = (wxDivisionShape *)leftExpr->GetClientData(); + child->SetLeftSide(leftSide); + } + } + if (topSideId > -1) + { + wxExpr *topExpr = database.HashFind("shape", topSideId); + if (topExpr && topExpr->GetClientData()) + { + wxDivisionShape *topSide = (wxDivisionShape *)topExpr->GetClientData(); + child->SetTopSide(topSide); + } + } + if (rightSideId > -1) + { + wxExpr *rightExpr = database.HashFind("shape", rightSideId); + if (rightExpr && rightExpr->GetClientData()) + { + wxDivisionShape *rightSide = (wxDivisionShape *)rightExpr->GetClientData(); + child->SetRightSide(rightSide); + } + } + if (bottomSideId > -1) + { + wxExpr *bottomExpr = database.HashFind("shape", bottomSideId); + if (bottomExpr && bottomExpr->GetClientData()) + { + wxDivisionShape *bottomSide = (wxDivisionShape *)bottomExpr->GetClientData(); + child->SetBottomSide(bottomSide); + } + } + } + i ++; + idExpr = divisionExpr->Nth(i); + } + } + } + + clause = database.FindClauseByFunctor("shape"); + } +} + +// Allow for modifying file +bool wxDiagram::OnDatabaseLoad(wxExprDatabase& db) +{ + return TRUE; +} + +bool wxDiagram::OnDatabaseSave(wxExprDatabase& db) +{ + return TRUE; +} + +bool wxDiagram::OnShapeSave(wxExprDatabase& db, wxShape& shape, wxExpr& expr) +{ + shape.WriteAttributes(&expr); + db.Append(&expr); + + if (shape.IsKindOf(CLASSINFO(wxCompositeShape))) + { + wxNode *node = shape.GetChildren().First(); + while (node) + { + wxShape *childShape = (wxShape *)node->Data(); + wxExpr *childExpr = new wxExpr("shape"); + OnShapeSave(db, *childShape, *childExpr); + node = node->Next(); + } + } + + return TRUE; +} + +bool wxDiagram::OnShapeLoad(wxExprDatabase& db, wxShape& shape, wxExpr& expr) +{ + shape.ReadAttributes(&expr); + return TRUE; +} + +bool wxDiagram::OnHeaderSave(wxExprDatabase& db, wxExpr& expr) +{ + return TRUE; +} + +bool wxDiagram::OnHeaderLoad(wxExprDatabase& db, wxExpr& expr) +{ + return TRUE; +} + +#endif + +void wxDiagram::SetCanvas(wxShapeCanvas *can) +{ + m_diagramCanvas = can; +} + +// Find a shape by its id +wxShape* wxDiagram::FindShape(long id) const +{ + wxNode* node = GetShapeList()->First(); + while (node) + { + wxShape* shape = (wxShape*) node->Data(); + if (shape->GetId() == id) + return shape; + node = node->Next(); + } + return NULL; +} + + +//// Crossings classes + +wxLineCrossings::wxLineCrossings() +{ +} + +wxLineCrossings::~wxLineCrossings() +{ + ClearCrossings(); +} + +void wxLineCrossings::FindCrossings(wxDiagram& diagram) +{ + ClearCrossings(); + wxNode* node1 = diagram.GetShapeList()->First(); + while (node1) + { + wxShape* shape1 = (wxShape*) node1->Data(); + if (shape1->IsKindOf(CLASSINFO(wxLineShape))) + { + wxLineShape* lineShape1 = (wxLineShape*) shape1; + // Iterate through the segments + wxList* pts1 = lineShape1->GetLineControlPoints(); + int i; + for (i = 0; i < (pts1->Number() - 1); i++) + { + wxRealPoint* pt1_a = (wxRealPoint*) (pts1->Nth(i)->Data()); + wxRealPoint* pt1_b = (wxRealPoint*) (pts1->Nth(i+1)->Data()); + + // Now we iterate through the segments again + + wxNode* node2 = diagram.GetShapeList()->First(); + while (node2) + { + wxShape* shape2 = (wxShape*) node2->Data(); + + // Assume that the same line doesn't cross itself + if (shape2->IsKindOf(CLASSINFO(wxLineShape)) && (shape1 != shape2)) + { + wxLineShape* lineShape2 = (wxLineShape*) shape2; + // Iterate through the segments + wxList* pts2 = lineShape2->GetLineControlPoints(); + int j; + for (j = 0; j < (pts2->Number() - 1); j++) + { + wxRealPoint* pt2_a = (wxRealPoint*) (pts2->Nth(j)->Data()); + wxRealPoint* pt2_b = (wxRealPoint*) (pts2->Nth(j+1)->Data()); + + // Now let's see if these two segments cross. + double ratio1, ratio2; + oglCheckLineIntersection(pt1_a->x, pt1_a->y, pt1_b->x, pt1_b->y, + pt2_a->x, pt2_a->y, pt2_b->x, pt2_b->y, + & ratio1, & ratio2); + + if ((ratio1 < 1.0) && (ratio1 > -1.0)) + { + // Intersection! + wxLineCrossing* crossing = new wxLineCrossing; + crossing->m_intersect.x = (pt1_a->x + (pt1_b->x - pt1_a->x)*ratio1); + crossing->m_intersect.y = (pt1_a->y + (pt1_b->y - pt1_a->y)*ratio1); + + crossing->m_pt1 = * pt1_a; + crossing->m_pt2 = * pt1_b; + crossing->m_pt3 = * pt2_a; + crossing->m_pt4 = * pt2_b; + + crossing->m_lineShape1 = lineShape1; + crossing->m_lineShape2 = lineShape2; + + m_crossings.Append(crossing); + } + } + } + node2 = node2->Next(); + } + } + } + + node1 = node1->Next(); + } +} + +void wxLineCrossings::DrawCrossings(wxDiagram& diagram, wxDC& dc) +{ + dc.SetBrush(*wxTRANSPARENT_BRUSH); + + long arcWidth = 8; + + wxNode* node = m_crossings.First(); + while (node) + { + wxLineCrossing* crossing = (wxLineCrossing*) node->Data(); +// dc.DrawEllipse((long) (crossing->m_intersect.x - (arcWidth/2.0) + 0.5), (long) (crossing->m_intersect.y - (arcWidth/2.0) + 0.5), +// arcWidth, arcWidth); + + + // Let's do some geometry to find the points on either end of the arc. +/* + +(x1, y1) + |\ + | \ + | \ + | \ + | \ + | |\ c c1 + | a | \ + | \ + | - x <-- centre of arc + a1 | b |\ + | | \ c2 + | a2 | \ + | - \ + | b2 \ + | \ + |_______________\ (x2, y2) + b1 + +*/ + + double a1 = wxMax(crossing->m_pt1.y, crossing->m_pt2.y) - wxMin(crossing->m_pt1.y, crossing->m_pt2.y) ; + double b1 = wxMax(crossing->m_pt1.x, crossing->m_pt2.x) - wxMin(crossing->m_pt1.x, crossing->m_pt2.x) ; + double c1 = sqrt( (a1*a1) + (b1*b1) ); + + double c = arcWidth / 2.0; + double a = c * a1/c1 ; + double b = c * b1/c1 ; + + // I'm not sure this is right, since we don't know which direction we should be going in - need + // to know which way the line slopes and choose the sign appropriately. + double arcX1 = crossing->m_intersect.x - b; + double arcY1 = crossing->m_intersect.y - a; + + double arcX2 = crossing->m_intersect.x + b; + double arcY2 = crossing->m_intersect.y + a; + + dc.SetPen(*wxBLACK_PEN); + dc.DrawArc( (long) arcX1, (long) arcY1, (long) arcX2, (long) arcY2, + (long) crossing->m_intersect.x, (long) crossing->m_intersect.y); + + dc.SetPen(*wxWHITE_PEN); + dc.DrawLine( (long) arcX1, (long) arcY1, (long) arcX2, (long) arcY2 ); + + node = node->Next(); + } +} + +void wxLineCrossings::ClearCrossings() +{ + wxNode* node = m_crossings.First(); + while (node) + { + wxLineCrossing* crossing = (wxLineCrossing*) node->Data(); + delete crossing; + node = node->Next(); + } + m_crossings.Clear(); +} + diff --git a/utils/projgen/makeproj.cpp b/utils/projgen/makeproj.cpp index c8a377f17b..4003324e5f 100644 --- a/utils/projgen/makeproj.cpp +++ b/utils/projgen/makeproj.cpp @@ -451,19 +451,19 @@ void MyApp::GenerateSamples(const wxString& dir) wxMessageBox(msg); } - // OGLEdit + // OGLEdit. We have to do it the long way because we need to add the extra ogl.lib. - project.SetIncludeDirs(wxStringList("../../../../include", "../../src", 0)); - project.SetResourceIncludeDirs(wxStringList("../../../../include", 0)); - project.SetLibDirs(wxStringList("../../../../lib", 0)); - project.SetDebugLibDirs(wxStringList("../../../../src/Debug", "../../src/Debug", "../../../../src/jpeg/Debug", "../../../../src/tiff/Debug", 0)); - project.SetReleaseLibDirs(wxStringList("../../../../src/Release", "../../src/Release", "../../../../src/jpeg/Release", "../../../../src/tiff/Release", 0)); + project.SetIncludeDirs(wxStringList("../../../include", 0)); + project.SetResourceIncludeDirs(wxStringList("../../../include", 0)); + project.SetLibDirs(wxStringList("../../../lib", 0)); + project.SetDebugLibDirs(wxStringList("../../../src/Debug", "../../../src/ogl/Debug", "../../../src/jpeg/Debug", "../../../src/tiff/Debug", 0)); + project.SetReleaseLibDirs(wxStringList("../../../src/Release", "../../../src/ogl/Release", "../../../src/jpeg/Release", "../../../src/tiff/Release", 0)); project.SetExtraLibs(wxStringList("ogl.lib", 0)); project.SetProjectName("OGLEditVC"); project.SetTargetName("ogledit"); - project.SetProjectPath(dir + wxString("/utils/ogl/samples/ogledit")); + project.SetProjectPath(dir + wxString("/samples/ogl/ogledit")); project.SetSourceFiles(wxStringList("ogledit.cpp", "doc.cpp", "palette.cpp", "view.cpp", "doc.h", "ogledit.h", "palette.h", "view.h", 0)); @@ -476,16 +476,17 @@ void MyApp::GenerateSamples(const wxString& dir) // OGL Studio - project.SetIncludeDirs(wxStringList("../../../../include", "../../src", 0)); - project.SetResourceIncludeDirs(wxStringList("../../../../include", 0)); - project.SetLibDirs(wxStringList("../../../../lib", 0)); - project.SetDebugLibDirs(wxStringList("../../../../src/Debug", "../../src/Debug", "../../../../src/jpeg/Debug", "../../../../src/tiff/Debug", 0)); - project.SetReleaseLibDirs(wxStringList("../../../../src/Release", "../../src/Release", "../../../../src/jpeg/Release", "../../../../src/tiff/Release", 0)); + project.SetIncludeDirs(wxStringList("../../../include", 0)); + project.SetResourceIncludeDirs(wxStringList("../../../include", 0)); + project.SetLibDirs(wxStringList("../../../lib", 0)); + project.SetDebugLibDirs(wxStringList("../../../src/Debug", "../../../src/ogl/Debug", "../../../src/jpeg/Debug", "../../../src/tiff/Debug", 0)); + project.SetReleaseLibDirs(wxStringList("../../../src/Release", "../../../src/ogl/Release", "../../../src/jpeg/Release", "../../../src/tiff/Release", 0)); + project.SetExtraLibs(wxStringList("ogl.lib", 0)); project.SetProjectName("StudioVC"); project.SetTargetName("studio"); - project.SetProjectPath(dir + wxString("/utils/ogl/samples/studio")); + project.SetProjectPath(dir + wxString("/samples/ogl/studio")); project.SetSourceFiles(wxStringList("studio.cpp", "cspalette.cpp", "dialogs.cpp", "view.cpp", "doc.cpp", "mainfrm.cpp", "project.cpp", "shapes.cpp", "symbols.cpp", "csprint.cpp", "studio.h", "cspalette.h", "dialogs.h", "view.h", -- 2.45.2