]> git.saurik.com Git - wxWidgets.git/commitdiff
Formerly known as wxLayout.
authorKarsten Ballüder <ballueder@usa.net>
Mon, 7 Jun 1999 09:57:14 +0000 (09:57 +0000)
committerKarsten Ballüder <ballueder@usa.net>
Mon, 7 Jun 1999 09:57:14 +0000 (09:57 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@2686 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

14 files changed:
samples/richedit/Micon.xpm [new file with mode: 0644]
samples/richedit/Mpch.h [new file with mode: 0644]
samples/richedit/README [new file with mode: 0644]
samples/richedit/TODO [new file with mode: 0644]
samples/richedit/kbList.cpp [new file with mode: 0644]
samples/richedit/kbList.h [new file with mode: 0644]
samples/richedit/wxLayout.cpp [new file with mode: 0644]
samples/richedit/wxLayout.h [new file with mode: 0644]
samples/richedit/wxllist.cpp [new file with mode: 0644]
samples/richedit/wxllist.h [new file with mode: 0644]
samples/richedit/wxlparser.cpp [new file with mode: 0644]
samples/richedit/wxlparser.h [new file with mode: 0644]
samples/richedit/wxlwindow.cpp [new file with mode: 0644]
samples/richedit/wxlwindow.h [new file with mode: 0644]

diff --git a/samples/richedit/Micon.xpm b/samples/richedit/Micon.xpm
new file mode 100644 (file)
index 0000000..153d3a4
--- /dev/null
@@ -0,0 +1,309 @@
+/* XPM */
+static char *Micon_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    64    48      254            2",
+/* colors */
+".. c #040207",
+".# c #6482b4",
+".a c #2a4471",
+".b c #9cc2d4",
+".c c #4c627f",
+".d c #94918e",
+".e c #0c243e",
+".f c #4c4a4a",
+".g c #3c63a8",
+".h c #7ca2ac",
+".i c #24447e",
+".j c #2c2c2c",
+".k c #5482cc",
+".l c #d4d0d0",
+".m c #99aab7",
+".n c #5c74b1",
+".o c #2c5287",
+".p c #1a2a4d",
+".q c #acdefc",
+".r c #646362",
+".s c #7491d0",
+".t c #bcc4bf",
+".u c #5273aa",
+".v c #b4b1aa",
+".w c #3d5583",
+".x c #828482",
+".y c #8c9490",
+".z c #6f7369",
+".A c #1c365c",
+".B c #041220",
+".C c #2c325c",
+".D c #94b6e4",
+".E c #3e4242",
+".F c #648edc",
+".G c #d4f2fc",
+".H c #cbd3d1",
+".I c #3c54a1",
+".J c #243244",
+".K c #4c69aa",
+".L c #7c8ba2",
+".M c #4c5d84",
+".N c #34497f",
+".O c #1c2228",
+".P c #6484c5",
+".Q c #6a7788",
+".R c #9ba09b",
+".S c #2c3634",
+".T c #acb6b4",
+".U c #141517",
+".V c #a0c4e8",
+".W c #515753",
+".X c #5c76cc",
+".Y c #1b2f51",
+".Z c #4472c4",
+".0 c #7c8a88",
+".1 c #5a6262",
+".2 c #a4aba6",
+".3 c #bcc8d5",
+".4 c #7494df",
+".5 c #84b2d4",
+".6 c #6784d9",
+".7 c #acd3e4",
+".8 c #304b72",
+".9 c #2c4c81",
+"#. c #3c5b93",
+"## c #5468bc",
+"#a c #b5bbb0",
+"#b c #1c3765",
+"#c c #444e44",
+"#d c #ecece8",
+"#e c #7ca3dc",
+"#f c #d4deda",
+"#g c #345495",
+"#h c #1c2641",
+"#i c #94a6cc",
+"#j c #243252",
+"#k c #a7acb5",
+"#l c #5c7ab3",
+"#m c #0a152d",
+"#n c #c4def0",
+"#o c #686e84",
+"#p c #a4a19e",
+"#q c #3e3c3a",
+"#r c #84aaee",
+"#s c #040a09",
+"#t c #3c6294",
+"#u c #7c929c",
+"#v c #3c5c9d",
+"#w c #4e6ead",
+"#x c #344458",
+"#y c #446bae",
+"#z c #696b6a",
+"#A c #547cbc",
+"#B c #789ae3",
+"#C c #112a44",
+"#D c #4f504b",
+"#E c #2c3140",
+"#F c #8c8688",
+"#G c #5e5c5c",
+"#H c #8c8c80",
+"#I c #cccccc",
+"#J c #4c6398",
+"#K c #c7cbc4",
+"#L c #5174b8",
+"#M c #3d558e",
+"#N c #2c3c5f",
+"#O c #acbad4",
+"#P c #3f495a",
+"#Q c #354e82",
+"#R c #6a8ac7",
+"#S c #767c84",
+"#T c #30374b",
+"#U c #b1c9e7",
+"#V c #1b315d",
+"#W c #537bcb",
+"#X c #c4bec0",
+"#Y c #243e6a",
+"#Z c #969892",
+"#0 c #7e858e",
+"#1 c #94b3f1",
+"#2 c #c2d4e8",
+"#3 c #141e35",
+"#4 c #acb2ac",
+"#5 c #c4ced0",
+"#6 c #2b4d8e",
+"#7 c #445ca2",
+"#8 c #2c3e6f",
+"#9 c #14243e",
+"a. c #f1fdfa",
+"a# c #8c9abc",
+"aa c #d7f9f9",
+"ab c #5a697e",
+"ac c #c7ebf7",
+"ad c #bceefc",
+"ae c #b4c2b4",
+"af c #889cf0",
+"ag c #d8d6c8",
+"ah c #748598",
+"ai c #b4d2fc",
+"aj c #4c5eb0",
+"ak c #3f4f64",
+"al c #8492bc",
+"am c #161d1e",
+"an c #5d7dcf",
+"ao c #5c86d6",
+"ap c #9cacc8",
+"aq c #6c92e6",
+"ar c #e4ecec",
+"as c #89b7ef",
+"at c #a6d0f8",
+"au c #e4e2e0",
+"av c #8c98a4",
+"aw c #ccdaec",
+"ax c #94bee4",
+"ay c #232b2b",
+"az c #1c2b43",
+"aA c #0c1c33",
+"aB c #99bcf7",
+"aC c #6c72bc",
+"aD c #7c766c",
+"aE c #a4a2b4",
+"aF c #6c7eac",
+"aG c #e4d6dc",
+"aH c #e4fefc",
+"aI c #84aeb4",
+"aJ c #b4b6bf",
+"aK c #345b9b",
+"aL c #bce2ef",
+"aM c #ccc6bc",
+"aN c #82a3ef",
+"aO c #7c7b77",
+"aP c #040c1e",
+"aQ c #6c7e94",
+"aR c #9ca69c",
+"aS c #acbebc",
+"aT c #a2cafa",
+"aU c #545e5f",
+"aV c #5c6a74",
+"aW c #cae6ee",
+"aX c #5c6e7c",
+"aY c #5474c6",
+"aZ c #fcfaf4",
+"a0 c #344672",
+"a1 c #446ec4",
+"a2 c #b4c4d4",
+"a3 c #313231",
+"a4 c #9cb2b4",
+"a5 c #345a8c",
+"a6 c #7496d4",
+"a7 c #0c1a24",
+"a8 c #444a47",
+"a9 c #343e3c",
+"b. c #dce6e4",
+"b# c #a9b2bc",
+"ba c #a6a6a3",
+"bb c #446a9c",
+"bc c #c4f2f8",
+"bd c #445667",
+"be c #727475",
+"bf c #6a7896",
+"bg c #9aa0a7",
+"bh c #9ec4fa",
+"bi c #545a61",
+"bj c #6474e0",
+"bk c #546674",
+"bl c #b8bcbd",
+"bm c #5d7cbf",
+"bn c #515255",
+"bo c #979a9f",
+"bp c #849cd0",
+"bq c #546a8f",
+"br c #d7d8d5",
+"bs c #688ada",
+"bt c #4f6ebe",
+"bu c #343e4c",
+"bv c #dafefc",
+"bw c #acd6fc",
+"bx c #b4b6b0",
+"by c #8c9a94",
+"bz c #203a44",
+"bA c #a4b6c8",
+"bB c #4c6a98",
+"bC c #040214",
+"bD c #5c74be",
+"bE c #4c5c98",
+"bF c #24325c",
+"bG c #8c8c8f",
+"bH c #4464a7",
+"bI c #2c457e",
+"bJ c #5c83c7",
+"bK c #34538a",
+"bL c #b4dff1",
+"bM c #7c92d4",
+"bN c #c4c4c0",
+"bO c #243759",
+"bP c #0c151e",
+"bQ c #9cb2d4",
+"bR c #6c8fd3",
+"bS c #546aab",
+"bT c #848c9f",
+"bU c #242420",
+"bV c #6c83c0",
+"bW c #343935",
+"bX c #848b89",
+"bY c #acaca6",
+"bZ c #c4cad0",
+"b0 c #445c90",
+"b1 c #243865",
+"b2 c #dce0dc",
+"b3 c #747b76",
+"b4 c #8cacee",
+"b5 c #0c0c08",
+"b6 c #446299",
+"b7 c #8493a4",
+/* pixels */
+"................................................................................................................................",
+"..................................bC....bC....bC..bC....bC..bCbCbCbC..bCbC..bC..bC..bC..bCbC..bC..bC....bC....bC................",
+"..#9#C#h#C.p.Y.Y.Y#j.Y.Y.Y#V#V#Vb1bFb1b1#8#Y.a.a#Q#Q.a.N#Q.abI.i.9bI#Q#MbK#M.wb0#M.9.N.N.N.9.abI.a#Y#Yb1b1#b#bb1b1b1#V#V#V#Vaz..",
+"..#h#C.p.p#9.Y.Y#j.AbObO.A.AbO.Ab1#Y#Y#8.a.aa0.N.8.w.w#QbK.w.ibI.9#6#Q#.#Mb0b0#J#MbK#M.NbK.N.9.NbI.N#YbIb1#Y#8#8bOb1bO#j#V#Caz..",
+"..#9.e#h#C.p.p.Y.YbO.A#b#N.a#8#Y#bb1#8#Y.Na0.9.8#Q.w.Mb0#Q#MbK.9bK#g#6.Kb6#J#J#wb0#M#MbKbK#Q#M.9bI.N.N.a.N.a.a.ab1b1#V.Y#V.Y.Y..",
+"..#9#C.p#h.p.p.p.Y#VbO#b.a.ia0.9#Q.N#YbI.a.N.N.N.w#Q.wb6b6b0b6#.#g#v#M.K#w#L.n.n#vbH#.bH.Ib6aK#MbK.9#Q#Q#Q#Q.a#Yb1.AbF#VbO.Y#j..",
+"..#h#h.p.p.p.Y.p#bbF#bb1#Y.a.8.N#Q#M#M#Q.N.9#QbK#M#Mb0b0.ubB.K.K#..K#v#w.nbmbV.nbHbS#w#7#w#vb0#.#M#Mb0#M#Q.9#Y#Yb1#Yb1b1.Y.Y.Y..",
+"..#h#9.p.p.p#V#V#b#b#Y#Y.a.ibI.N.w#Mb0b6#7#M#Q#QbK#.b6b6bq#l.n#LbHbH#y#L#R.s.4#AaY#w#w#L.K.KbH.g.KbH#v#M.9bI.i.8.a#Yb1.A.A.A#j..",
+"..#h#C.p.p.Y#V#V#bb1.abIbI#6.o.o#g.oaK#tbH.K.KbH#M.Iaj.K#w.n#R.P#Rbt#W#W.4bpb4aoanbsaobm#La1#L#A#L.ga5bK#g#g#Q.8#Y#bb1b1bOb1bO..",
+"...p.p.Y#V.Y#V.Ab1#YbI.9#Q#Q#M#M#7#7#M#v.M#J.K.K.nbS#MbH.nbm.#b4.s#Baq#Wb4aB#1aqaq#R.P.##l#RbmbD.K#7#J#J#.#Q.9.i.N.a#Y#Yb1.Aaz..",
+"..az#C#V#j#V.A#N#8.N.N.ibObz#T.J#E.J#T#Tbu.Y.8#..K.nbVbD#wbm.4a6aTb4aoaNaTaiasaNa6.n.m.3bZ#2bN.3aR#2#2.3#J#Q#MbK.8.a#8#b.AbO#j..",
+"..#h.p.p.Y.Yb1bO.ibI#g#Mbd#hambU.jbW.Sa3aybP.Y.9bHbH.ubm#BbM.P#rbhbc.qasbL.G.VbhaBbpbZaJbobxbl#I#a#abXbP#V.9#6.NbI#8#8#bbF#V#j..",
+"..az#C.Y.Y.Y#bb1.abI#Q.oaj#Pa3a3aya3a3bW.Eayb0.K.g#y.K#LanbRbhaTaxbLbvbLbvbvaLadaTai.mbobYba#Xbl.H#I#P#m#.#M#QbIbI#Y#Yb1#b#V#j..",
+"..az.p.p#VbObO#Y.a.N#g#g.I#xbW.j.ja3.E.Ebnbib0bmananbm#wanbs.4asacbLbvaHa.aHbvbc.7aIbY#p#pblbl#Kbe#F#k#9#..I#g#6.i#8#8b1b1.A#j..",
+"..#h#C.p.YbO#bb1a0bIbKbK#7#xaya3.jaya3#q.Wbn.J.wbD#Lbm.X#Bb4bhat.b#na.a.a.aZaHaHaW#k#a.vagbNaObl#I.vb3#3#w.K#7#v#M#QbIa0#Y#N#N..",
+"..#haz.p#V.YbO#Y#Y.N.9#g#7#P.EbUa8#q#D.f.f.fbi#hbB#LaY.n.P#R#e.5.7aLa.a.aZaZa.a.aS#5#p.d#p.t.l.HbYaObo.Y#w.Kb6#.#M.Na0.a#8#NbO..",
+"..#h#C.YbO#V#N#Y.8#Q#g#t##ak.j.W.f.Wbn#Gbe#zbnaU.M#Ra6#eaNb4bh.7bLaWa.aZaZaZa.br.H.2ba.H.T#fau.H.H#p.x#3#w.K#tb0#Q#Q.a#8#Nb1bO..",
+"..az#j#j.Ab1#N.a.8#Q#.bb##ak.Ebnbn.1.Ua8.zaO#z.xbubqbsbR.saqaN#1bw.7aaaHa.b.a.a4bZ#k#dbgbP.H#IbG#4bY#o#9#w.K#7b0#Q.8.a#8#NbObO..",
+"..az#j.Y.YbO#8.a.8#Q#7#t##bd.r#D#D.rbPaV#G#z.x.y#z.p.u#W.6#B#r#eaTaTaLaWaaaI#5#aau#XbraU#8.HbN.T.RbY#0#9#w.Kb6#M#Q#Qa0#Y#Y#N#N..",
+"..#h#j.YbOb1bO#Ya0.NbKa5aj.c.f#G#z.1#3.Mbe#zaO.x#pbT#.bmbsbs.F#1#easat.Gbc.hb.b2aragbgbPaC.3#k.v#4babe#9.KbH#7b0#Qak.a.i#N#Y#T..",
+"..az.Y#j.Y.Ab1#Y.8.N#gbK.IaX.r.raDaV.Bb0bfbeb3bab3#HazbBaYbsaqbRaf#1.DaB#na2#K#4b3.ybC.Yaf#k#Z.y.d#p#S#3#v#7#M#g.N.N.a#N#Y#NbO..",
+"..#h.p#C#jbFbO#8.a.NbK#.#7bk.z.zb3#H#9aKbm#J.y#Hbablb#.e.PaqbmbsaNaN#1aB#2bZ.x.2aub3.AbSbjapbobobo.rbn#9#v#gbK.9bI.a.a#Yb1bObO..",
+"..#haz.YbF#VbO#Y.abI#QaK.I.Q.z.WaO#za7b0an.ub#.R.y.R#XbXbEbtbJbR#Bbsb4.D.3.v#p#za3#s.ubJbj#u.WbWb3.Rbe#9#v#v#g.9bI#Yb1b1#b.A#j..",
+"..#h#C.p#C.Y#bbO#YbI.9.o.Iab#Zb3.x.da7bK#WbmalbTae.t#F#Gaz.nbsaqbJ.6#R#U#aaMbx#KbPbz#laoanb#ba.2.RbG#G#9#v#v#g.9bI.ab1#bbF#Vaz..",
+"..#haz.p.p#V#Vb1#Y.a#6bK#7bk.1#z#Z.y#m#.a1a1bq.LbX#HblbN.3#N.PaobJafbQ.3.tblbx.TazbB.X.kaYb7bG.d.x#ZaV#3bH#v#Q.NbI#8b1b1.A.Y.Y..",
+"..az#h#C.p#VbO#b#YbIbK#g#7aQ.d.y.RbX#mbK#y#ybt.#bZ#IaM.l.2bdbmanaobMap.t.2bY.2.ObO.s.X#W.6bX#F.yaOaD#G#9b6#7.I#Q.a.ab1#bbF.Y.Y..",
+"..#9#h.p.p#V#Vb1.a.NbK#..IaQ.xbob3aO#m.9#L.ZaY#w#iaJagaGbr#5.8aF.4a#blbN#Z#Z.WaP#l#l.6#WaY#0aO.y.xb3#PaA#7b6bK#QbI#8b1bO.A#V.Y..",
+"..#h.p#C#V.YbO#Y.abI.9aK.Ibf#D.1bYbY#mbK#ybt#ybHbSbT#aba.tbx#S.M#B.y#kbxbYbYaP.YbR#A.6bmbt.Lb3#z.W#Dbn#3bK#.#M#Q.N#Yb1b1#V.Yaz..",
+"..#h#C.p#V.p#b.A.a#Y#Q#..Ib7#kbe#4#pa7bK#ybH.g.gbHbfbZbN#4bNbgakah#Zbg#F.x.1#9bK.P#A.X.#btbTaO.W.r.ra8.e#Q.o#Q#Q.a.ab1bO.A.Yaz..",
+"..#h.p#h#C#VbOb1#YbI.9.o.I.L#H#Z.2.vaA#QbHaK.g.g#y#7#nbr#a.H.vaE.zaU#4blbebCbIaK#Lbm#LbJbtaXaO.z#z#G.EaA#g#Q.9bI.a.a#Nb1#jbO.Y..",
+"..#h#C#h#V.p#V.A.a#8.9.9.Iah#4bY#4bGbP#QaKaKaKaK#7#wbEbg.z.zay.E#a#K.2#ZbCbO#v#gbH.Xbb.ubDbk#z.r#c.f.E#9#Q#6bI.i#8b1#YbO.AbO.J..",
+"..#h.p#9.p.p#b.A#8#Y.9.9.I.0.R.2bN#XbP.NaK.IaK#v.IbS.KaQaR.Wbl#K.RbY.R.y#9#M#gaKbH.Kbb#yaCbk.r#Ga8#D#TaAbK#6.i.a#Y#bbObO.Y#jaz..",
+"..#9#9.p.p.Y#V.Ab1#YbI.9#7a#bn.Hb2#FaP.a.I#g#g#g#v#7bHb0.L.HbY.y.0#ZaObC.8b0#g#6aKbH#wbb#LaX#D#q.Ea3.UaAbK#QbI#Y#Y#bbO.AbO.Y.Y..",
+"..#9#h#h#C.p.Y#V#Y#Y#6.obEbk.H.2bUbe#m.a#g#g#Q#M#M#vaK#6bq#k.d.x.y#Z..az#M#v.o#6.o#v#L#tbSbda8bU.Ub5.O#3#6#6bI.ib1#bbF.Y#C.Yaz..",
+"..#9#9.p.p.p#Vb1#Y.N#6.o#Q#O.R.xaM.HaPa0bK#Q#Q#M#M#MbK#gb0akb3aO.xbX#9#x#v#g.N#6.9.wbH#yb0bn#D.f#q.j.U#3.N#6#8.i#b#b.Y.p.Y.paz..",
+"..#9#h#9.p.p#V#bb1#8bI#g.NbAb.br.t#H#m#Y#Q#g#Q.9.9.N#6.o#gb0avbG#Z...Y.w#g#6bIbIbIbK#v.K#Ma7#s#s....#haA#Q.NbI#Yb1#V#V#V.p.paz..",
+"..#9#9#9.p.p#VbO#Y#8#6.i#M.Q#z.H#f#K.B#Y#6.9.N.9bIbI.9.9#M#M#JbybP.B.Nb0.NbIbI#Y.ibI#vbH.wbubW.E.Sa3a7#m.o#Q#Y#Yb1#V#V#C.p.p.e..",
+"..#3#9#9#9.Y#V#VbF#Y#8#6ak#O#db2br.HaP#N.N#QbIbI.a#Y.i.8#M#Qa0.L.B.p#Q#Q.i.i.i#Y.ibI#Q#..c.E.ja3a3bWambP.N.9#Y#Y#b#b#V.p.p.p#9..",
+"..#3.e#9.p.p.Y.Yb1b1#Y#.#Ubgbl.T#S..aw#obI.a.a#8#Y#Y.a#YbI.Na0.8bO#8a0#Qa0#8b1#Y#Y#8#Q.ibO#Ta9a9bWa3ay#Eb1.a.ab1#V#V.Y.p.p.e#9..",
+"..#3#9.p#h#C.p.Y#Vb1#b#V.a.Y.Y.Y#CazbO.eb1#8#Y#b#bb1b1#8bI#Y.8.abIb1#Y.Nb1#Y#Y#Y#b#Y.9.8.8.C.JbO#j.Yaz#C.p.Y#bb1#V.p.p.p#C.e#9..",
+"..#9#9#9.p#9.p.Y.Y#V#b#bb1#8.i#8.a.a#Y#Y#Y#Yb1b1#b#bb1#N#Y#8b1#Y#Yb1#8#Yb1#b#b#b#bb1#Y.N.w.8.N.8#Q.8.i.a#b#Y#bbO#V.Y.p#C.p.p#9..",
+"..#3#9.e#9.p.p#9#C.Y#V#b#b#b#Y#Y#Y#Y#Y#Yb1b1bO#V.Y#j#Vb1b1bObObObO.Ab1#N.A.AbF#V#V#V#b#8.aa0.a.ibI.8#Y#Yb1#V#V#V#V.p.p#9.p.e#9..",
+"..#3#3#9.e.e.p.p.p.p#V.Y#b#b#Vb1#b#Yb1.A#V.Y.Y.Y.Y.Y.A#j.YbO#VbO.Y#jbO#b#j#j#V.Y#V#V#bb1#Y.a#Yb1.a#8b1b1#b.A#V#C.p.p.p.p.e.e#9..",
+"..#3aAaA#3#9.e.e#9#C#C.Y.p.Y#V#VbF#VbO.Y#j.p.p.Y#C#j.Y#j.Y#j.Y#j.Y.YbO.Y#j.Y.p.p.p.p.Y#VbOb1#NbObOb1b1.A#V.p.p.p#C.p#9#9#9.e#9..",
+"..#3#9.e#3aA#9.e#9.p.p.e.p.p.p#V#j.Y.Y.Y#9.p.p#9.Yaz.Yaz.paz.Y.paz.Y.Y#j#C.p#C.p#C#C.p#V#VbO#VbF#V#j#V#j.p.p.p#C.p#9#C#C#9.e#9..",
+"..#3aA#9aA#9aA.e#9.e#9#9.p.p.p.p#Caz.Y#C.p.p#9.p#C#Caz.p#Caz.Y#C.p#9#j.p#h.p#C#C#C.e.p#9.Y#j.Y.Y.p.p.p#C.p.p#9#9#9#9#9.e#9.e#3..",
+"..#3.e#3.e#3.e#9#9aA#9.e.e.e.p#C.p#h#Caz#9.p.p.p#h.Y#9.p.p#C.paz.p#h.Yaz#9.p#C.e.e.e.p.p#9.p.paz#C.paz.Y#9.p.e#9.e#9#9#9#9aA#9..",
+"......bC..bC..bCbCbCbCbCbCbC..bC....bC..bCbCbCbCbC..bC....bC......bC..bCbCbCbCbCbCbCbCbCbCbC....bC......bCbC..bC..bC..bC........"
+};
diff --git a/samples/richedit/Mpch.h b/samples/richedit/Mpch.h
new file mode 100644 (file)
index 0000000..863f2eb
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+  This is an empty Mpch.h file to allow me to move the
+  wxl* files between Mahogany and the wxLayout sample
+  without modifying them.
+*/
+
+// static int _mpch_dummy = 0;
+
diff --git a/samples/richedit/README b/samples/richedit/README
new file mode 100644 (file)
index 0000000..5539268
--- /dev/null
@@ -0,0 +1,50 @@
+
+README for wxLayout classes
+---------------------------
+
+All the source in this directory is copyrighted under the
+GPL (GNU GENERAL PUBLIC LICENSE), version 2,
+by Karsten Ballueder <ballueder@usa.net>.
+
+
+This is still work in progress, so if you want to make any significant
+changes, please get in touch with me before.
+
+There are three building blocks for rich text editing:
+
+wxllist :
+
+The wxLayoutList layout engine. It is a linked list of wxLayoutObjects
+which can arrange and display them on any wxDC. I am trying to keep
+this class as simple as possible, to be just the core layout
+engine. All "convenience" functions should be defined in classes built 
+on top of this.
+The wxLayoutList is derived from kbList, a double-linked list with an
+interface modelled after the STL list. As wxLayoutList depends on the
+way kbList treats iterators (i.e. the iterator value after an insert() 
+or erase() operation), I don't feel like rewriting it for wxList.
+
+wxlwindow :
+
+Contains a class wxLayoutWindow, derived from wxScrolledWindow which
+can directly be used as a rich-text display or editing window. The
+function responsible for keyboard handling is virtual and can be
+overloaded for different keybindings. wxLayoutWindow can sent fake
+menu-events to the application to react to the user clicking on
+objects.
+
+wxlparser:
+
+Contains several high level functions operating on
+wxLayoutList. Currently implemented is inserting of text (including
+linebreaks) and export of objects, text or html.
+Planned for the future is an html parser for importing html.
+
+
+wxLayout.cpp is a simple test program. It will export Text and HTML to
+stdout and demonstrate some of the features and bugs of wxLayoutList.
+
+There are still things to do and I'm working on them. :-)
+
+Karsten Ballueder <Ballueder@usa.ne>          29 June 1998
+
diff --git a/samples/richedit/TODO b/samples/richedit/TODO
new file mode 100644 (file)
index 0000000..a387962
--- /dev/null
@@ -0,0 +1,44 @@
+
+BUGS
+=====================================================================
+
+- dmalloc shows duplicate deletion after merging two lines and
+  deleting the second half
+
+- word wrap for objects with lots of non-space needs to search in positive
+  direction if begin of first object is reached
+
+TODO
+=====================================================================
+
+
+- typedef wxCoords CoordType ??
+
+- merge RecalulateXXX and Layout() into one
+- remove UpdateCursorScreenCoords() which is no longer needed
+
+  - UNDO!!
+  - replacement of llist in window
+  - selection highlighting is a bit broken
+Improve speed! (See layout problem below!)
+
+  - wxlwindow needs to shrink scrollbar range when window contents get removed
+  - When selecting with the mouse, scroll window if pointer is outside.
+
+
+
+- The import of a private data object does not work yet, we need to get
+  the objects back from the string.
+- Changing default settings in Clear() or changing/inserting/deleting
+  a wxLayoutObject needs to update the m_StyleInfo in all lines, only
+  then can we start using that one.
+  
+- update rectangle (needs support in wxllist and wxWindows)
+  --> needs a bit of fixing still
+      some code bits are commented out in wxlwindow.cpp
+      offset handling seems a bit dodgy, white shadow to top/left of cursor
+
+  - DragNDrop
+
+  - Update docs, do full rtf/html editing. 
+  - Verify html export.
diff --git a/samples/richedit/kbList.cpp b/samples/richedit/kbList.cpp
new file mode 100644 (file)
index 0000000..a5798fc
--- /dev/null
@@ -0,0 +1,339 @@
+/*-*- c++ -*-********************************************************
+ * kbList.cc : a double linked list                                 *
+ *                                                                  *
+ * (C) 1998 by Karsten Ballüder (Ballueder@usa.net)                 *
+ *                                                                  *
+ * $Id$          *
+ *                                                                  *
+ * $Log$
+ * Revision 1.1  1999/06/07 09:57:12  KB
+ * Formerly known as wxLayout.
+ *
+ * Revision 1.3  1998/11/19 20:34:50  KB
+ * fixes
+ *
+ * Revision 1.8  1998/09/23 08:57:27  KB
+ * changed deletion behaviour
+ *
+ * Revision 1.7  1998/08/16 21:21:29  VZ
+ *
+ * 1) fixed config file bug: it was never created (attempt to create ~/.M/config
+ *    always failed, must mkdir("~/.M") first)
+ * 2) "redesign" of "Folder properties" dialog and bug corrected, small change to
+ *    MInputBox (it was too wide)
+ * 3) bug in ProvFC when it didn't reckognize the books as being in the correct
+ *    format (=> messages "can't reopen book") corrected
+ * 4) I tried to enhance MDialog_About(), but it didn't really work... oh well,
+ *    I've never said I was an artist
+ *
+ * Revision 1.6  1998/07/08 11:56:56  KB
+ * M compiles and runs on Solaris 2.5/gcc 2.8/c-client gso
+ *
+ * Revision 1.5  1998/06/27 20:07:18  KB
+ * several bug fixes for kbList
+ * started adding my layout stuff
+ *
+ * Revision 1.1.1.1  1998/06/13 21:51:12  karsten
+ * initial code
+ *
+ * Revision 1.4  1998/05/24 14:48:00  KB
+ * lots of progress on Python, but cannot call functions yet
+ * kbList fixes again?
+ *
+ * Revision 1.3  1998/05/18 17:48:34  KB
+ * more list<>->kbList changes, fixes for wxXt, improved makefiles
+ *
+ * Revision 1.2  1998/05/14 16:39:31  VZ
+ *
+ * fixed SIGSEGV in ~kbList if the list is empty
+ *
+ * Revision 1.1  1998/05/13 19:02:11  KB
+ * added kbList, adapted MimeTypes for it, more python, new icons
+ *
+ *******************************************************************/
+
+#ifdef __GNUG__
+#   pragma implementation "kbList.h"
+#endif
+
+#include   "kbList.h"
+
+
+kbListNode::kbListNode( void *ielement,
+                        kbListNode *iprev,
+                        kbListNode *inext)
+{
+   next = inext;
+   prev = iprev;
+   if(prev)
+      prev->next = this;
+   if(next)
+      next->prev = this;
+   element = ielement;
+}
+
+kbListNode::~kbListNode()
+{
+   if(prev)
+      prev->next = next;
+   if(next)
+      next->prev = prev;
+}
+
+
+kbList::iterator::iterator(kbListNode *n)
+{
+   node = n;
+}
+
+void *
+kbList::iterator::operator*() 
+{
+   return node->element;
+}
+
+kbList::iterator &
+kbList::iterator::operator++()
+{
+   node  = node ? node->next : NULL;
+   return *this;
+}
+
+kbList::iterator &
+kbList::iterator::operator--()
+{
+   node = node ? node->prev : NULL; 
+   return *this;
+}
+kbList::iterator &
+kbList::iterator::operator++(int /* foo */)
+{
+   return operator++();
+}
+
+kbList::iterator &
+kbList::iterator::operator--(int /* bar */)
+{
+   return operator--();
+}
+
+
+bool
+kbList::iterator::operator !=(kbList::iterator const & i) const
+{
+   return node != i.node;
+}
+
+bool
+kbList::iterator::operator ==(kbList::iterator const & i) const
+{
+   return node == i.node;
+}
+
+kbList::kbList(bool ownsEntriesFlag)
+{
+   first = NULL;
+   last = NULL;
+   ownsEntries = ownsEntriesFlag;
+}
+
+void
+kbList::push_back(void *element)
+{
+   if(! first) // special case of empty list
+   {
+      first = new kbListNode(element);
+      last = first;
+      return;
+   }
+   else
+      last = new kbListNode(element, last);
+}
+
+void
+kbList::push_front(void *element)
+{
+   if(! first) // special case of empty list
+   {
+      push_back(element);
+      return;
+   }
+   else
+      first = new kbListNode(element, NULL, first);
+}
+
+void *
+kbList::pop_back(void)
+{
+   iterator i;
+   void *data;
+   bool ownsFlagBak = ownsEntries;
+   i = tail();
+   data = *i;
+   ownsEntries = false;
+   erase(i);
+   ownsEntries = ownsFlagBak;
+   return data;
+}
+
+void *
+kbList::pop_front(void)
+{
+   iterator i;
+   void *data;
+   bool ownsFlagBak = ownsEntries;
+   
+   i = begin();
+   data = *i;
+   ownsEntries = false;
+   erase(i);
+   ownsEntries = ownsFlagBak;
+   return data;
+   
+}
+
+void
+kbList::insert(kbList::iterator & i, void *element)
+{   
+   if(! i.Node())
+      return;
+   else if(i.Node() == first)
+   {
+      push_front(element);
+      i = first;
+      return;
+   }
+   i = kbList::iterator(new kbListNode(element, i.Node()->prev, i.Node()));
+}
+
+void
+kbList::doErase(kbList::iterator & i)
+{
+   kbListNode
+      *node = i.Node(),
+      *prev, *next;
+   
+   if(! node) // illegal iterator
+      return;
+
+   prev = node->prev;
+   next = node->next;
+   
+   // correct first/last:
+   if(node == first)
+      first = node->next;
+   if(node == last)  // don't put else here!
+      last = node->prev;
+
+   // build new links:
+   if(prev)
+      prev->next = next;
+   if(next)
+      next->prev = prev;
+
+   // delete this node and contents:
+   // now done separately
+   //if(ownsEntries)
+   //delete *i;
+   delete i.Node();
+
+   // change the iterator to next element:
+   i = kbList::iterator(next);
+}
+
+kbList::~kbList()
+{
+   kbListNode *next;
+
+   while ( first != NULL )
+   {
+      next = first->next;
+      if(ownsEntries)
+         delete first->element;
+      delete first;
+      first = next;
+   }
+}
+
+kbList::iterator
+kbList::begin(void) const
+{
+   return kbList::iterator(first);
+}
+
+kbList::iterator
+kbList::tail(void) const
+{
+   return kbList::iterator(last);
+}
+
+kbList::iterator
+kbList::end(void) const
+{
+   return kbList::iterator(NULL); // the one after the last
+}
+
+unsigned
+kbList::size(void) const // inefficient
+{
+   unsigned count = 0;
+   kbList::iterator i;
+   for(i = begin(); i != end(); i++, count++)
+      ;
+   return count;
+}
+
+
+
+
+
+
+
+#ifdef   KBLIST_TEST
+
+#include   <iostream.h>
+
+KBLIST_DEFINE(kbListInt,int);
+   
+int main(void)
+{
+   int
+      n, *ptr;
+   kbListInt
+      l;
+   kbListInt::iterator
+      i;
+   
+   for(n = 0; n < 10; n++)
+   {
+      ptr = new int;
+      *ptr = n*n;
+      l.push_back(ptr);
+   }
+
+   i = l.begin(); // first element
+   i++; // 2nd
+   i++; // 3rd
+   i++; // 4th, insert here:
+   ptr = new int;
+   *ptr = 4444;
+   l.insert(i,ptr);
+
+   // this cannot work, because l.end() returns NULL:
+   i = l.end(); // behind last
+   i--;  // still behind last
+   l.erase(i);  // doesn't do anything
+
+   // this works:
+   i = l.tail(); // last element
+   i--;
+   --i;
+   l.erase(i); // erase 3rd last element (49)
+   
+   for(i = l.begin(); i != l.end(); i++)
+      cout << *i << '\t' << *((int *)*i) << endl;
+
+   
+   return 0;
+}
+#endif
diff --git a/samples/richedit/kbList.h b/samples/richedit/kbList.h
new file mode 100644 (file)
index 0000000..8c52aba
--- /dev/null
@@ -0,0 +1,315 @@
+/*-*- c++ -*-********************************************************
+ * kbList.h : a double linked list                                  *
+ *                                                                  *
+ * (C) 1998 by Karsten Ballüder (Ballueder@usa.net)                 *
+ *                                                                  *
+ * $Id$
+ *
+ *******************************************************************/
+
+#ifndef   KBLIST_H
+#   define   KBLIST_H
+
+#ifdef __GNUG__
+#   pragma interface "kbList.h"
+#endif
+
+#ifndef   NULL
+#   define   NULL   0
+#endif
+
+/**@name Double linked list implementation. */
+//@{
+
+/** kbListNode is a class used by kbList. It represents a single
+    element in the list. It is not intended for general use outside
+    kbList functions.
+*/
+struct kbListNode
+{
+   /// pointer to next node or NULL
+   struct kbListNode *next;
+   /// pointer to previous node or NULL
+   struct kbListNode *prev;
+   /// pointer to the actual data
+   void *element;
+   /** Constructor - it automatically links the node into the list, if
+       the iprev, inext parameters are given.
+       @param ielement pointer to the data for this node (i.e. the data itself)
+       @param iprev if not NULL, use this as previous element in list
+       @param inext if not NULL, use this as next element in list
+   */
+   kbListNode( void *ielement,
+               kbListNode *iprev = NULL,
+               kbListNode *inext = NULL);
+   /// Destructor.
+   ~kbListNode();
+};
+
+/** The main list class, handling void pointers as data.
+  */
+
+class kbList
+{
+public:
+   /// An iterator class for kbList, just like for the STL classes.
+   class iterator
+   {
+   protected:
+      /// the node to which this iterator points
+      kbListNode *node;
+      friend class kbList;
+         public:
+      /** Constructor.
+          @param n if not NULL, the node to which to point
+      */
+      iterator(kbListNode *n = NULL);
+      /** Dereference operator.
+          @return the data pointer of the node belonging to this
+          iterator
+      */
+      void * operator*();
+
+      /** This operator allows us to write if(i). It is <em>not</em> a 
+          dereference operator and the result is always useless apart
+          from its logical value!
+      */
+      operator void*() const { return node == NULL ? (void*)0 : (void*)(-1); }
+      
+      /** Increment operator - prefix, goes to next node in list.
+          @return itself
+      */
+      iterator & operator++();
+
+      /** Decrement operator - prefix, goes to previous node in list.
+          @return itself
+      */
+      iterator & operator--();
+
+      /** Increment operator - prefix, goes to next node in list.
+          @return itself
+      */
+      iterator & operator++(int); //postfix
+
+      /** Decrement operator - prefix, goes to previous node in list.
+          @return itself
+      */
+      iterator & operator--(int); //postfix
+
+      /** Comparison operator.
+          @return true if not equal.
+      */
+      bool operator !=(iterator const &) const;
+
+      /* Comparison operator.
+         @return true if equal
+      */
+      bool operator ==(iterator const &) const;
+
+      /** Returns a pointer to the node associated with this iterator.
+          This function is not for general use and should be
+          protected. However, if protected, it cannot be called from
+          derived classes' iterators. (Is this a bug in gcc/egcs?)
+          @return the node pointer
+      */
+      inline kbListNode * Node(void) const
+         { return node; }
+   };
+
+   /** Constructor.
+       @param ownsEntriesFlag if true, the list owns the entries and
+       will issue a delete on each of them when deleting them. If
+       false, the entries themselves will not get deleted. Do not use
+       this with array types!
+   */
+   kbList(bool ownsEntriesFlag = true);
+
+   /** Destructor.
+       If entries are owned, they will all get deleted from here.
+   */
+   ~kbList();
+
+   /** Tell list whether it owns objects. If owned, they can be
+       deleted by list. See the constructor for more details.
+       @param ownsflag if true, list will own entries
+   */
+   void ownsObjects(bool ownsflag = true)
+      { ownsEntries = ownsflag; }
+
+   /** Query whether list owns entries.
+       @return true if list owns entries
+   */
+   bool ownsObjects(void)
+      { return ownsEntries; }
+
+   /** Add an entry at the end of the list.
+       @param element pointer to data
+   */
+   void push_back(void *element);
+
+   /** Add an entry at the head of the list.
+       @param element pointer to data
+   */
+   void push_front(void *element);
+
+   /** Get element from end of the list and delete it.
+       NOTE: In this case the element's data will not get deleted by
+       the list. It is the responsibility of the caller to free it.
+       @return the element data
+   */
+   void *pop_back(void);
+
+   /** Get element from head of the list and delete it.
+       NOTE: In this case the element's data will not get deleted by
+       the list. It is the responsibility of the caller to free it.
+       @return the element data
+   */
+   void *pop_front(void);
+
+   /** Insert an element into the list.
+       @param i an iterator pointing to the element, before which the new one should be inserted
+       @param element the element data
+   */
+   void insert(iterator & i, void *element);
+
+   /** Remove an element from the list _without_ deleting the object.
+       @param  i iterator pointing to the element to be deleted
+       @return the value of the element just removed
+   */
+   void *remove(iterator& i) { void *p = *i; doErase(i); return p; }
+
+   /** Erase an element, move iterator to following element.
+       @param i iterator pointing to the element to be deleted
+   */
+   void erase(iterator & i) { deleteContent(i); doErase(i); }
+
+   /* Get head of list.
+      @return iterator pointing to head of list
+   */
+   iterator begin(void) const;
+
+   /* Get end of list.
+   @return iterator pointing after the end of the list. This is an
+   invalid iterator which cannot be dereferenced or decremented. It is
+   only of use in comparisons. NOTE: this is different from STL!
+   @see tail
+   */
+   iterator end(void) const;
+
+   /* Get last element in list.
+      @return iterator pointing to the last element in the list.
+      @see end
+   */
+   iterator tail(void) const;
+
+   /* Get the number of elements in the list.
+      @return number of elements in the list
+   */
+   unsigned size(void) const;
+
+   /* Query whether list is empty.
+      @return true if list is empty
+   */
+   inline bool empty(void) const
+      { return first == NULL ; }
+
+protected:
+   /// if true, list owns entries
+   bool        ownsEntries;
+   /// pointer to first element in list
+   kbListNode *first;
+   /// pointer to last element in list
+   kbListNode *last;
+protected:
+   /** Erase an element, move iterator to following element.
+       @param i iterator pointing to the element to be deleted
+   */
+   void doErase(iterator & i);
+
+   /** Deletes the actual content if ownsflag is set.
+       param iterator i
+   */
+   inline void deleteContent(iterator i)
+      { if(ownsEntries) delete *i; }
+
+
+private:
+   /// forbid copy construction
+   kbList(kbList const &foo);
+   /// forbid assignments
+   kbList& operator=(const kbList& foo);
+};
+
+/// just for backward compatibility, will be removed soon
+typedef kbList::iterator kbListIterator;
+/// cast an iterator to a pointer, compatibility only to be removed
+#define   kbListICast(type, iterator)   ((type *)*iterator)
+/// cast an iterator to a const pointer, compatibility only to be removed
+#define   kbListIcCast(type, iterator)   ((type const *)*iterator)
+
+/** Macro to define a kbList with a given name, having elements of
+    pointer to the given type. I.e. KBLIST_DEFINE(Int,int) would
+    create a kbListInt type holding int pointers.
+*/
+#define   KBLIST_DEFINE(name,type)   \
+class name : public kbList \
+{ \
+public: \
+   class iterator : public kbList::iterator \
+   { \
+   protected: \
+      inline iterator(kbList::iterator const & i) \
+         { node = i.Node(); } \
+      friend class name; \
+   public: \
+      inline iterator(kbListNode *n = NULL) \
+         : kbList::iterator(n) {} \
+      inline type * operator*() \
+         /* the cast is needed for MS VC++ 5.0 */ \
+         { return (type *)((kbList::iterator *)this)->operator*() ; } \
+   }; \
+   inline name(bool ownsEntriesFlag = TRUE) \
+      : kbList(ownsEntriesFlag) {} \
+   \
+   inline type *pop_back(void) \
+      { return (type *) kbList::pop_back(); } \
+   \
+   inline type *pop_front(void) \
+      { return (type *) kbList::pop_front(); } \
+   \
+   type *remove(iterator& i) \
+      { return (type *)kbList::remove(i); } \
+   inline void erase(iterator & i) \
+      { deleteContent(i); doErase(i); } \
+   \
+   inline iterator begin(void) const \
+      { return kbList::begin(); } \
+   \
+   inline iterator end(void) const \
+      { return kbList::end(); } \
+   \
+   inline iterator tail(void) const \
+      { return kbList::tail(); } \
+   ~name() \
+   { \
+      kbListNode *next; \
+      while ( first != NULL ) \
+      { \
+         next = first->next; \
+         if(ownsEntries) \
+            delete (type *)first->element; \
+         delete first; \
+         first = next; \
+      } \
+   } \
+protected: \
+   inline void deleteContent(iterator i) \
+      { if(ownsEntries) delete *i; } \
+}
+
+#ifdef   MCONFIG_H
+/// define the most commonly used list type once:
+KBLIST_DEFINE(kbStringList, String);
+#endif
+//@}
+#endif // KBLIST_H
diff --git a/samples/richedit/wxLayout.cpp b/samples/richedit/wxLayout.cpp
new file mode 100644 (file)
index 0000000..b4cd050
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ * Program: wxLayout
+ *
+ * Author: Karsten Ballüder
+ *
+ * Copyright: (C) 1998, Karsten Ballüder <Ballueder@usa.net>
+ *
+ */
+
+#ifdef __GNUG__
+#pragma implementation "wxLayout.h"
+#endif
+
+#include "wx/wxprec.h"
+#ifdef __BORLANDC__
+#  pragma hdrstop
+#endif
+
+#include "wxLayout.h"
+#include "wx/textfile.h"
+
+
+#include   "Micon.xpm"
+
+
+//-----------------------------------------------------------------------------
+// main program
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_APP(MyApp)
+
+//-----------------------------------------------------------------------------
+// MyFrame
+//-----------------------------------------------------------------------------
+
+   enum ids{ ID_ADD_SAMPLE = 1, ID_CLEAR, ID_PRINT,
+             ID_PRINT_SETUP, ID_PAGE_SETUP, ID_PREVIEW, ID_PRINT_PS,
+             ID_PRINT_SETUP_PS, ID_PAGE_SETUP_PS,ID_PREVIEW_PS,
+             ID_WRAP, ID_NOWRAP, ID_PASTE, ID_COPY, ID_CUT, ID_FIND,
+             ID_WXLAYOUT_DEBUG, ID_QUIT, ID_CLICK, ID_HTML, ID_TEXT,
+             ID_TEST, ID_LINEBREAKS_TEST, ID_LONG_TEST, ID_URL_TEST };
+
+
+IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
+
+   BEGIN_EVENT_TABLE(MyFrame,wxFrame)
+   EVT_MENU(ID_PRINT, MyFrame::OnPrint)
+   EVT_MENU(ID_PREVIEW, MyFrame::OnPrintPreview)
+   EVT_MENU(ID_PRINT_SETUP, MyFrame::OnPrintSetup)
+   EVT_MENU(ID_PAGE_SETUP, MyFrame::OnPageSetup)
+   EVT_MENU(ID_PRINT_PS, MyFrame::OnPrintPS)
+   EVT_MENU(ID_PREVIEW_PS, MyFrame::OnPrintPreviewPS)
+   EVT_MENU(ID_PRINT_SETUP_PS, MyFrame::OnPrintSetupPS)
+   EVT_MENU(ID_PAGE_SETUP_PS, MyFrame::OnPageSetupPS)
+   EVT_MENU    (-1,       MyFrame::OnCommand)
+   EVT_COMMAND (-1,-1,    MyFrame::OnCommand)
+   EVT_CHAR    (  wxLayoutWindow::OnChar  )
+   END_EVENT_TABLE()
+
+
+MyFrame::MyFrame(void) :
+   wxFrame( (wxFrame *) NULL, -1, "wxLayout",
+             wxPoint(880,100), wxSize(256,256) )
+{
+   CreateStatusBar( 2 );
+
+   SetStatusText( "wxLayout by Karsten Ballüder." );
+
+   wxMenuBar *menu_bar = new wxMenuBar();
+
+   wxMenu *file_menu = new wxMenu;
+   file_menu->Append(ID_PRINT, "&Print...", "Print");
+   file_menu->Append(ID_PRINT_SETUP, "Print &Setup...","Setup printer properties");
+   file_menu->Append(ID_PAGE_SETUP, "Page Set&up...", "Page setup");
+   file_menu->Append(ID_PREVIEW, "Print Pre&view", "Preview");
+#ifdef __WXMSW__
+   file_menu->AppendSeparator();
+   file_menu->Append(ID_PRINT_PS, "Print PostScript...", "Print (PostScript)");
+   file_menu->Append(ID_PRINT_SETUP_PS, "Print Setup PostScript...", "Setup printer properties (PostScript)");
+   file_menu->Append(ID_PAGE_SETUP_PS, "Page Setup PostScript...", "Page setup (PostScript)");
+   file_menu->Append(ID_PREVIEW_PS, "Print Preview PostScript", "Preview (PostScript)");
+#endif
+   file_menu->AppendSeparator();
+   file_menu->Append( ID_TEXT, "Export &Text");
+   file_menu->Append( ID_HTML, "Export &HTML");
+   file_menu->Append( ID_QUIT, "E&xit");
+   menu_bar->Append(file_menu, "&File" );
+
+   wxMenu *edit_menu = new wxMenu;
+   edit_menu->Append( ID_CLEAR, "C&lear");
+   edit_menu->Append( ID_ADD_SAMPLE, "&Example");
+   edit_menu->Append( ID_LONG_TEST, "Add &many lines");
+   edit_menu->AppendSeparator();
+   edit_menu->Append( ID_LINEBREAKS_TEST, "Add &several lines");
+   edit_menu->Append( ID_URL_TEST, "Insert an &URL");
+   edit_menu->AppendSeparator();
+   edit_menu->Append(ID_WRAP, "&Wrap mode", "Activate wrapping at pixel 200.");
+   edit_menu->Append(ID_NOWRAP, "&No-wrap mode", "Deactivate wrapping.");
+   edit_menu->AppendSeparator();
+   edit_menu->Append(ID_COPY, "&Copy", "Copy text to clipboard.");
+   edit_menu->Append(ID_CUT, "Cu&t", "Cut text to clipboard.");
+   edit_menu->Append(ID_PASTE,"&Paste", "Paste text from clipboard.");
+   edit_menu->Append(ID_FIND, "&Find", "Find text.");
+   menu_bar->Append(edit_menu, "&Edit" );
+
+#ifndef __WXMSW__
+   menu_bar->Show( TRUE );
+#endif // MSW
+
+   SetMenuBar( menu_bar );
+
+   m_lwin = new wxLayoutWindow(this);
+   m_lwin->SetStatusBar(GetStatusBar(), 0, 1);
+   m_lwin->SetMouseTracking(true);
+   m_lwin->SetEditable(true);
+   m_lwin->SetWrapMargin(40);
+   m_lwin->Clear(wxROMAN,16,wxNORMAL,wxNORMAL, false);
+   m_lwin->SetFocus();
+
+   // create and set the background bitmap (this will result in a lattice)
+   static const int sizeBmp = 10;
+   wxBitmap *bitmap = new wxBitmap(sizeBmp, sizeBmp);
+   wxMemoryDC dcMem;
+   dcMem.SelectObject( *bitmap );
+   dcMem.SetBackground( *wxWHITE_BRUSH );
+   dcMem.Clear();
+
+   dcMem.SetPen( *wxGREEN_PEN );
+   dcMem.DrawLine(sizeBmp/2, 0, sizeBmp/2, sizeBmp);
+   dcMem.DrawLine(0, sizeBmp/2, sizeBmp, sizeBmp/2);
+
+   dcMem.SelectObject( wxNullBitmap );
+
+   m_lwin->SetBackgroundBitmap(bitmap);
+};
+
+void
+MyFrame::AddSampleText(wxLayoutList *llist)
+{
+   llist->Clear(wxSWISS,16,wxNORMAL,wxNORMAL, false);
+   llist->SetFont(-1,-1,-1,-1,-1,"blue");
+   llist->Insert("blue");
+   llist->SetFont(-1,-1,-1,-1,-1,"black");
+   llist->Insert("The quick brown fox jumps over the lazy dog.");
+   llist->LineBreak();
+
+   llist->SetFont(wxROMAN,16,wxNORMAL,wxNORMAL, false);
+   llist->Insert("--");
+   llist->LineBreak();
+
+   llist->SetFont(wxROMAN);
+   llist->Insert("The quick brown fox jumps over the lazy dog.");
+   llist->LineBreak();
+   llist->Insert("Hello ");
+   llist->Insert(new wxLayoutObjectIcon(new wxICON(Micon)));
+   llist->SetFontWeight(wxBOLD);
+   llist->Insert("World! ");
+   llist->SetFontWeight(wxNORMAL);
+   llist->Insert("The quick brown fox jumps...");
+   llist->LineBreak();
+   llist->Insert("over the lazy dog.");
+   llist->SetFont(-1,-1,-1,-1,true);
+   llist->Insert("underlined");
+   llist->SetFont(-1,-1,-1,-1,false);
+   llist->SetFont(wxROMAN);
+   llist->Insert("This is ");
+   llist->SetFont(-1,-1,-1,wxBOLD);  llist->Insert("BOLD ");  llist->SetFont(-1,-1,-1,wxNORMAL);
+   llist->Insert("and ");
+   llist->SetFont(-1,-1,wxITALIC);
+   llist->Insert("italics ");
+   llist->SetFont(-1,-1,wxNORMAL);
+   llist->LineBreak();
+   llist->Insert("and ");
+   llist->SetFont(-1,-1,wxSLANT);
+   llist->Insert("slanted");
+   llist->SetFont(-1,-1,wxNORMAL);
+   llist->Insert(" text.");
+   llist->LineBreak();
+   llist->Insert("and ");
+   llist->SetFont(-1,-1,-1,-1,-1,"blue");
+   llist->Insert("blue");
+   llist->SetFont(-1,-1,-1,-1,-1,"black");
+   llist->Insert(" and ");
+   llist->SetFont(-1,-1,-1,-1,-1,"green","black");
+   llist->Insert("green on black");
+   llist->SetFont(-1,-1,-1,-1,-1,"black","white");
+   llist->Insert(" text.");
+   llist->LineBreak();
+
+   llist->SetFont(-1,-1,wxSLANT);
+   llist->Insert("Slanted");
+   llist->SetFont(-1,-1,wxNORMAL);
+   llist->Insert(" and normal text and ");
+   llist->SetFont(-1,-1,wxSLANT);
+   llist->Insert("slanted");
+   llist->SetFont(-1,-1,wxNORMAL);
+   llist->Insert(" again.");
+   llist->LineBreak();
+
+   // add some more text for testing:
+   llist->Insert("And here the source for the test program:");
+   llist->LineBreak();
+   llist->SetFont(wxTELETYPE,16);
+   llist->Insert("And here the source for the test program:");
+   llist->LineBreak();
+   llist->Insert("And here the source for the test program:");
+   llist->LineBreak();
+   llist->Insert("And here the source for the test program:");
+
+   char buffer[1024];
+   FILE *in = fopen("wxLayout.cpp","r");
+   if(in)
+   {
+      for(;;)
+      {
+         fgets(buffer,1024,in);
+         if(feof(in))
+            break;
+         wxLayoutImportText(llist, buffer);
+      }
+   }
+
+   llist->MoveCursorTo(wxPoint(0,0));
+   m_lwin->SetDirty();
+   m_lwin->Refresh();
+}
+
+void
+MyFrame::Clear(void)
+{
+   m_lwin->Clear(wxROMAN,16,wxNORMAL,wxNORMAL, false);
+}
+
+
+void MyFrame::OnCommand( wxCommandEvent &event )
+{
+   switch (event.GetId())
+   {
+   case ID_QUIT:
+      Close( TRUE );
+      break;
+   case ID_PRINT:
+   {
+      wxPrinter printer;
+      wxLayoutPrintout printout(m_lwin->GetLayoutList(),_("M: Printout"));
+      if (! printer.Print(this, &printout, TRUE))
+         wxMessageBox(
+            _("There was a problem with printing the message:\n"
+              "perhaps your current printer is not set up correctly?"),
+            _("Printing"), wxOK);
+   }
+   break;
+   case ID_NOWRAP:
+   case ID_WRAP:
+      m_lwin->SetWrapMargin(event.GetId() == ID_NOWRAP ? 0 : 40);
+      break;
+   case ID_ADD_SAMPLE:
+      AddSampleText(m_lwin->GetLayoutList());
+      break;
+   case ID_CLEAR:
+      Clear();
+      break;
+   case ID_CLICK:
+      cerr << "Received click event." << endl;
+      break;
+   case ID_PASTE:
+      m_lwin->Paste();
+      m_lwin->Refresh(FALSE);
+      break;
+   case ID_COPY:
+      m_lwin->Copy();
+      m_lwin->Refresh(FALSE);
+      break;
+   case ID_CUT:
+      m_lwin->Cut();
+      m_lwin->Refresh(FALSE);
+      break;
+   case ID_FIND:
+      m_lwin->Find("void");
+      m_lwin->Refresh(FALSE);
+      break;
+   case ID_HTML:
+   {
+      wxLayoutExportObject *export;
+      wxLayoutExportStatus status(m_lwin->GetLayoutList());
+
+      while((export = wxLayoutExport( &status,
+                                      WXLO_EXPORT_AS_HTML)) != NULL)
+      {
+         if(export->type == WXLO_EXPORT_HTML)
+            cout << *(export->content.text);
+         else
+            cout << "<!--UNKNOWN OBJECT>";
+         delete export;
+      }
+   }
+   break;
+   case ID_TEXT:
+   {
+      wxLayoutExportObject *export;
+      wxLayoutExportStatus status(m_lwin->GetLayoutList());
+
+      while((export = wxLayoutExport( &status, WXLO_EXPORT_AS_TEXT)) != NULL)
+      {
+         if(export->type == WXLO_EXPORT_TEXT)
+            cout << *(export->content.text);
+         else
+            cout << "<!--UNKNOWN OBJECT>";
+         delete export;
+      }
+   }
+   break;
+   case ID_LONG_TEST:
+   {
+      wxString line;
+      wxLayoutList *llist = m_lwin->GetLayoutList();
+      for(int i = 1; i < 5000; i++)
+      {
+         line.Printf("This is line number %d.", i);
+         llist->Insert(line);
+         llist->LineBreak();
+      }
+      llist->MoveCursorTo(wxPoint(0,0));
+      m_lwin->SetDirty();
+      m_lwin->Refresh();
+      break;
+   }
+
+   case ID_LINEBREAKS_TEST:
+      wxLayoutImportText(m_lwin->GetLayoutList(),
+                         "This is a text\n"
+                         "with embedded line\n"
+                         "breaks.\n");
+      m_lwin->SetDirty();
+      m_lwin->Refresh();
+      break;
+
+   case ID_URL_TEST:
+      // VZ: this doesn't work, of course, but I think it should -
+      //     wxLayoutWindow should have a flag m_highlightUrls and do it itself
+      //     (instead of doing it manually like M does now)
+      m_lwin->GetLayoutList()->Insert("http://www.wxwindows.org/");
+   }
+};
+
+void MyFrame::OnPrint(wxCommandEvent& WXUNUSED(event))
+{
+#ifdef __WXMSW__
+   wxGetApp().SetPrintMode(wxPRINT_WINDOWS);
+#else
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+#endif
+   wxPrinter printer;
+   wxLayoutPrintout printout( m_lwin->GetLayoutList(),"Printout from wxLayout");
+   if (! printer.Print(this, &printout, TRUE))
+      wxMessageBox(
+         "There was a problem printing.\nPerhaps your current printer is not set correctly?",
+         "Printing", wxOK);
+}
+
+void MyFrame::OnPrintPS(wxCommandEvent& WXUNUSED(event))
+{
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+
+#ifdef OS_UNIX
+   wxPostScriptPrinter printer;
+   wxLayoutPrintout printout( m_lwin->GetLayoutList(),"My printout");
+   printer.Print(this, &printout, TRUE);
+#endif
+}
+
+void MyFrame::OnPrintPreview(wxCommandEvent& WXUNUSED(event))
+{
+#ifdef __WXMSW__
+   wxGetApp().SetPrintMode(wxPRINT_WINDOWS);
+#else
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+#endif
+   wxPrintData printData;
+
+   // Pass two printout objects: for preview, and possible printing.
+   wxPrintPreview *preview = new wxPrintPreview(new
+                                                wxLayoutPrintout(
+                                                   m_lwin->GetLayoutList()), new wxLayoutPrintout( m_lwin->GetLayoutList()), & printData);
+   if (!preview->Ok())
+   {
+      delete preview;
+      wxMessageBox("There was a problem previewing.\nPerhaps your current printer is not set correctly?", "Previewing", wxOK);
+      return;
+   }
+
+   wxPreviewFrame *frame = new wxPreviewFrame(preview, this, "Demo Print Preview", wxPoint(100, 100), wxSize(600, 650));
+   frame->Centre(wxBOTH);
+   frame->Initialize();
+   frame->Show(TRUE);
+}
+
+void MyFrame::OnPrintPreviewPS(wxCommandEvent& WXUNUSED(event))
+{
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+
+   wxPrintData printData;
+
+   // Pass two printout objects: for preview, and possible printing.
+   wxPrintPreview *preview = new wxPrintPreview(new wxLayoutPrintout( m_lwin->GetLayoutList()), new wxLayoutPrintout( m_lwin->GetLayoutList()), & printData);
+   wxPreviewFrame *frame = new wxPreviewFrame(preview, this, "Demo Print Preview", wxPoint(100, 100), wxSize(600, 650));
+   frame->Centre(wxBOTH);
+   frame->Initialize();
+   frame->Show(TRUE);
+}
+
+void MyFrame::OnPrintSetup(wxCommandEvent& WXUNUSED(event))
+{
+#ifdef OS_WIN
+   wxGetApp().SetPrintMode(wxPRINT_WINDOWS);
+#else
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+#endif
+   wxPrintDialog printerDialog(this, & m_PrintData);
+   printerDialog.ShowModal();
+}
+
+void MyFrame::OnPageSetup(wxCommandEvent& WXUNUSED(event))
+{
+#ifdef __WXMSW__
+   wxGetApp().SetPrintMode(wxPRINT_WINDOWS);
+#else
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+#endif
+   wxPageSetupData data;
+
+#ifdef __WXMSW__
+   wxPageSetupDialog pageSetupDialog(this, & data);
+#else
+   wxGenericPageSetupDialog pageSetupDialog(this, & data);
+#endif
+   pageSetupDialog.ShowModal();
+
+   data = pageSetupDialog.GetPageSetupData();
+}
+
+void MyFrame::OnPrintSetupPS(wxCommandEvent& WXUNUSED(event))
+{
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+
+   wxPrintData data;
+
+#ifdef __WXMSW__
+   wxPrintDialog printerDialog(this, & data);
+#else
+   wxGenericPrintDialog printerDialog(this, & data);
+#endif
+   printerDialog.ShowModal();
+}
+
+void MyFrame::OnPageSetupPS(wxCommandEvent& WXUNUSED(event))
+{
+   wxGetApp().SetPrintMode(wxPRINT_POSTSCRIPT);
+
+   wxPageSetupData data;
+#ifdef __WXMSW__
+   wxPageSetupDialog pageSetupDialog(this, & data);
+#else
+   wxGenericPageSetupDialog pageSetupDialog(this, & data);
+#endif
+   pageSetupDialog.ShowModal();
+}
+
+
+//-----------------------------------------------------------------------------
+// MyApp
+//-----------------------------------------------------------------------------
+
+MyApp::MyApp(void) :
+   wxApp( )
+{
+};
+
+bool MyApp::OnInit(void)
+{
+   wxFrame *frame = new MyFrame();
+   frame->Show( TRUE );
+//   wxSetAFMPath("/usr/local/src/wxWindows/misc/afm/");
+   return TRUE;
+};
+
+
+
+
+
diff --git a/samples/richedit/wxLayout.h b/samples/richedit/wxLayout.h
new file mode 100644 (file)
index 0000000..d64cd74
--- /dev/null
@@ -0,0 +1,66 @@
+/* -*- c++ -*- */
+
+#ifndef __WXLAYOUTH__
+#define __WXLAYOUTH__
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+#include "wx/wx.h"
+
+#include "wxllist.h"
+#include "wxlwindow.h"
+#include "wxlparser.h"
+
+//-----------------------------------------------------------------------------
+// derived classes
+//-----------------------------------------------------------------------------
+
+class MyFrame;
+class MyApp;
+
+//-----------------------------------------------------------------------------
+// MyFrame
+//-----------------------------------------------------------------------------
+
+class MyFrame: public wxFrame
+{
+  DECLARE_DYNAMIC_CLASS(MyFrame)
+
+  public:
+  
+   MyFrame(void);
+   void AddSampleText(wxLayoutList *llist);
+   void Clear(void);
+   void OnCommand( wxCommandEvent &event );
+
+    void OnPrint(wxCommandEvent& event);
+    void OnPrintPreview(wxCommandEvent& event);
+    void OnPrintSetup(wxCommandEvent& event);
+    void OnPageSetup(wxCommandEvent& event);
+    void OnPrintPS(wxCommandEvent& event);
+    void OnPrintPreviewPS(wxCommandEvent& event);
+    void OnPrintSetupPS(wxCommandEvent& event);
+    void OnPageSetupPS(wxCommandEvent& event);
+
+   DECLARE_EVENT_TABLE()
+
+private:
+   wxLayoutWindow  *m_lwin;
+   wxPrintData m_PrintData;
+};
+
+//-----------------------------------------------------------------------------
+// MyApp
+//-----------------------------------------------------------------------------
+
+class MyApp: public wxApp
+{
+  public:
+  
+    MyApp(void);
+    virtual bool OnInit(void);
+};
+
+#endif // __WXCONVERTH__
diff --git a/samples/richedit/wxllist.cpp b/samples/richedit/wxllist.cpp
new file mode 100644 (file)
index 0000000..f28ef6a
--- /dev/null
@@ -0,0 +1,2905 @@
+/*-*- c++ -*-********************************************************
+ * wxllist: wxLayoutList, a layout engine for text and graphics     *
+ *                                                                  *
+ * (C) 1998-1999 by Karsten Ballüder (Ballueder@usa.net)            *
+ *                                                                  *
+ * $Id$
+ *******************************************************************/
+
+/*
+
+  Some docs:
+
+  Layout() recalculates the objects, sizes, etc.
+  Draw()   just draws them with the current settings, without
+           re-layout()ing them again
+
+  Each line has its own wxLayoutStyleInfo structure which gets updated
+  from within Layout(). Thanks to this, we don't need to re-layout all
+  lines if we want to draw one, but can just use its styleinfo to set
+  the right font.
+
+ */
+
+#ifdef __GNUG__
+#   pragma implementation "wxllist.h"
+#endif
+
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+#  pragma hdrstop
+#endif
+
+#include "Mpch.h"
+
+#ifdef M_BASEDIR
+#   include "gui/wxllist.h"
+#   include "gui/wxlparser.h"
+#   define  SHOW_SELECTIONS 1
+#else
+#   include "wxllist.h"
+#   include "wxlparser.h"
+#   define SHOW_SELECTIONS 1
+#endif
+
+#ifndef USE_PCH
+#   include <iostream.h>
+
+#   include <wx/dc.h>
+#   include <wx/dcps.h>
+#   include <wx/print.h>
+#   include <wx/log.h>
+#   include <wx/filefn.h>
+#endif
+
+#ifdef WXLAYOUT_USE_CARET
+#   include <wx/caret.h>
+#endif // WXLAYOUT_USE_CARET
+
+#include <ctype.h>
+
+/// This should never really get created
+#define   WXLLIST_TEMPFILE   "__wxllist.tmp"
+
+#ifdef WXLAYOUT_DEBUG
+
+#  define   TypeString(t)      g_aTypeStrings[t]
+#  define   WXLO_DEBUG(x)      wxLogDebug x
+
+   static const char *g_aTypeStrings[] =
+   {
+      "invalid", "text", "cmd", "icon"
+   };
+   void
+   wxLayoutObject::Debug(void)
+   {
+      WXLO_DEBUG(("%s",g_aTypeStrings[GetType()]));
+   }
+#else
+#  define   TypeString(t)        ""
+#  define   WXLO_DEBUG(x)
+#endif
+
+// FIXME under MSW, this constant is needed to make the thing properly redraw
+//       itself - I don't know where the size calculation error is and I can't
+//       waste time looking for it right now. Search for occurences of
+//       MSW_CORRECTION to find all the places where I did it.
+#ifdef __WXMSW__
+   static const int MSW_CORRECTION = 10;
+#else
+   static const int MSW_CORRECTION = 0;
+#endif
+
+/// Cursors smaller than this disappear in XOR drawing mode
+#define WXLO_MINIMUM_CURSOR_WIDTH   4
+
+/// Use this character to estimate a cursor size when none is available.
+#define WXLO_CURSORCHAR   "E"
+/** @name Helper functions */
+//@{
+/// allows me to compare to wxPoints
+bool operator <=(wxPoint const &p1, wxPoint const &p2)
+{
+   return p1.y < p2.y || (p1.y == p2.y && p1.x <= p2.x);
+}
+
+/*
+  The following STAY HERE until we have a working wxGTK again!!!
+*/
+#ifndef wxWANTS_CHARS
+/// allows me to compare to wxPoints
+bool operator ==(wxPoint const &p1, wxPoint const &p2)
+{
+   return p1.x == p2.x && p1.y == p2.y;
+}
+
+/// allows me to compare to wxPoints
+bool operator !=(wxPoint const &p1, wxPoint const &p2)
+{
+   return p1.x != p2.x || p1.y != p2.y;
+}
+
+wxPoint & operator += (wxPoint &p1, wxPoint const &p2)
+{
+   p1.x += p2.x;
+   p1.y += p2.y;
+   return p1;
+}
+#endif // old wxGTK
+
+/// allows me to compare to wxPoints
+bool operator>(wxPoint const &p1, wxPoint const &p2)
+{
+   return !(p1 <= p2);
+}
+
+/// grows a wxRect so that it includes the given point
+
+static
+void GrowRect(wxRect &r, CoordType x, CoordType y)
+{
+   if(r.x > x)
+      r.x = x;
+   else if(r.x + r.width < x)
+      r.width = x - r.x;
+
+   if(r.y > y)
+      r.y = y;
+   else if(r.y + r.height < y)
+      r.height = y - r.y;
+}
+
+#if 0
+// unused
+/// returns true if the point is in the rectangle
+static
+bool Contains(const wxRect &r, const wxPoint &p)
+{
+   return r.x <= p.x && r.y <= p.y && (r.x+r.width) >= p.x && (r.y + r.height) >= p.y;
+}
+#endif
+
+
+//@}
+
+
+void ReadString(wxString &to, wxString &from)
+{
+   to = "";
+   const char *cptr = from.c_str();
+   while(*cptr && *cptr != '\n')
+      to += *cptr++;
+   if(*cptr) cptr++;
+   from = cptr;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   wxLayoutObject
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* static */
+wxLayoutObject *
+wxLayoutObject::Read(wxString &istr)
+{
+   wxString tmp;
+   ReadString(tmp, istr);
+   int type = -1;
+   sscanf(tmp.c_str(),"%d", &type);
+
+   switch(type)
+   {
+   case WXLO_TYPE_TEXT:
+      return wxLayoutObjectText::Read(istr);
+   case WXLO_TYPE_CMD:
+      return wxLayoutObjectCmd::Read(istr);
+   case WXLO_TYPE_ICON:
+      return wxLayoutObjectIcon::Read(istr);
+   default:
+      return NULL;
+   }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   wxLayoutObjectText
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+wxLayoutObjectText::wxLayoutObjectText(const wxString &txt)
+{
+   m_Text = txt;
+   m_Width = 0;
+   m_Height = 0;
+   m_Top = 0;
+   m_Bottom = 0;
+}
+
+wxLayoutObject *
+wxLayoutObjectText::Copy(void)
+{
+   wxLayoutObjectText *obj = new wxLayoutObjectText(m_Text);
+   obj->m_Width = m_Width;
+   obj->m_Height = m_Height;
+   obj->m_Top = m_Top;
+   obj->m_Bottom = m_Bottom;
+   obj->SetUserData(m_UserData);
+   return obj;
+}
+
+
+void
+wxLayoutObjectText::Write(wxString &ostr)
+{
+   ostr << (int) WXLO_TYPE_TEXT << '\n'
+        << m_Text << '\n';
+}
+/* static */
+wxLayoutObjectText *
+wxLayoutObjectText::Read(wxString &istr)
+{
+   wxString text;
+   ReadString(text, istr);
+
+   return new wxLayoutObjectText(text);
+}
+
+wxPoint
+wxLayoutObjectText::GetSize(CoordType *top, CoordType *bottom) const
+{
+
+   *top = m_Top; *bottom = m_Bottom;
+   return wxPoint(m_Width, m_Height);
+}
+
+void
+wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &coords,
+                         wxLayoutList *wxllist,
+                         CoordType begin, CoordType end)
+{
+   if( end <= 0 )
+   {
+      // draw the whole object normally
+      dc.DrawText(m_Text, coords.x, coords.y-m_Top);
+   }
+   else
+   {
+      // highlight the bit between begin and len
+      CoordType
+         xpos = coords.x,
+         ypos = coords.y-m_Top;
+      long width, height, descent;
+
+      if(begin < 0) begin = 0;
+      if( end > (signed)m_Text.Length() )
+         end = m_Text.Length();
+
+      wxString str = m_Text.Mid(0, begin);
+      dc.DrawText(str, xpos, ypos);
+      dc.GetTextExtent(str, &width, &height, &descent);
+      xpos += width;
+      wxllist->StartHighlighting(dc);
+      str = m_Text.Mid(begin, end-begin);
+      dc.DrawText(str, xpos, ypos);
+      dc.GetTextExtent(str, &width, &height, &descent);
+      xpos += width;
+      wxllist->EndHighlighting(dc);
+      str = m_Text.Mid(end, m_Text.Length()-end);
+      dc.DrawText(str, xpos, ypos);
+   }
+}
+
+CoordType
+wxLayoutObjectText::GetOffsetScreen(wxDC &dc, CoordType xpos) const
+{
+   CoordType
+      offs = 1,
+      maxlen = m_Text.Length();
+   long
+      width = 0,
+      height, descent = 0l;
+
+   if(xpos == 0) return 0; // easy
+
+   while(width < xpos && offs < maxlen)
+   {
+      dc.GetTextExtent(m_Text.substr(0,offs),
+                       &width, &height, &descent);
+      offs++;
+   }
+   /* We have to substract 1 to compensate for the offs++, and another
+      one because we don't want to position the cursor behind the
+      object what we clicked on, but before - otherwise it looks
+      funny. */
+   return (xpos > 2) ? offs-2 : 0;
+}
+
+void
+wxLayoutObjectText::Layout(wxDC &dc, class wxLayoutList *llist)
+{
+   long descent = 0l;
+
+   // now this is done in wxLayoutLine::Layout(), but this code might be
+   // reenabled later - in principle, it's more efficient
+#if 0
+   CoordType widthOld = m_Width,
+             heightOld = m_Height;
+#endif // 0
+
+   dc.GetTextExtent(m_Text, &m_Width, &m_Height, &descent);
+
+#if 0
+   if ( widthOld != m_Width || heightOld != m_Height )
+   {
+      // as the text length changed, it must be refreshed
+      wxLayoutLine *line = GetLine();
+
+      wxCHECK_RET( line, "wxLayoutObjectText can't refresh itself" );
+
+      // as our size changed, we need to repaint the part which was appended
+      wxPoint position(line->GetPosition());
+
+      // this is not the most efficient way (we repaint the whole line), but
+      // it's not too slow and is *simple*
+      if ( widthOld < m_Width )
+         widthOld = m_Width;
+      if ( heightOld < m_Height )
+         heightOld = m_Height;
+
+      llist->SetUpdateRect(position.x + widthOld + MSW_CORRECTION,
+                           position.y + heightOld + MSW_CORRECTION);
+   }
+#endif // 0
+
+   m_Bottom = descent;
+   m_Top = m_Height - m_Bottom;
+}
+
+
+#ifdef WXLAYOUT_DEBUG
+void
+wxLayoutObjectText::Debug(void)
+{
+   wxLayoutObject::Debug();
+   WXLO_DEBUG((" `%s`", m_Text.c_str()));
+}
+#endif
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   wxLayoutObjectIcon
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap const &icon)
+{
+   m_Icon = new wxBitmap(icon);
+}
+
+
+void
+wxLayoutObjectIcon::Write(wxString &ostr)
+{
+   /* Exports icon through a temporary file. */
+
+   wxString file = wxGetTempFileName("wxloexport");
+
+   ostr << WXLO_TYPE_ICON << '\n'
+        << file << '\n';
+   m_Icon->SaveFile(file, WXLO_BITMAP_FORMAT);
+}
+/* static */
+wxLayoutObjectIcon *
+wxLayoutObjectIcon::Read(wxString &istr)
+{
+   wxString file;
+   ReadString(file, istr);
+
+   if(! wxFileExists(file))
+      return NULL;
+   wxLayoutObjectIcon *obj = new wxLayoutObjectIcon;
+
+   if(!obj->m_Icon->LoadFile(file, WXLO_BITMAP_FORMAT))
+   {
+      delete obj;
+      return NULL;
+   }
+   else
+      return obj;
+}
+
+wxLayoutObject *
+wxLayoutObjectIcon::Copy(void)
+{
+   wxLayoutObjectIcon *obj = new wxLayoutObjectIcon(new
+                                                    wxBitmap(*m_Icon));
+   obj->SetUserData(m_UserData);
+   return obj;
+}
+
+wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap *icon)
+{
+   m_Icon = icon;
+}
+
+void
+wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &coords,
+                         wxLayoutList *wxllist,
+                         CoordType begin, CoordType /* len */)
+{
+   dc.DrawBitmap(*m_Icon, coords.x, coords.y-m_Icon->GetHeight(),
+                 (m_Icon->GetMask() == NULL) ? FALSE : TRUE);
+}
+
+void
+wxLayoutObjectIcon::Layout(wxDC & /* dc */, class wxLayoutList * )
+{
+}
+
+wxPoint
+wxLayoutObjectIcon::GetSize(CoordType *top, CoordType *bottom) const
+{
+   *top = m_Icon->GetHeight();
+   *bottom = 0;
+   return wxPoint(m_Icon->GetWidth(), m_Icon->GetHeight());
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   wxLayoutObjectCmd
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+wxLayoutStyleInfo::wxLayoutStyleInfo(int ifamily,
+                                     int isize,
+                                     int istyle,
+                                     int iweight,
+                                     int iul,
+                                     wxColour *fg,
+                                     wxColour *bg)
+{
+   family = ifamily; size = isize;
+   style = istyle; weight = iweight;
+   underline = iul != 0;
+   if(fg)
+   {
+      m_fg = *fg;
+      m_fg_valid = TRUE;
+   }
+   else
+      m_fg = *wxBLACK;
+   if(bg)
+   {
+      m_bg = *bg;
+      m_bg_valid = TRUE;
+   }
+   else
+      m_bg = *wxWHITE;
+}
+
+#define COPY_SI_(what) if(right.what != -1) what = right.what;
+
+wxLayoutStyleInfo &
+wxLayoutStyleInfo::operator=(const wxLayoutStyleInfo &right)
+{
+   COPY_SI_(family);
+   COPY_SI_(style);
+   COPY_SI_(size);
+   COPY_SI_(weight);
+   COPY_SI_(underline);
+   if(right.m_fg_valid) m_fg = right.m_fg;
+   if(right.m_bg_valid) m_bg = right.m_bg;
+   return *this;
+}
+
+wxLayoutObjectCmd::wxLayoutObjectCmd(int family, int size, int style, int
+                                     weight, int underline,
+                                     wxColour *fg, wxColour *bg)
+
+{
+   m_StyleInfo = new wxLayoutStyleInfo(family, size,style,weight,underline,fg,bg);
+}
+
+wxLayoutObject *
+wxLayoutObjectCmd::Copy(void)
+{
+   wxLayoutObjectCmd *obj = new wxLayoutObjectCmd(
+      m_StyleInfo->size,
+      m_StyleInfo->family,
+      m_StyleInfo->style,
+      m_StyleInfo->weight,
+      m_StyleInfo->underline,
+      m_StyleInfo->m_fg_valid ?
+      &m_StyleInfo->m_fg : NULL,
+      m_StyleInfo->m_bg_valid ?
+      &m_StyleInfo->m_bg : NULL);
+   obj->SetUserData(m_UserData);
+   return obj;
+}
+
+void
+wxLayoutObjectCmd::Write(wxString &ostr)
+{
+   ostr << WXLO_TYPE_CMD << '\n'
+        << m_StyleInfo->size << '\n'
+        << m_StyleInfo->family << '\n'
+        << m_StyleInfo->style << '\n'
+        << m_StyleInfo->weight << '\n'
+        << m_StyleInfo->underline << '\n'
+        << m_StyleInfo->m_fg_valid << '\n'
+        << m_StyleInfo->m_bg_valid << '\n';
+   if(m_StyleInfo->m_fg_valid)
+   {
+      ostr << m_StyleInfo->m_fg.Red() << '\n'
+           << m_StyleInfo->m_fg.Green() << '\n'
+           << m_StyleInfo->m_fg.Blue() << '\n';
+   }
+   if(m_StyleInfo->m_bg_valid)
+   {
+      ostr << m_StyleInfo->m_bg.Red() << '\n'
+           << m_StyleInfo->m_bg.Green() << '\n'
+           << m_StyleInfo->m_bg.Blue() << '\n';
+   }
+}
+/* static */
+wxLayoutObjectCmd *
+wxLayoutObjectCmd::Read(wxString &istr)
+{
+   wxLayoutObjectCmd *obj = new wxLayoutObjectCmd;
+
+   wxString tmp;
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->size);
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->family);
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->style);
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->weight);
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->underline);
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->m_fg_valid);
+   ReadString(tmp, istr);
+   sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->m_bg_valid);
+   if(obj->m_StyleInfo->m_fg_valid)
+   {
+      int red, green, blue;
+      ReadString(tmp, istr);
+      sscanf(tmp.c_str(),"%d", &red);
+      ReadString(tmp, istr);
+      sscanf(tmp.c_str(),"%d", &green);
+      ReadString(tmp, istr);
+      sscanf(tmp.c_str(),"%d", &blue);
+      obj->m_StyleInfo->m_fg = wxColour(red, green, blue);
+   }
+   if(obj->m_StyleInfo->m_bg_valid)
+   {
+      int red, green, blue;
+      ReadString(tmp, istr);
+      sscanf(tmp.c_str(),"%d", &red);
+      ReadString(tmp, istr);
+      sscanf(tmp.c_str(),"%d", &green);
+      ReadString(tmp, istr);
+      sscanf(tmp.c_str(),"%d", &blue);
+      obj->m_StyleInfo->m_bg = wxColour(red, green, blue);
+   }
+   return obj;
+}
+
+
+wxLayoutObjectCmd::~wxLayoutObjectCmd()
+{
+   delete m_StyleInfo;
+}
+
+wxLayoutStyleInfo *
+wxLayoutObjectCmd::GetStyle(void) const
+{
+   return m_StyleInfo;
+}
+
+void
+wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const & /* coords */,
+                        wxLayoutList *wxllist,
+                        CoordType begin, CoordType /* len */)
+{
+   wxASSERT(m_StyleInfo);
+   wxllist->ApplyStyle(*m_StyleInfo, dc);
+}
+
+void
+wxLayoutObjectCmd::Layout(wxDC &dc, class wxLayoutList * llist)
+{
+   // this get called, so that recalculation uses right font sizes
+   Draw(dc, wxPoint(0,0), llist);
+}
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   The wxLayoutLine object
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+wxLayoutLine::wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist)
+{
+   m_LineNumber = 0;
+   m_Width = m_Height = 0;
+   m_Length = 0;
+   MarkDirty(0);
+   m_Previous = prev;
+   m_Next = NULL;
+   RecalculatePosition(llist);
+   if(m_Previous)
+   {
+      m_LineNumber = m_Previous->GetLineNumber()+1;
+      m_Next = m_Previous->GetNextLine();
+      m_Previous->m_Next = this;
+   }
+   if(m_Next)
+   {
+      m_Next->m_Previous = this;
+      m_Next->MoveLines(+1);
+      m_Next->RecalculatePositions(1,llist);
+   }
+}
+
+wxLayoutLine::~wxLayoutLine()
+{
+   // kbList cleans itself
+}
+
+wxPoint
+wxLayoutLine::RecalculatePosition(wxLayoutList *llist)
+{
+   wxASSERT(m_Previous || GetLineNumber() == 0);
+
+   wxPoint posOld(m_Position);
+
+   if(m_Previous)
+   {
+      m_Position = m_Previous->GetPosition();
+      m_Position.y += m_Previous->GetHeight();
+   }
+   else
+      m_Position = wxPoint(0,0);
+
+   if ( m_Position != posOld )
+   {
+       // the whole line moved and must be repainted
+       llist->SetUpdateRect(m_Position);
+       llist->SetUpdateRect(m_Position.x + GetWidth() + MSW_CORRECTION,
+                            m_Position.y + GetHeight() + MSW_CORRECTION);
+       llist->SetUpdateRect(posOld);
+       llist->SetUpdateRect(posOld.x + GetWidth() + MSW_CORRECTION,
+                            posOld.y + GetHeight() + MSW_CORRECTION);
+   }
+
+   return m_Position;
+}
+
+void
+wxLayoutLine::RecalculatePositions(int recurse, wxLayoutList *llist)
+{
+   //FIXME: is this really needed? We run Layout() anyway.
+   // Recursing here, drives computation time up exponentially, as
+   // each line will cause all following lines to be recalculated.
+   // Yes, or linenumbers go wrong.
+
+   wxASSERT(recurse >= 0);
+   wxPoint pos = m_Position;
+   CoordType height = m_Height;
+
+//   WXLO_TRACE("RecalculatePositions()");
+   RecalculatePosition(llist);
+   if(m_Next)
+   {
+      if(recurse > 0)
+         m_Next->RecalculatePositions(--recurse, llist);
+      else if(pos != m_Position || m_Height != height)
+         m_Next->RecalculatePositions(0, llist);
+   }
+}
+
+wxLayoutObjectList::iterator
+wxLayoutLine::FindObject(CoordType xpos, CoordType *offset) const
+{
+   wxASSERT(xpos >= 0);
+   wxASSERT(offset);
+   wxLayoutObjectList::iterator
+      i,
+      found = NULLIT;
+   CoordType x = 0, len;
+
+   /* We search through the objects. As we don't like returning the
+      object that the cursor is behind, we just remember such an
+      object in "found" so we can return it if there is really no
+      further object following it. */
+   for(i = m_ObjectList.begin(); i != NULLIT; i++)
+   {
+      len = (**i).GetLength();
+      if( x <= xpos && xpos <= x + len )
+      {
+         *offset = xpos-x;
+         if(xpos == x + len) // is there another object behind?
+            found = i;
+         else  // we are really inside this object
+            return i;
+      }
+      x += (**i).GetLength();
+   }
+   return found;  // ==NULL if really none found
+}
+
+wxLayoutObjectList::iterator
+wxLayoutLine::FindObjectScreen(wxDC &dc,
+                               CoordType xpos, CoordType *cxpos,
+                               bool *found) const
+{
+   wxASSERT(cxpos);
+   wxASSERT(cxpos);
+   wxLayoutObjectList::iterator i;
+   CoordType x = 0, cx = 0, width;
+
+   for(i = m_ObjectList.begin(); i != NULLIT; i++)
+   {
+      width = (**i).GetWidth();
+      if( x <= xpos && xpos <= x + width )
+      {
+         *cxpos = cx + (**i).GetOffsetScreen(dc, xpos-x);
+         if(found) *found = true;
+         return i;
+      }
+      x += (**i).GetWidth();
+      cx += (**i).GetLength();
+   }
+   // behind last object:
+   *cxpos = cx;
+   if(found) *found = false;
+   return m_ObjectList.tail();
+}
+
+/** Finds text in this line.
+    @param needle the text to find
+    @param xpos the position where to start the search
+    @return the cursoor coord where it was found or -1
+*/
+CoordType
+wxLayoutLine::FindText(const wxString &needle, CoordType xpos) const
+{
+   int
+      cpos = 0,
+      relpos = -1;
+   wxString const *text;
+
+   for(wxLOiterator i = m_ObjectList.begin(); i != m_ObjectList.end(); i++)
+   {
+      if(cpos >= xpos) // search from here!
+      {
+         if((**i).GetType() == WXLO_TYPE_TEXT)
+         {
+            text = & ((wxLayoutObjectText*)(*i))->GetText();
+            relpos = text->Find(needle);
+            if(relpos >= cpos-xpos) // -1 if not found
+            {
+               return cpos+relpos;
+            }
+         }
+         cpos += (**i).GetLength();
+      }
+   }
+   return -1; // not found
+}
+
+bool
+wxLayoutLine::Insert(CoordType xpos, wxLayoutObject *obj)
+{
+   wxASSERT(xpos >= 0);
+   wxASSERT(obj != NULL);
+
+   MarkDirty(xpos);
+
+   // If we insert a command object, we need to recalculate all lines
+   // to update their styleinfo structure.
+   if(obj->GetType() == WXLO_TYPE_CMD)
+      MarkNextDirty(-1);
+
+   CoordType offset;
+   wxLOiterator i = FindObject(xpos, &offset);
+   if(i == NULLIT)
+   {
+      if(xpos == 0 ) // aha, empty line!
+      {
+         m_ObjectList.push_back(obj);
+         m_Length += obj->GetLength();
+         return true;
+      }
+      else
+         return false;
+   }
+
+   CoordType len = (**i).GetLength();
+   if(offset == 0 /*&& i != m_ObjectList.begin()*/) // why?
+   {  // insert before this object
+      m_ObjectList.insert(i,obj);
+      m_Length += obj->GetLength();
+      return true;
+   }
+   if(offset == len )
+   {
+      if( i == m_ObjectList.tail()) // last object?
+         m_ObjectList.push_back(obj);
+      else
+      {  // insert after current object
+         i++;
+         m_ObjectList.insert(i,obj);
+      }
+         m_Length += obj->GetLength();
+      return true;
+   }
+   /* Otherwise we need to split the current object.
+      Fortunately this can only be a text object. */
+   wxASSERT((**i).GetType() == WXLO_TYPE_TEXT);
+   wxString left, right;
+   wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
+   left = tobj->GetText().substr(0,offset);
+   right = tobj->GetText().substr(offset,len-offset);
+   // current text object gets set to right half
+   tobj->GetText() = right; // set new text
+   // before it we insert the new object
+   m_ObjectList.insert(i,obj);
+   m_Length += obj->GetLength();
+   // and before that we insert the left half
+   m_ObjectList.insert(i,new wxLayoutObjectText(left));
+   return true;
+}
+
+bool
+wxLayoutLine::Insert(CoordType xpos, const wxString& text)
+{
+   wxASSERT(xpos >= 0);
+
+   MarkDirty(xpos);
+
+   CoordType offset;
+   wxLOiterator i = FindObject(xpos, &offset);
+   if(i != NULLIT && (**i).GetType() == WXLO_TYPE_TEXT)
+   {
+      wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
+      tobj->GetText().insert(offset, text);
+      m_Length += text.Length();
+   }
+   else
+   {
+      if ( !Insert(xpos, new wxLayoutObjectText(text)) )
+         return false;
+   }
+
+   return true;
+}
+
+CoordType
+wxLayoutLine::Delete(CoordType xpos, CoordType npos)
+{
+   CoordType offset, len;
+
+   wxASSERT(xpos >= 0);
+   wxASSERT(npos >= 0);
+   MarkDirty(xpos);
+   wxLOiterator i = FindObject(xpos, &offset);
+   while(npos > 0)
+   {
+      if(i == NULLIT)  return npos;
+      // now delete from that object:
+      if((**i).GetType() != WXLO_TYPE_TEXT)
+      {
+         if(offset != 0) // at end of line after a non-text object
+            return npos;
+         // always len == 1:
+         len = (**i).GetLength();
+         m_Length -= len;
+         npos -= len;
+         // If we delete a command object, we need to recalculate all lines
+         // to update their styleinfo structure.
+         if((**i).GetType() == WXLO_TYPE_CMD)
+            MarkNextDirty(-1);
+         m_ObjectList.erase(i);
+      }
+      else
+      {
+         // tidy up: remove empty text objects
+         if((**i).GetLength() == 0)
+         {
+            m_ObjectList.erase(i);
+            continue;
+         }
+         // Text object:
+         CoordType max = (**i).GetLength() - offset;
+         if(npos < max) max = npos;
+         if(max == 0)
+         {
+            if(xpos == GetLength())
+               return npos;
+            else
+            {  // at    the end of an object
+               // move to    begin of next object:
+               i++; offset = 0;
+               continue; // start over
+            }
+         }
+         npos -= max;
+         m_Length -= max;
+         if(offset == 0 && max == (**i).GetLength())
+            m_ObjectList.erase(i);  // remove the whole object
+         else
+            ((wxLayoutObjectText *)(*i))->GetText().Remove(offset,max);
+      }
+   }
+
+   return npos;
+}
+
+void
+wxLayoutLine::MarkNextDirty(int recurse)
+{
+   wxLayoutLine *line = GetNextLine();
+   while(line && (recurse == -1 || recurse >= 0))
+   {
+      line->MarkDirty();
+      line = line->GetNextLine();
+      if(recurse > 0) recurse --;
+   }
+}
+
+bool
+wxLayoutLine::DeleteWord(CoordType xpos)
+{
+   wxASSERT(xpos >= 0);
+   CoordType offset;
+   MarkDirty(xpos);
+
+   wxLOiterator i = FindObject(xpos, &offset);
+
+   for(;;)
+   {
+      if(i == NULLIT) return false;
+      if((**i).GetType() != WXLO_TYPE_TEXT)
+      {
+         // This should only happen when at end of line, behind a non-text
+         // object:
+         if(offset == (**i).GetLength()) return false;
+         m_Length -= (**i).GetLength(); // -1
+         m_ObjectList.erase(i);
+         return true; // we are done
+      }
+      else
+      {  // text object:
+         if(offset == (**i).GetLength()) // at end of object
+         {
+            i++; offset = 0;
+            continue;
+         }
+         wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
+         size_t count = 0;
+         wxString str = tobj->GetText();
+         str = str.substr(offset,str.Length()-offset);
+         // Find out how many positions we need to delete:
+         // 1. eat leading space
+         while(isspace(str.c_str()[count])) count++;
+         // 2. eat the word itself:
+         while(isalnum(str.c_str()[count])) count++;
+         // now delete it:
+         wxASSERT(count+offset <= (size_t) (**i).GetLength());
+         ((wxLayoutObjectText *)*i)->GetText().erase(offset,count);
+         m_Length -= count;
+         return true;
+      }
+   }
+
+   wxFAIL_MSG("unreachable");
+}
+
+wxLayoutLine *
+wxLayoutLine::DeleteLine(bool update, wxLayoutList *llist)
+{
+   if(m_Next) m_Next->m_Previous = m_Previous;
+   if(m_Previous) m_Previous->m_Next = m_Next;
+   if(update)
+   {
+      m_Next->MoveLines(-1);
+      m_Next->RecalculatePositions(1, llist);
+      /* We assume that if we have more than one object in the list,
+         this means that we have a command object, so we need to
+         update the following lines. */
+      if(m_ObjectList.size() > 1 ||
+         ( m_ObjectList.begin() != NULLIT &&
+           (**m_ObjectList.begin()).GetType() == WXLO_TYPE_CMD)
+         )
+         MarkNextDirty(-1);
+   }
+   wxLayoutLine *next = m_Next;
+   delete this;
+   return next;
+}
+
+void
+wxLayoutLine::Draw(wxDC &dc,
+                   wxLayoutList *llist,
+                   const wxPoint & offset) const
+{
+   wxLayoutObjectList::iterator i;
+   wxPoint pos = offset;
+   pos = pos + GetPosition();
+
+   pos.y += m_BaseLine;
+
+   CoordType xpos = 0; // cursorpos, lenght of line
+
+   CoordType from, to, tempto;
+
+   int highlight = llist->IsSelected(this, &from, &to);
+//   WXLO_DEBUG(("highlight=%d",  highlight ));
+   if(highlight == 1) // we need to draw the whole line inverted!
+      llist->StartHighlighting(dc);
+   else
+      llist->EndHighlighting(dc);
+
+   for(i = m_ObjectList.begin(); i != NULLIT; i++)
+   {
+      if(highlight == -1) // partially highlight line
+      {
+         // parts of the line need highlighting
+         tempto = xpos+(**i).GetLength();
+         (**i).Draw(dc, pos, llist, from-xpos, to-xpos);
+      }
+      else
+         (**i).Draw(dc, pos, llist);
+      pos.x += (**i).GetWidth();
+      xpos += (**i).GetLength();
+   }
+}
+
+/*
+  This function does all the recalculation, that is, it should only be
+  called from within wxLayoutList::Layout(), as it uses the current
+  list's styleinfo and updates it.
+*/
+void
+wxLayoutLine::Layout(wxDC &dc,
+                     wxLayoutList *llist,
+                     wxPoint *cursorPos,
+                     wxPoint *cursorSize,
+                     int cx,
+                     bool suppressSIupdate)
+{
+   wxLayoutObjectList::iterator i;
+
+   // when a line becomes dirty, we redraw it from the place where it was
+   // changed till the end of line (because the following wxLayoutObjects are
+   // moved when the preceding one changes) - calculate the update rectangle.
+   CoordType updateTop = m_Position.y,
+             updateLeft = -1,
+             updateWidth = m_Width,
+             updateHeight = m_Height;
+
+   CoordType
+      topHeight = 0,
+      bottomHeight = 0;  // above and below baseline
+   CoordType
+      objTopHeight, objBottomHeight; // above and below baseline
+   CoordType
+      len, count = 0;
+
+   CoordType heightOld = m_Height;
+
+   m_Height = 0;
+   m_Width = 0;
+   m_BaseLine = 0;
+
+   bool cursorFound = false;
+
+   if(cursorPos)
+   {
+      *cursorPos = m_Position;
+      if(cursorSize) *cursorSize = wxPoint(0,0);
+   }
+
+   m_StyleInfo = llist->GetStyleInfo(); // save current style
+   for(i = m_ObjectList.begin(); i != NULLIT; i++)
+   {
+      wxLayoutObject *obj = *i;
+      obj->Layout(dc, llist);
+      wxPoint sizeObj = obj->GetSize(&objTopHeight, &objBottomHeight);
+
+      if(cursorPos && ! cursorFound)
+      {
+         // we need to check whether the text cursor is here
+         len = obj->GetLength();
+         if(count <= cx && count+len > cx)
+         {
+            if(obj->GetType() == WXLO_TYPE_TEXT)
+            {
+               len = cx - count; // pos in object
+               CoordType width, height, descent;
+               dc.GetTextExtent((*(wxLayoutObjectText*)*i).GetText().substr(0,len),
+                                &width, &height, &descent);
+               cursorPos->x += width;
+               cursorPos->y = m_Position.y;
+               wxString str;
+               if(len < obj->GetLength())
+                  str = (*(wxLayoutObjectText*)*i).GetText().substr(len,1);
+               else
+                  str = WXLO_CURSORCHAR;
+               dc.GetTextExtent(str, &width, &height, &descent);
+               wxASSERT(cursorSize);
+               // Just in case some joker inserted an empty string object:
+               if(width == 0) width = WXLO_MINIMUM_CURSOR_WIDTH;
+               if(height == 0) height = sizeObj.y;
+               cursorSize->x = width;
+               cursorSize->y = height;
+               cursorFound = true; // no more checks
+            }
+            else
+            {
+               // on some other object
+               CoordType top, bottom; // unused
+               *cursorSize = obj->GetSize(&top,&bottom);
+               cursorPos->y = m_Position.y;
+               cursorFound = true; // no more checks
+            }
+         }
+         else
+         {
+            count += len;
+            cursorPos->x += obj->GetWidth();
+         }
+      } // cursor finding
+
+      m_Width += sizeObj.x;
+      if(sizeObj.y > m_Height)
+      {
+         m_Height = sizeObj.y;
+      }
+
+      if(objTopHeight > topHeight)
+         topHeight = objTopHeight;
+      if(objBottomHeight > bottomHeight)
+         bottomHeight = objBottomHeight;
+   }
+
+   if ( IsDirty() )
+   {
+      if ( updateHeight < m_Height )
+         updateHeight = m_Height;
+      if ( updateWidth < m_Width )
+         updateWidth = m_Width;
+
+      // update all line if we don't know where to start from
+      if ( updateLeft == -1 )
+          updateLeft = 0;
+
+      llist->SetUpdateRect(updateLeft, updateTop);
+      llist->SetUpdateRect(updateLeft + updateWidth + MSW_CORRECTION,
+                           updateTop + updateHeight + MSW_CORRECTION);
+   }
+
+   if(topHeight + bottomHeight > m_Height)
+   {
+      m_Height = topHeight+bottomHeight;
+   }
+
+   m_BaseLine = topHeight;
+
+   if(m_Height == 0)
+   {
+      CoordType width, height, descent;
+      dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
+      m_Height = height;
+      m_BaseLine = m_Height - descent;
+   }
+
+   // tell next line about coordinate change
+   if(m_Next && m_Height != heightOld)
+   {
+      // FIXME isn't this done in RecalculatePositions() below anyhow?
+      m_Next->RecalculatePositions(0, llist);
+   }
+
+   // We need to check whether we found a valid cursor size:
+   if(cursorPos)
+   {
+      // this might be the case if the cursor is at the end of the
+      // line or on a command object:
+      if(cursorSize->y < WXLO_MINIMUM_CURSOR_WIDTH)
+      {
+         CoordType width, height, descent;
+         dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
+         cursorSize->x = width;
+         cursorSize->y = height;
+      }
+      if(m_BaseLine >= cursorSize->y) // the normal case anyway
+         cursorPos->y += m_BaseLine-cursorSize->y;
+   }
+   RecalculatePositions(1, llist);
+   MarkClean();
+}
+
+
+wxLayoutLine *
+wxLayoutLine::Break(CoordType xpos, wxLayoutList *llist)
+{
+   wxASSERT(xpos >= 0);
+
+   MarkDirty(xpos);
+
+   /* If we are at the begin of a line, we want to move all other
+      lines down and stay with the cursor where we are. However, if we
+      are in an empty line, we want to move down with it. */
+   if(xpos == 0 && GetLength() > 0)
+   { // insert an empty line before this one
+      wxLayoutLine *prev = new wxLayoutLine(m_Previous, llist);
+      if(m_Previous == NULL)
+      {  // We were in first line, need to link in new empty line
+         // before this.
+         prev->m_Next = this;
+         m_Previous = prev;
+         m_Previous->m_Height = 0; // this is a wild guess
+      }
+      if(m_Next)
+         m_Next->RecalculatePositions(1, llist);
+      return m_Previous;
+   }
+
+   CoordType offset;
+   wxLOiterator i = FindObject(xpos, &offset);
+   if(i == NULLIT)
+      // must be at the end of the line then
+      return new wxLayoutLine(this, llist);
+   // split this line:
+
+   wxLayoutLine *newLine = new wxLayoutLine(this, llist);
+   // split object at i:
+   if((**i).GetType() == WXLO_TYPE_TEXT && offset != 0)
+   {
+      wxString left, right;
+      wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
+      left = tobj->GetText().substr(0,offset);
+      right = tobj->GetText().substr(offset,tobj->GetLength()-offset);
+      // current text object gets set to left half
+      tobj->GetText() = left; // set new text
+      newLine->Append(new wxLayoutObjectText(right));
+      m_Length -= right.Length();
+      i++; // don't move this object to the new list
+   }
+   else
+   {
+      if(offset > 0)
+         i++; // move objects from here to new list
+   }
+
+   while(i != m_ObjectList.end())
+   {
+      wxLayoutObject *obj = *i;
+      newLine->Append(obj);
+      m_Length -= obj->GetLength();
+
+      m_ObjectList.remove(i); // remove without deleting it
+   }
+   if(m_Next)
+      m_Next->RecalculatePositions(2, llist);
+   return newLine;
+}
+
+
+void
+wxLayoutLine::MergeNextLine(wxLayoutList *llist)
+{
+   wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
+   wxLayoutObjectList &list = GetNextLine()->m_ObjectList;
+   wxLOiterator i;
+
+   MarkDirty(GetWidth());
+
+   wxLayoutObject *last = NULL;
+   for(i = list.begin(); i != list.end();)
+   {
+      wxLayoutObject *current = *i;
+
+      // merge text objects together for efficiency
+      if ( last && last->GetType() == WXLO_TYPE_TEXT &&
+                   current->GetType() == WXLO_TYPE_TEXT )
+      {
+         wxLayoutObjectText *textObj = (wxLayoutObjectText *)last;
+         wxString text(textObj->GetText());
+         text += ((wxLayoutObjectText *)current)->GetText();
+         textObj->SetText(text);
+
+         list.erase(i); // remove and delete it
+      }
+      else
+      {
+         // just append the object "as was"
+         Append(current);
+
+         list.remove(i); // remove without deleting it
+      }
+   }
+   wxASSERT(list.empty());
+
+   wxLayoutLine *oldnext = GetNextLine();
+   wxLayoutLine *nextLine = oldnext->GetNextLine();
+   SetNext(nextLine);
+   if ( nextLine )
+   {
+      nextLine->MoveLines(-1);
+   }
+   else
+   {
+       // this is now done in Delete(), but if this function is ever called
+       // from elsewhere, we might have to move refresh code back here (in
+       // order not to duplicate it)
+#if 0
+       wxPoint pos(oldnext->GetPosition());
+       llist->SetUpdateRect(pos);
+       llist->SetUpdateRect(pos.x + oldnext->GetWidth() + MSW_CORRECTION,
+                            pos.y + oldnext->GetHeight() + MSW_CORRECTION);
+#endif // 0
+   }
+
+   delete oldnext;
+}
+
+CoordType
+wxLayoutLine::GetWrapPosition(CoordType column)
+{
+   CoordType offset;
+   wxLOiterator i = FindObject(column, &offset);
+   if(i == NULLIT) return -1; // cannot wrap
+
+   // go backwards through the list and look for space in text objects
+   do
+   {
+      if((**i).GetType() == WXLO_TYPE_TEXT)
+      {
+         do
+         {
+            if( isspace(((wxLayoutObjectText*)*i)->GetText().c_str()[(size_t)offset]))
+               return column;
+            else
+            {
+               offset--;
+               column--;
+            }
+         }while(offset != -1);
+         i--;  // move on to previous object
+      }
+      else
+      {
+         column -= (**i).GetLength();
+         i--;
+      }
+      if( i != NULLIT)
+         offset = (**i).GetLength();
+   }while(i != NULLIT);
+   /* If we reached the begin of the list and have more than one
+      object, that one is longer than the margin, so break behind
+      it. */
+   CoordType pos = 0;
+   i = m_ObjectList.begin();
+   while(i != NULLIT && (**i).GetType() != WXLO_TYPE_TEXT)
+   {
+      pos += (**i).GetLength();
+      i++;
+   }
+   if(i == NULLIT) return -1;  //why should this happen?
+   pos += (**i).GetLength();
+   i++;
+   while(i != NULLIT && (**i).GetType() != WXLO_TYPE_TEXT)
+   {
+            pos += (**i).GetLength();
+            i++;
+   }
+   if(i == NULLIT) return -1;  //this is possible, if there is only one text object
+   // now we are at the second text object:
+   pos -= (**i).GetLength();
+   return pos; // in front of it
+}
+
+
+#ifdef WXLAYOUT_DEBUG
+void
+wxLayoutLine::Debug(void)
+{
+   wxString tmp;
+   wxPoint pos = GetPosition();
+   WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d",
+               (long int) GetLineNumber(),
+               (long int) pos.x, (long int) pos.y,
+               (long int) GetHeight(),
+               (long int) m_BaseLine,
+               (int) m_StyleInfo.family));
+   if(m_ObjectList.begin() != NULLIT)
+      (**m_ObjectList.begin()).Debug();
+
+}
+#endif
+
+void
+wxLayoutLine::Copy(wxLayoutList *llist,
+                   CoordType from,
+                   CoordType to)
+{
+   CoordType firstOffset, lastOffset;
+
+   if(to == -1) to = GetLength();
+   if(from == to) return;
+
+   wxLOiterator first = FindObject(from, &firstOffset);
+   wxLOiterator last  = FindObject(to, &lastOffset);
+
+   // Common special case: only one object
+   if( first != NULLIT && last != NULLIT && *first == *last )
+   {
+      if( (**first).GetType() == WXLO_TYPE_TEXT )
+      {
+         llist->Insert(new wxLayoutObjectText(
+            ((wxLayoutObjectText
+              *)*first)->GetText().substr(firstOffset,
+                                          lastOffset-firstOffset))
+            );
+         return;
+      }
+      else // what can we do?
+      {
+         if(lastOffset > firstOffset) // i.e. +1 :-)
+            llist->Insert( (**first).Copy() );
+         return;
+      }
+   }
+
+   // If we reach here, we can safely copy the whole first object from
+   // the firstOffset position on:
+   if((**first).GetType() == WXLO_TYPE_TEXT && firstOffset != 0)
+   {
+      llist->Insert(new wxLayoutObjectText(
+         ((wxLayoutObjectText *)*first)->GetText().substr(firstOffset))
+         );
+   }
+   else if(firstOffset == 0)
+      llist->Insert( (**first).Copy() );
+   // else nothing to copy :-(
+
+   // Now we copy all objects before the last one:
+   wxLOiterator i = first; i++;
+   for( ; i != last; i++)
+      llist->Insert( (**i).Copy() );
+
+   // And now the last object:
+   if(lastOffset != 0)
+   {
+      if( (**last).GetType() == WXLO_TYPE_TEXT )
+      {
+         llist->Insert(new wxLayoutObjectText(
+            ((wxLayoutObjectText *)*last)->GetText().substr(0,lastOffset))
+            );
+      }
+      else
+         llist->Insert( (**last).Copy() );
+   }
+}
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   The wxLayoutList object
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+wxLayoutList::wxLayoutList()
+{
+#ifdef WXLAYOUT_USE_CARET
+   m_caret = NULL;
+#endif // WXLAYOUT_USE_CARET
+
+   m_FirstLine = NULL;
+   InvalidateUpdateRect();
+   Clear();
+}
+
+wxLayoutList::~wxLayoutList()
+{
+   InternalClear();
+   m_FirstLine->DeleteLine(false, this);
+}
+
+void
+wxLayoutList::Empty(void)
+{
+   while(m_FirstLine)
+      m_FirstLine = m_FirstLine->DeleteLine(false, this);
+
+   m_CursorPos = wxPoint(0,0);
+   m_CursorScreenPos = wxPoint(0,0);
+   m_CursorSize = wxPoint(0,0);
+   m_movedCursor = true;
+   m_FirstLine = new wxLayoutLine(NULL, this); // empty first line
+   m_CursorLine = m_FirstLine;
+   InvalidateUpdateRect();
+}
+
+
+void
+wxLayoutList::InternalClear(void)
+{
+   Empty();
+   m_Selection.m_selecting = false;
+   m_Selection.m_valid = false;
+
+   m_DefaultStyleInfo.family = wxSWISS;
+   m_DefaultStyleInfo.size = WXLO_DEFAULTFONTSIZE;
+   m_DefaultStyleInfo.style = wxNORMAL;
+   m_DefaultStyleInfo.weight = wxNORMAL;
+   m_DefaultStyleInfo.underline = 0;
+   m_DefaultStyleInfo.m_fg_valid = TRUE;
+   m_DefaultStyleInfo.m_fg = *wxBLACK;
+   m_DefaultStyleInfo.m_bg_valid = TRUE;
+   m_DefaultStyleInfo.m_bg = *wxWHITE;
+
+   m_CurrentStyleInfo = m_DefaultStyleInfo;
+}
+
+void
+wxLayoutList::SetFont(int family, int size, int style, int weight,
+                      int underline, wxColour *fg,
+                      wxColour *bg)
+{
+   if(family != -1)    m_CurrentStyleInfo.family = family;
+   if(size != -1)      m_CurrentStyleInfo.size = size;
+   if(style != -1)     m_CurrentStyleInfo.style = style;
+   if(weight != -1)    m_CurrentStyleInfo.weight = weight;
+   if(underline != -1) m_CurrentStyleInfo.underline = underline != 0;
+   if(fg) m_CurrentStyleInfo.m_fg = *fg;
+   if(bg) m_CurrentStyleInfo.m_bg = *bg;
+   Insert(
+      new wxLayoutObjectCmd(
+         m_CurrentStyleInfo.family,
+         m_CurrentStyleInfo.size,
+         m_CurrentStyleInfo.style,
+         m_CurrentStyleInfo.weight,
+         m_CurrentStyleInfo.underline,
+         fg, bg));
+}
+
+void
+wxLayoutList::SetFont(int family, int size, int style, int weight,
+                      int underline, char const *fg, char const *bg)
+
+{
+   wxColour
+      *cfg = NULL,
+      *cbg = NULL;
+
+   if( fg )
+      cfg = wxTheColourDatabase->FindColour(fg);
+   if( bg )
+      cbg = wxTheColourDatabase->FindColour(bg);
+
+   SetFont(family,size,style,weight,underline,cfg,cbg);
+}
+
+void
+wxLayoutList::Clear(int family, int size, int style, int weight,
+                    int underline, wxColour *fg, wxColour *bg)
+{
+   InternalClear();
+   m_DefaultStyleInfo = wxLayoutStyleInfo(family, size, style, weight,
+                                        underline, fg, bg);
+   m_CurrentStyleInfo = m_DefaultStyleInfo;
+}
+
+wxPoint
+wxLayoutList::FindText(const wxString &needle, const wxPoint &cpos) const
+{
+   int xpos;
+
+   wxLayoutLine *line;
+   for(line = m_FirstLine;
+       line;
+       line = line->GetNextLine())
+   {
+      if(line->GetLineNumber() >= cpos.y)
+      {
+         xpos = line->FindText(needle,
+                               (line->GetLineNumber() == cpos.y) ?
+                               cpos.x : 0);
+         if(xpos != -1)
+            return wxPoint(xpos, line->GetLineNumber());
+      }
+   }
+   return wxPoint(-1,-1);
+}
+
+
+bool
+wxLayoutList::MoveCursorTo(wxPoint const &p)
+{
+   AddCursorPosToUpdateRect();
+
+   wxPoint cursorPosOld = m_CursorPos;
+
+   wxLayoutLine *line = m_FirstLine;
+   while(line && line->GetLineNumber() != p.y)
+      line = line->GetNextLine();
+   if(line && line->GetLineNumber() == p.y) // found it
+   {
+      m_CursorPos.y = p.y;
+      m_CursorLine = line;
+      CoordType len = line->GetLength();
+      if(len >= p.x)
+      {
+         m_CursorPos.x = p.x;
+      }
+      else
+      {
+         m_CursorPos.x = len;
+      }
+   }
+
+   m_movedCursor = m_CursorPos != cursorPosOld;
+
+   return m_CursorPos == p;
+}
+
+bool
+wxLayoutList::MoveCursorVertically(int n)
+{
+   AddCursorPosToUpdateRect();
+
+   wxPoint cursorPosOld = m_CursorPos;
+
+   bool rc;
+   if(n  < 0) // move up
+   {
+      if(m_CursorLine == m_FirstLine) return false;
+      while(n < 0 && m_CursorLine)
+      {
+         m_CursorLine = m_CursorLine->GetPreviousLine();
+         m_CursorPos.y--;
+         n++;
+      }
+      if(! m_CursorLine)
+      {
+         m_CursorLine = m_FirstLine;
+         m_CursorPos.y = 0;
+         rc = false;
+      }
+      else
+      {
+         if(m_CursorPos.x > m_CursorLine->GetLength())
+            m_CursorPos.x = m_CursorLine->GetLength();
+         rc = true;
+      }
+   }
+   else // move down
+   {
+      wxLayoutLine *last = m_CursorLine;
+      if(! m_CursorLine->GetNextLine()) return false;
+      while(n > 0 && m_CursorLine)
+      {
+         n--;
+         m_CursorPos.y ++;
+         m_CursorLine = m_CursorLine->GetNextLine();
+      }
+      if(! m_CursorLine)
+      {
+         m_CursorLine = last;
+         m_CursorPos.y ++;
+         rc = false;
+      }
+      else
+      {
+         if(m_CursorPos.x > m_CursorLine->GetLength())
+            m_CursorPos.x = m_CursorLine->GetLength();
+         rc = true;
+      }
+   }
+
+   m_movedCursor = m_CursorPos != cursorPosOld;
+
+   return rc;
+}
+
+bool
+wxLayoutList::MoveCursorHorizontally(int n)
+{
+   AddCursorPosToUpdateRect();
+
+   wxPoint cursorPosOld = m_CursorPos;
+
+   int move;
+   while(n < 0)
+   {
+      if(m_CursorPos.x == 0) // at begin of line
+      {
+         if(! MoveCursorVertically(-1))
+            break;
+         MoveCursorToEndOfLine();
+         n++;
+         continue;
+      }
+      move = -n;
+      if(move > m_CursorPos.x) move = m_CursorPos.x;
+      m_CursorPos.x -= move; n += move;
+   }
+
+   while(n > 0)
+   {
+      int len =  m_CursorLine->GetLength();
+      if(m_CursorPos.x == len) // at end of line
+      {
+         if(! MoveCursorVertically(1))
+            break;
+         MoveCursorToBeginOfLine();
+         n--;
+         continue;
+      }
+      move = n;
+      if( move >= len-m_CursorPos.x) move = len-m_CursorPos.x;
+      m_CursorPos.x += move;
+      n -= move;
+   }
+
+   m_movedCursor = m_CursorPos != cursorPosOld;
+
+   return n == 0;
+}
+
+bool
+wxLayoutList::MoveCursorWord(int n)
+{
+   wxCHECK_MSG( m_CursorLine, false, "no current line" );
+   wxCHECK_MSG( n == -1 || n == +1, false, "not implemented yet" );
+
+   CoordType moveDistance = 0;
+   CoordType offset;
+   for ( wxLOiterator i = m_CursorLine->FindObject(m_CursorPos.x, &offset);
+         n != 0;
+         n > 0 ? i++ : i-- )
+   {
+      if ( i == NULLIT )
+         return false;
+
+      wxLayoutObject *obj = *i;
+      if( obj->GetType() != WXLO_TYPE_TEXT )
+      {
+         // any non text objects count as one word
+         n > 0 ? n-- : n++;
+
+         moveDistance += obj->GetLength();
+      }
+      else
+      {
+         // text object
+         wxLayoutObjectText *tobj = (wxLayoutObjectText *)obj;
+
+         if ( offset == tobj->GetLength() )
+         {
+            // at end of object
+            n > 0 ? n-- : n++;
+         }
+         else
+         {
+            const char *start = tobj->GetText().c_str();
+            const char *p = start + offset;
+
+            // to the beginning/end of the next/prev word
+            while ( isspace(*p) )
+            {
+               n > 0 ? p++ : p--;
+            }
+
+            // go to the end/beginning of the word (in a broad sense...)
+            while ( p >= start && !isspace(*p) )
+            {
+               n > 0 ? p++ : p--;
+            }
+
+            if ( n > 0 )
+            {
+               // now advance to the beginning of the next word
+               while ( isspace(*p) )
+                  p++;
+            }
+
+            n > 0 ? n-- : n++;
+
+            moveDistance = p - start - offset;
+         }
+      }
+
+      // except for the first iteration, offset is 0
+      offset = 0;
+   }
+
+   MoveCursorHorizontally(moveDistance);
+
+   return true;
+}
+
+bool
+wxLayoutList::Insert(wxString const &text)
+{
+   wxASSERT(m_CursorLine);
+   wxASSERT_MSG( text.Find('\n') == wxNOT_FOUND, "use wxLayoutImportText!" );
+
+   if ( !text )
+       return true;
+
+   AddCursorPosToUpdateRect();
+
+   if ( !m_CursorLine->Insert(m_CursorPos.x, text) )
+      return false;
+
+   m_CursorPos.x += text.Length();
+
+   m_movedCursor = true;
+
+   m_CursorLine->RecalculatePositions(0, this);
+
+   return true;
+}
+
+bool
+wxLayoutList::Insert(wxLayoutObject *obj)
+{
+   wxASSERT(m_CursorLine);
+
+   if(! m_CursorLine)
+      m_CursorLine = GetFirstLine();
+
+   AddCursorPosToUpdateRect();
+
+   m_CursorLine->Insert(m_CursorPos.x, obj);
+   m_CursorPos.x += obj->GetLength();
+   m_movedCursor = true;
+
+   m_CursorLine->RecalculatePositions(0, this);
+
+   return true;
+}
+
+bool
+wxLayoutList::Insert(wxLayoutList *llist)
+{
+   wxASSERT(llist);
+   bool rc = TRUE;
+
+   for(wxLayoutLine *line = llist->GetFirstLine();
+       line;
+       line = line->GetNextLine()
+      )
+   {
+      for(wxLOiterator i = line->GetFirstObject();
+          i != NULLIT;
+          i++)
+         rc |= Insert(*i);
+      LineBreak();
+   }
+   return rc;
+}
+
+bool
+wxLayoutList::LineBreak(void)
+{
+   wxASSERT(m_CursorLine);
+   bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
+
+   AddCursorPosToUpdateRect();
+
+   wxPoint position(m_CursorLine->GetPosition());
+
+   CoordType
+      width = m_CursorLine->GetWidth(),
+      height = m_CursorLine->GetHeight();
+
+   m_CursorLine = m_CursorLine->Break(m_CursorPos.x, this);
+   if(setFirst) // we were at beginning of first line
+      m_FirstLine = m_CursorLine->GetPreviousLine();
+   if(m_CursorPos.x != 0)
+      m_CursorPos.y++;
+   m_CursorPos.x = 0;
+
+   wxLayoutLine *prev = m_CursorLine->GetPreviousLine();
+   wxCHECK_MSG(prev, false, "just broke the line, where is the previous one?");
+
+   height += prev->GetHeight();
+
+   m_movedCursor = true;
+
+   SetUpdateRect(position);
+   SetUpdateRect(position.x + width + MSW_CORRECTION,
+                 position.y + height + MSW_CORRECTION);
+
+   return true;
+}
+
+bool
+wxLayoutList::WrapLine(CoordType column)
+{
+   if(m_CursorPos.x <= column || column < 1)
+      return false; // do nothing yet
+   else
+   {
+      CoordType xpos = m_CursorLine->GetWrapPosition(column);
+      if(xpos == -1)
+         return false; // cannot break line
+      //else:
+      CoordType newpos = m_CursorPos.x - xpos - 1;
+      m_CursorPos.x = xpos;
+
+      AddCursorPosToUpdateRect();
+
+      LineBreak();
+      Delete(1); // delete the space
+      m_CursorPos.x = newpos;
+
+      m_CursorLine->RecalculatePositions(1, this);
+
+      m_movedCursor = true;
+
+      return true;
+   }
+}
+
+bool
+wxLayoutList::Delete(CoordType npos)
+{
+   wxCHECK_MSG(m_CursorLine, false, "can't delete in non existing line");
+
+   if ( npos == 0 )
+       return true;
+
+   AddCursorPosToUpdateRect();
+
+   // were other lines appended to this one (this is important to know because
+   // this means that our width _increased_ as the result of deletion)
+   bool wasMerged = false;
+
+   // the size of the region to update
+   CoordType totalHeight = m_CursorLine->GetHeight(),
+             totalWidth = m_CursorLine->GetWidth();
+
+   CoordType left;
+   do
+   {
+      left = m_CursorLine->Delete(m_CursorPos.x, npos);
+
+      if( left > 0 )
+      {
+         // More to delete, continue on next line.
+
+         // First, check if line is empty:
+         if(m_CursorLine->GetLength() == 0)
+         {
+            // in this case, updating could probably be optimised
+#ifdef WXLO_DEBUG
+            wxASSERT(DeleteLines(1) == 0);
+#else
+            DeleteLines(1);
+#endif
+
+            left--;
+         }
+         else
+         {
+            // Need to join next line
+            if(! m_CursorLine->GetNextLine())
+               break; // cannot
+            else
+            {
+               wasMerged = true;
+               wxLayoutLine *next = m_CursorLine->GetNextLine();
+               if ( next )
+               {
+                  totalHeight += next->GetHeight();
+                  totalWidth += next->GetWidth();
+
+                  m_CursorLine->MergeNextLine(this);
+                  left--;
+               }
+               else
+               {
+                  wxFAIL_MSG("can't delete all this");
+
+                  return false;
+               }
+            }
+         }
+      }
+   }
+   while ( left> 0 );
+
+   // we need to update the whole tail of the line and the lines which
+   // disappeared
+   if ( wasMerged )
+   {
+      wxPoint position(m_CursorLine->GetPosition());
+      SetUpdateRect(position);
+      SetUpdateRect(position.x + totalWidth + MSW_CORRECTION,
+                    position.y + totalHeight + MSW_CORRECTION);
+   }
+
+   return left == 0;
+}
+
+int
+wxLayoutList::DeleteLines(int n)
+{
+   wxASSERT(m_CursorLine);
+   wxLayoutLine *line;
+
+   AddCursorPosToUpdateRect();
+
+   while(n > 0)
+   {
+      if(!m_CursorLine->GetNextLine())
+      {  // we cannot delete this line, but we can clear it
+         MoveCursorToBeginOfLine();
+         DeleteToEndOfLine();
+         m_CursorLine->RecalculatePositions(2, this);
+         return n-1;
+      }
+      //else:
+      line = m_CursorLine;
+      m_CursorLine = m_CursorLine->DeleteLine(true, this);
+      n--;
+      if(line == m_FirstLine) m_FirstLine = m_CursorLine;
+      wxASSERT(m_FirstLine);
+      wxASSERT(m_CursorLine);
+   }
+   m_CursorLine->RecalculatePositions(2, this);
+   return n;
+}
+
+void
+wxLayoutList::Recalculate(wxDC &dc, CoordType bottom)
+{
+   wxLayoutLine *line = m_FirstLine;
+
+   // first, make sure everything is calculated - this might not be
+   // needed, optimise it later
+   ApplyStyle(m_DefaultStyleInfo, dc);
+   while(line)
+   {
+      line->RecalculatePosition(this); // so we don't need to do it all the time
+      // little condition to speed up redrawing:
+      if(bottom != -1 && line->GetPosition().y > bottom) break;
+      line = line->GetNextLine();
+   }
+}
+
+void
+wxLayoutList::UpdateCursorScreenPos(wxDC &dc,
+                                    bool resetCursorMovedFlag,
+                                    const wxPoint& translate)
+{
+   wxCHECK_RET( m_CursorLine, "no cursor line" );
+
+   if ( m_movedCursor )
+   {
+      // we need to save the current style, in case the layout() of
+      // the line changes it
+      wxLayoutStyleInfo SiBackup = m_CurrentStyleInfo;
+      m_CursorLine->Layout(dc, this,
+                           &m_CursorScreenPos, &m_CursorSize,
+                           m_CursorPos.x,
+                           /* suppress update */ true);
+      ApplyStyle(SiBackup, dc); // restore it
+
+      if ( resetCursorMovedFlag )
+      {
+#ifdef WXLAYOUT_USE_CARET
+            // adjust the caret position
+            wxPoint coords(m_CursorScreenPos);
+            coords += translate;
+
+            // and set it
+            m_caret->Move(coords);
+#endif // WXLAYOUT_USE_CARET
+
+         m_movedCursor = false;
+      }
+   }
+}
+
+wxPoint
+wxLayoutList::GetCursorScreenPos(wxDC &dc)
+{
+   // this function is called with wxMemoryDC argument from ScrollToCursor(),
+   // for example, so it shouldn't clear "cursor moved" flag - or else the
+   // cursor won't be moved when UpdateCursorScreenPos() is called with the
+   // "real" (i.e. the one used for drawing) wxDC.
+   UpdateCursorScreenPos(dc, false /* don't reset the flag */);
+
+   return m_CursorScreenPos;
+}
+
+/*
+  Is called before each Draw(). Now, it will re-layout all lines which
+  have changed.
+*/
+void
+wxLayoutList::Layout(wxDC &dc, CoordType bottom, bool forceAll)
+{
+   // first, make sure everything is calculated - this might not be
+   // needed, optimise it later
+   ApplyStyle(m_DefaultStyleInfo, dc);
+
+   // This one we always Layout() to get the current cursor
+   // coordinates on the screen:
+   m_CursorLine->MarkDirty();
+   bool wasDirty = false;
+   wxLayoutLine *line = m_FirstLine;
+   while(line)
+   {
+      if(! wasDirty)
+         ApplyStyle(line->GetStyleInfo(), dc);
+      if(forceAll || line->IsDirty())
+      {
+         // The following Layout() calls will update our
+         // m_CurrentStyleInfo if needed.
+         if(line == m_CursorLine)
+            line->Layout(dc, this,
+                         (wxPoint *)&m_CursorScreenPos,
+                         (wxPoint *)&m_CursorSize, m_CursorPos.x);
+         else
+            line->Layout(dc, this);
+
+         // little condition to speed up redrawing:
+         if(bottom != -1 && line->GetPosition().y > bottom)
+            break;
+         wasDirty = true;
+      }
+      line->RecalculatePositions(1, this);
+      line = line->GetNextLine();
+   }
+
+   // can only be 0 if we are on the first line and have no next line
+   wxASSERT(m_CursorSize.x != 0 || (m_CursorLine &&
+                                    m_CursorLine->GetNextLine() == NULL &&
+                                    m_CursorLine == m_FirstLine));
+   AddCursorPosToUpdateRect();
+}
+
+void
+wxLayoutList::Draw(wxDC &dc,
+                   wxPoint const &offset,
+                   CoordType top,
+                   CoordType bottom)
+{
+   wxLayoutLine *line = m_FirstLine;
+
+   /* We need to re-layout all dirty lines to update styleinfos
+      etc. However, somehow we don't find all dirty lines... */
+   Layout(dc); //,-1,true); //FIXME
+   ApplyStyle(m_DefaultStyleInfo, dc);
+   wxBrush brush(m_CurrentStyleInfo.m_bg, wxSOLID);
+   dc.SetBrush(brush);
+   dc.SetBackgroundMode(wxTRANSPARENT);
+
+   bool style_set = false;
+   while(line)
+   {
+      // only draw if between top and bottom:
+      if((top == -1 ||
+          line->GetPosition().y + line->GetHeight() >= top))
+      {
+//         if(! style_set)
+         {
+            ApplyStyle(line->GetStyleInfo(), dc);
+            style_set = true;
+         }
+         line->Draw(dc, this, offset);
+      }
+#if 0
+         else
+         line->Layout(dc, this);
+#endif
+         // little condition to speed up redrawing:
+      if(bottom != -1 && line->GetPosition().y > bottom) break;
+      line = line->GetNextLine();
+   }
+   InvalidateUpdateRect();
+
+   WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
+               m_Selection.m_valid ? "valid" : "invalid",
+               m_Selection.m_CursorA.x, m_Selection.m_CursorA.y,
+               m_Selection.m_CursorB.x, m_Selection.m_CursorB.y));
+}
+
+wxLayoutObject *
+wxLayoutList::FindObjectScreen(wxDC &dc, wxPoint const pos,
+                               wxPoint *cursorPos,
+                               bool *found)
+{
+   // First, find the right line:
+   wxLayoutLine *line = m_FirstLine;
+   wxPoint p;
+
+   ApplyStyle(m_DefaultStyleInfo, dc);
+   while(line)
+   {
+      p = line->GetPosition();
+      if(p.y <= pos.y && p.y+line->GetHeight() >= pos.y)
+         break;
+#if 0
+      // we need to run a layout here to get font sizes right :-(
+
+      // VZ: we can't call Layout() from here because it marks the line as
+      //     clean and it is not refreshed when it's called from wxLayoutList::
+      //     Layout() - if we really need to do this, we should introduce an
+      //     extra argument to Layout() to prevent the line from MarkClean()ing
+      //     itself here
+      line->Layout(dc, this);
+#endif
+      line = line->GetNextLine();
+   }
+   if(line == NULL)
+   {
+      if(found) *found = false;
+      return NULL; // not found
+   }
+   if(cursorPos) cursorPos->y = line->GetLineNumber();
+   // Now, find the object in the line:
+   wxLOiterator i = line->FindObjectScreen(dc, pos.x,
+                                           cursorPos ? & cursorPos->x : NULL ,
+                                           found);
+   return (i == NULLIT) ? NULL : *i;
+
+}
+
+wxPoint
+wxLayoutList::GetSize(void) const
+{
+   wxLayoutLine
+      *line = m_FirstLine,
+      *last = line;
+   if(! line)
+      return wxPoint(0,0);
+
+   wxPoint maxPoint(0,0);
+
+   // find last line:
+   while(line)
+   {
+      if(line->GetWidth() > maxPoint.x)
+          maxPoint.x = line->GetWidth();
+      last = line;
+      line = line->GetNextLine();
+   }
+
+   maxPoint.y = last->GetPosition().y + last->GetHeight();
+
+   // if the line was just added, its height would be 0 and we can't call
+   // Layout() from here because we don't have a dc and we might be not drawing
+   // at all, besides... So take the cursor height by default (taking 0 is bad
+   // because then the scrollbars won't be resized and the new line won't be
+   // shown at all)
+   if ( last->IsDirty() )
+   {
+      if ( last->GetHeight() == 0 )
+         maxPoint.y += m_CursorSize.y;
+      if ( last->GetWidth() == 0 && maxPoint.x < m_CursorSize.x )
+         maxPoint.x = m_CursorSize.x;
+   }
+
+   return maxPoint;
+}
+
+
+void
+wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
+{
+   wxPoint coords(m_CursorScreenPos);
+   coords += translate;
+
+#ifdef WXLAYOUT_DEBUG
+   WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
+               (long)m_CursorPos.x, (long)m_CursorPos.y,
+               (long)coords.x, (long)coords.y,
+               (long)m_CursorSize.x, (long)m_CursorSize.y,
+               (long)m_CursorLine->GetLineNumber(),
+               (long)m_CursorLine->GetLength()));
+
+   wxLogStatus("Cursor is at (%d, %d)", m_CursorPos.x, m_CursorPos.y);
+#endif
+
+#ifndef WXLAYOUT_USE_CARET
+   dc.SetBrush(*wxBLACK_BRUSH);
+   dc.SetLogicalFunction(wxXOR);
+   dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
+   if(active)
+   {
+      dc.DrawRectangle(coords.x, coords.y,
+                       m_CursorSize.x, m_CursorSize.y);
+      SetUpdateRect(coords.x, coords.y);
+      SetUpdateRect(coords.x+m_CursorSize.x, coords.y+m_CursorSize.y);
+   }
+   else
+   {
+      dc.DrawLine(coords.x, coords.y+m_CursorSize.y-1,
+                  coords.x, coords.y);
+      SetUpdateRect(coords.x, coords.y+m_CursorSize.y-1);
+      SetUpdateRect(coords.x, coords.y);
+   }
+   dc.SetLogicalFunction(wxCOPY);
+   //dc.SetBrush(wxNullBrush);
+#endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
+}
+
+void
+wxLayoutList::SetUpdateRect(CoordType x, CoordType y)
+{
+   if(m_UpdateRectValid)
+      GrowRect(m_UpdateRect, x, y);
+   else
+   {
+      m_UpdateRect.x = x;
+      m_UpdateRect.y = y;
+      m_UpdateRect.width = 4; // large enough to avoid surprises from
+      m_UpdateRect.height = 4;// wxGTK :-)
+      m_UpdateRectValid = true;
+   }
+}
+
+void
+wxLayoutList::StartSelection(const wxPoint& cposOrig, const wxPoint& spos)
+{
+   wxPoint cpos(cposOrig);
+   if ( cpos.x == -1 )
+      cpos = m_CursorPos;
+   WXLO_DEBUG(("Starting selection at %ld/%ld", cpos.x, cpos.y));
+   m_Selection.m_CursorA = cpos;
+   m_Selection.m_CursorB = cpos;
+   m_Selection.m_ScreenA = spos;
+   m_Selection.m_ScreenB = spos;
+   m_Selection.m_selecting = true;
+   m_Selection.m_valid = false;
+}
+
+void
+wxLayoutList::ContinueSelection(const wxPoint& cposOrig, const wxPoint& spos)
+{
+   wxPoint cpos(cposOrig);
+   if(cpos.x == -1)
+      cpos = m_CursorPos;
+
+   wxASSERT(m_Selection.m_selecting == true);
+   wxASSERT(m_Selection.m_valid == false);
+   WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos.x, cpos.y));
+
+   if ( m_Selection.m_CursorB <= cpos )
+   {
+      m_Selection.m_ScreenB = spos;
+      m_Selection.m_CursorB = cpos;
+   }
+   else
+   {
+      m_Selection.m_ScreenA = spos;
+      m_Selection.m_CursorA = cpos;
+   }
+
+   // we always want m_CursorA <= m_CursorB!
+   if( m_Selection.m_CursorA > m_Selection.m_CursorB )
+   {
+      // exchange the start/end points
+      wxPoint help = m_Selection.m_CursorB;
+      m_Selection.m_CursorB = m_Selection.m_CursorA;
+      m_Selection.m_CursorA = help;
+
+      help = m_Selection.m_ScreenB;
+      m_Selection.m_ScreenB = m_Selection.m_ScreenA;
+      m_Selection.m_ScreenA = help;
+   }
+}
+
+void
+wxLayoutList::EndSelection(const wxPoint& cposOrig, const wxPoint& spos)
+{
+   wxPoint cpos(cposOrig);
+   if(cpos.x == -1)
+      cpos = m_CursorPos;
+   ContinueSelection(cpos);
+   WXLO_DEBUG(("Ending selection at %ld/%ld", cpos.x, cpos.y));
+   m_Selection.m_selecting = false;
+   m_Selection.m_valid = true;
+}
+
+void
+wxLayoutList::DiscardSelection()
+{
+   if ( !HasSelection() )
+      return;
+
+   m_Selection.m_valid =
+   m_Selection.m_selecting = false;
+
+   // invalidate the area which was previousle selected - and which is not
+   // selected any more
+   if ( m_Selection.HasValidScreenCoords() )
+   {
+      SetUpdateRect(m_Selection.m_ScreenA);
+      SetUpdateRect(m_Selection.m_ScreenB);
+   }
+   else
+   {
+       // TODO
+   }
+}
+
+bool
+wxLayoutList::IsSelecting(void)
+{
+   return m_Selection.m_selecting;
+}
+
+bool
+wxLayoutList::IsSelected(const wxPoint &cursor)
+{
+   if ( !HasSelection() )
+      return false;
+
+   return m_Selection.m_CursorA <= cursor && cursor <= m_Selection.m_CursorB;
+}
+
+
+/** Tests whether this layout line is selected and needs
+    highlighting.
+    @param line to test for
+    @return 0 = not selected, 1 = fully selected, -1 = partially
+    selected
+    */
+int
+wxLayoutList::IsSelected(const wxLayoutLine *line, CoordType *from,
+                         CoordType *to)
+{
+   wxASSERT(line); wxASSERT(to); wxASSERT(from);
+
+   if(! m_Selection.m_valid && ! m_Selection.m_selecting)
+      return 0;
+
+   CoordType y = line->GetLineNumber();
+   if(m_Selection.m_CursorA.y < y && m_Selection.m_CursorB.y > y)
+      return 1;
+   else if(m_Selection.m_CursorA.y == y)
+   {
+      *from = m_Selection.m_CursorA.x;
+      if(m_Selection.m_CursorB.y == y)
+         *to = m_Selection.m_CursorB.x;
+      else
+         *to = line->GetLength();
+      return -1;
+   }
+   else if(m_Selection.m_CursorB.y == y)
+   {
+      *to = m_Selection.m_CursorB.x;
+      if(m_Selection.m_CursorA.y == y)
+         *from = m_Selection.m_CursorA.x;
+      else
+         *from = 0;
+      return -1;
+   }
+   else
+      return 0;
+}
+
+void
+wxLayoutList::DeleteSelection(void)
+{
+   if(! m_Selection.m_valid)
+      return;
+
+   m_Selection.m_valid = false;
+
+   // Only delete part of the current line?
+   if(m_Selection.m_CursorA.y == m_Selection.m_CursorB.y)
+   {
+      MoveCursorTo(m_Selection.m_CursorA);
+      Delete(m_Selection.m_CursorB.x - m_Selection.m_CursorA.x);
+      return;
+   }
+
+
+   wxLayoutLine
+      * firstLine = NULL,
+      * lastLine = NULL;
+
+   for(firstLine = m_FirstLine;
+       firstLine && firstLine->GetLineNumber() < m_Selection.m_CursorA.y;
+       firstLine=firstLine->GetNextLine())
+      ;
+   if(!firstLine || firstLine->GetLineNumber() != m_Selection.m_CursorA.y)
+      return;
+
+
+   for(lastLine = m_FirstLine;
+       lastLine && lastLine->GetLineNumber() < m_Selection.m_CursorB.y;
+       lastLine=lastLine->GetNextLine())
+      ;
+   if(!lastLine || lastLine->GetLineNumber() != m_Selection.m_CursorB.y)
+      return;
+
+
+   // We now know that the two lines are different:
+
+   // First, delete what's left of this line:
+   MoveCursorTo(m_Selection.m_CursorA);
+   DeleteToEndOfLine();
+
+   wxLayoutLine *nextLine = firstLine->GetNextLine();
+   while(nextLine && nextLine != lastLine)
+      nextLine = nextLine->DeleteLine(false, this);
+
+   // Now nextLine = lastLine;
+   Delete(1); // This joins firstLine and nextLine
+   Delete(m_Selection.m_CursorB.x); // This deletes the first x
+   // positions
+
+   /// Recalculate:
+   firstLine->RecalculatePositions(1, this);
+}
+
+/// Starts highlighting the selection
+void
+wxLayoutList::StartHighlighting(wxDC &dc)
+{
+#if SHOW_SELECTIONS
+   dc.SetTextForeground(m_CurrentStyleInfo.m_bg);
+   dc.SetTextBackground(m_CurrentStyleInfo.m_fg);
+   dc.SetBackgroundMode(wxSOLID);
+#endif
+}
+
+/// Ends highlighting the selection
+void
+wxLayoutList::EndHighlighting(wxDC &dc)
+{
+#if SHOW_SELECTIONS
+   dc.SetTextForeground(m_CurrentStyleInfo.m_fg);
+   dc.SetTextBackground(m_CurrentStyleInfo.m_bg);
+   dc.SetBackgroundMode(wxTRANSPARENT);
+#endif
+}
+
+
+wxLayoutList *
+wxLayoutList::Copy(const wxPoint &from,
+                   const wxPoint &to)
+{
+   wxLayoutLine
+      * firstLine = NULL,
+      * lastLine = NULL;
+
+   for(firstLine = m_FirstLine;
+       firstLine && firstLine->GetLineNumber() < from.y;
+       firstLine=firstLine->GetNextLine())
+      ;
+   if(!firstLine || firstLine->GetLineNumber() != from.y)
+      return NULL;
+
+   for(lastLine = m_FirstLine;
+       lastLine && lastLine->GetLineNumber() < to.y;
+       lastLine=lastLine->GetNextLine())
+      ;
+   if(!lastLine || lastLine->GetLineNumber() != to.y)
+      return NULL;
+
+   if(to <= from)
+   {
+      wxLayoutLine *tmp = firstLine;
+      firstLine = lastLine;
+      lastLine = tmp;
+   }
+
+   wxLayoutList *llist = new wxLayoutList();
+
+   if(firstLine == lastLine)
+   {
+      firstLine->Copy(llist, from.x, to.x);
+   }
+   else
+   {
+      // Extract objects from first line
+      firstLine->Copy(llist, from.x);
+      llist->LineBreak();
+      // Extract all lines between
+      for(wxLayoutLine *line = firstLine->GetNextLine();
+          line != lastLine;
+          line = line->GetNextLine())
+      {
+         line->Copy(llist);
+         llist->LineBreak();
+      }
+      // Extract objects from last line
+      lastLine->Copy(llist, 0, to.x);
+   }
+   return llist;
+}
+
+wxLayoutList *
+wxLayoutList::GetSelection(wxLayoutDataObject *wxlo, bool invalidate)
+{
+   if(! m_Selection.m_valid)
+   {
+      if(m_Selection.m_selecting)
+         EndSelection();
+      else
+         return NULL;
+   }
+
+   if(invalidate) m_Selection.m_valid = false;
+
+   wxLayoutList *llist = Copy( m_Selection.m_CursorA,
+                               m_Selection.m_CursorB );
+
+   if(llist && wxlo) // export as data object, too
+   {
+      wxString string;
+
+      wxLayoutExportObject *export;
+      wxLayoutExportStatus status(llist);
+      while((export = wxLayoutExport( &status, WXLO_EXPORT_AS_OBJECTS)) != NULL)
+      {
+         if(export->type == WXLO_EXPORT_EMPTYLINE)
+            ; //FIXME missing support for linebreaks in string format
+         else
+            export->content.object->Write(string);
+         delete export;
+      }
+
+      wxlo->SetData(string.c_str(), string.Length()+1);
+   }
+   return llist;
+}
+
+
+
+#define COPY_SI(what) if(si.what != -1) { m_CurrentStyleInfo.what = si.what; fontChanged = TRUE; }
+
+void
+wxLayoutList::ApplyStyle(wxLayoutStyleInfo const &si, wxDC &dc)
+{
+   bool fontChanged = FALSE;
+   COPY_SI(family);
+   COPY_SI(size);
+   COPY_SI(style);
+   COPY_SI(weight);
+   COPY_SI(underline);
+   if(fontChanged)
+      dc.SetFont( m_FontCache.GetFont(m_CurrentStyleInfo) );
+
+   if(si.m_fg_valid)
+   {
+      m_CurrentStyleInfo.m_fg = si.m_fg;
+      dc.SetTextForeground(m_CurrentStyleInfo.m_fg);
+   }
+   if(si.m_bg_valid)
+   {
+      m_CurrentStyleInfo.m_bg = si.m_bg;
+      dc.SetTextBackground(m_CurrentStyleInfo.m_bg);
+   }
+}
+
+
+#ifdef WXLAYOUT_DEBUG
+
+void
+wxLayoutList::Debug(void)
+{
+   WXLO_DEBUG(("Cursor is in line %d, screen pos = (%d, %d)",
+               m_CursorLine->GetLineNumber(),
+               m_CursorScreenPos.x, m_CursorScreenPos.y));
+
+   wxLayoutLine *line;
+   for(line = m_FirstLine; line; line = line->GetNextLine())
+   {
+      line->Debug();
+   }
+}
+
+#endif
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   wxLayoutPrintout
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+wxLayoutPrintout::wxLayoutPrintout(wxLayoutList *llist,
+                                   wxString const & title)
+:wxPrintout(title)
+{
+   m_llist = llist;
+   m_title = title;
+   // remove any highlighting which could interfere with printing:
+   m_llist->StartSelection();
+   m_llist->EndSelection();
+}
+
+wxLayoutPrintout::~wxLayoutPrintout()
+{
+}
+
+float
+wxLayoutPrintout::ScaleDC(wxDC *dc)
+{
+   // The following bit is taken from the printing sample, let's see
+   // whether it works for us.
+
+   /* You might use THIS code to set the printer DC to ROUGHLY reflect
+    * the screen text size. This page also draws lines of actual length 5cm
+    * on the page.
+    */
+  // Get the logical pixels per inch of screen and printer
+   int ppiScreenX, ppiScreenY;
+   GetPPIScreen(&ppiScreenX, &ppiScreenY);
+   int ppiPrinterX, ppiPrinterY;
+   GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
+
+   if(ppiScreenX == 0) // not yet set, need to guess
+   {
+      ppiScreenX = 100;
+      ppiScreenY = 100;
+   }
+   if(ppiPrinterX == 0) // not yet set, need to guess
+   {
+      ppiPrinterX = 72;
+      ppiPrinterY = 72;
+   }
+
+  // This scales the DC so that the printout roughly represents the
+  // the screen scaling. The text point size _should_ be the right size
+  // but in fact is too small for some reason. This is a detail that will
+  // need to be addressed at some point but can be fudged for the
+  // moment.
+  float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
+
+  // Now we have to check in case our real page size is reduced
+  // (e.g. because we're drawing to a print preview memory DC)
+  int pageWidth, pageHeight;
+  int w, h;
+  dc->GetSize(&w, &h);
+  GetPageSizePixels(&pageWidth, &pageHeight);
+  if(pageWidth != 0) // doesn't work always
+  {
+     // If printer pageWidth == current DC width, then this doesn't
+     // change. But w might be the preview bitmap width, so scale down.
+     scale = scale * (float)(w/(float)pageWidth);
+  }
+  dc->SetUserScale(scale, scale);
+  return scale;
+}
+
+bool wxLayoutPrintout::OnPrintPage(int page)
+{
+   wxDC *dc = GetDC();
+
+   ScaleDC(dc);
+
+   if (dc)
+   {
+      int top, bottom;
+      top = (page - 1)*m_PrintoutHeight;
+      bottom = top + m_PrintoutHeight;
+      // SetDeviceOrigin() doesn't work here, so we need to manually
+      // translate all coordinates.
+      wxPoint translate(m_Offset.x,m_Offset.y-top);
+      m_llist->Draw(*dc, translate, top, bottom);
+      return true;
+   }
+   else
+      return false;
+}
+
+void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
+{
+   /* We allocate a temporary wxDC for printing, so that we can
+      determine the correct paper size and scaling. We don't actually
+      print anything on it. */
+#ifdef __WXMSW__
+   wxPrinterDC psdc("","",WXLLIST_TEMPFILE,false);
+#else
+   wxPostScriptDC psdc(WXLLIST_TEMPFILE,false);
+#endif
+
+   float scale = ScaleDC(&psdc);
+
+   psdc.GetSize(&m_PageWidth, &m_PageHeight);
+   // This sets a left/top origin of 15% and 20%:
+   m_Offset = wxPoint((15*m_PageWidth)/100, m_PageHeight/20);
+
+   // This is the length of the printable area.
+   m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.15);
+   m_PrintoutHeight = (int)( m_PrintoutHeight / scale); // we want to use the real paper height
+
+
+   m_NumOfPages = 1 +
+      (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight));
+
+   *minPage = 1;
+   *maxPage = m_NumOfPages;
+
+   *selPageFrom = 1;
+   *selPageTo = m_NumOfPages;
+   wxRemoveFile(WXLLIST_TEMPFILE);
+}
+
+bool wxLayoutPrintout::HasPage(int pageNum)
+{
+   return pageNum <= m_NumOfPages;
+}
+
+/*
+  Stupid wxWindows doesn't draw proper ellipses, so we comment this
+  out. It's a waste of paper anyway.
+*/
+#if 0
+void
+wxLayoutPrintout::DrawHeader(wxDC &dc,
+                             wxPoint topleft, wxPoint bottomright,
+                             int pageno)
+{
+   // make backups of all essential parameters
+   const wxBrush& brush = dc.GetBrush();
+   const wxPen&   pen = dc.GetPen();
+   const wxFont&  font = dc.GetFont();
+
+   dc.SetBrush(*wxWHITE_BRUSH);
+   dc.SetPen(wxPen(*wxBLACK,0,wxSOLID));
+   dc.DrawRoundedRectangle(topleft.x,
+                           topleft.y,bottomright.x-topleft.x,
+                           bottomright.y-topleft.y);
+   dc.SetBrush(*wxBLACK_BRUSH);
+   wxFont myfont = wxFont((WXLO_DEFAULTFONTSIZE*12)/10,
+                          wxSWISS,wxNORMAL,wxBOLD,false,"Helvetica");
+   dc.SetFont(myfont);
+
+   wxString page;
+   page = "9999/9999  ";  // many pages...
+   long w,h;
+   dc.GetTextExtent(page,&w,&h);
+   page.Printf("%d/%d", pageno, (int) m_NumOfPages);
+   dc.DrawText(page,bottomright.x-w,topleft.y+h/2);
+   dc.GetTextExtent("XXXX", &w,&h);
+   dc.DrawText(m_title, topleft.x+w,topleft.y+h/2);
+
+   // restore settings
+   dc.SetPen(pen);
+   dc.SetBrush(brush);
+   dc.SetFont(font);
+}
+#endif
+
+
+wxFont &
+wxFontCache::GetFont(int family, int size, int style, int weight,
+                     bool underline)
+{
+   for(wxFCEList::iterator i = m_FontList.begin();
+       i != m_FontList.end(); i++)
+      if( (**i).Matches(family, size, style, weight, underline) )
+         return (**i).GetFont();
+   // not found:
+   wxFontCacheEntry *fce = new wxFontCacheEntry(family, size, style,
+                                                weight, underline);
+   m_FontList.push_back(fce);
+   return fce->GetFont();
+}
+
diff --git a/samples/richedit/wxllist.h b/samples/richedit/wxllist.h
new file mode 100644 (file)
index 0000000..5bc7fba
--- /dev/null
@@ -0,0 +1,1221 @@
+/*-*- c++ -*-********************************************************
+ * wxLayoutList.h - a formatted text rendering engine for wxWindows *
+ *                                                                  *
+ * (C) 1999 by Karsten Ballüder (Ballueder@usa.net)                 *
+ *                                                                  *
+ * $Id$
+ *******************************************************************/
+
+
+#ifndef WXLLIST_H
+#define WXLLIST_H
+
+#ifdef __GNUG__
+#   pragma interface "wxllist.h"
+#endif
+
+#include   "kbList.h"
+
+#include   "wx/wx.h"
+#include   "wx/print.h"
+#include   "wx/printdlg.h"
+#include   "wx/generic/printps.h"
+#include   "wx/generic/prntdlgg.h"
+#include   "wx/dataobj.h"
+
+// skip the following defines if embedded in M application
+#ifndef   M_BASEDIR
+#   define WXMENU_LAYOUT_LCLICK     1111
+#   define WXMENU_LAYOUT_RCLICK     1112
+#   define WXMENU_LAYOUT_DBLCLICK   1113
+#endif
+
+// use the wxWindows caret class instead of home grown cursor whenever possible
+#ifdef __WXMSW__
+    #undef WXLAYOUT_USE_CARET
+    #define WXLAYOUT_USE_CARET 1
+#endif // __WXMSW__
+
+// do not enable debug mode within Mahogany
+#if defined(__WXDEBUG__)  && ! defined(M_BASEDIR)
+#   define   WXLAYOUT_DEBUG
+#endif
+
+#ifdef WXLAYOUT_DEBUG
+#   define WXLO_TRACE(x)   wxLogDebug(x)
+#else
+#   define WXLO_TRACE(x)
+#endif
+
+#define WXLO_DEBUG_URECT 0
+
+#ifndef WXLO_DEFAULTFONTSIZE
+#   define WXLO_DEFAULTFONTSIZE 12
+#endif
+
+#ifdef __WXMSW__
+#   define WXLO_BITMAP_FORMAT wxBITMAP_TYPE_BMP
+#else
+#   define WXLO_BITMAP_FORMAT wxBITMAP_TYPE_PNG
+#endif
+
+/// Types of currently supported layout objects.
+enum wxLayoutObjectType
+{
+   /// illegal object type, should never appear
+   WXLO_TYPE_INVALID = 0,
+   /// text object, containing normal text
+   WXLO_TYPE_TEXT,
+   /// command object, containing font or colour changes
+   WXLO_TYPE_CMD,
+   /// icon object, any kind of image
+   WXLO_TYPE_ICON
+};
+
+/// Type used for coordinates in drawing. Must be signed.
+typedef long CoordType;
+
+// Forward declarations.
+class wxLayoutList;
+class wxLayoutLine;
+class wxLayoutObject;
+
+class WXDLLEXPORT wxCaret;
+class WXDLLEXPORT wxColour;
+class WXDLLEXPORT wxDC;
+class WXDLLEXPORT wxFont;
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   The wxLayout objects which make up the lines.
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/** The base class defining the interface to each object which can be
+    part of the layout. Each object needs to draw itself and calculate
+    its size.
+*/
+class wxLayoutObject
+{
+public:
+   /** This structure can be used to contain data associated with the
+       object.
+       It is refcounted, so the caller has to do a DecRef() on it
+       instead of a delete.
+   */
+   struct UserData
+   {
+      UserData() { m_refcount = 1; }
+      inline void IncRef(void) { m_refcount++; }
+      inline void DecRef(void) { m_refcount--; if(m_refcount == 0) delete this;}
+      inline void SetLabel(const wxString &l) { m_label = l; }
+      inline const wxString & GetLabel(void) const { return m_label; }
+   private:
+      int m_refcount;
+      wxString m_label;
+   protected:
+      virtual ~UserData() { wxASSERT(m_refcount == 0); }
+      /// prevents gcc from generating stupid warnings
+      friend class dummy_UserData;
+   };
+
+   /// return the type of this object
+   virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_INVALID; }
+   /** Calculates the size of an object.
+       @param dc the wxDC to draw on
+       @param llist the wxLayoutList
+   */
+   virtual void Layout(wxDC &dc, wxLayoutList *llist) = 0;
+
+   /** Draws an object.
+       @param dc the wxDC to draw on
+       @param coords where to draw the baseline of the object.
+       @param wxllist pointer to wxLayoutList
+       @param begin if !=-1, from which position on to highlight it
+       @param end if begin !=-1, how many positions to highlight it
+   */
+   virtual void Draw(wxDC & /* dc */,
+                     wxPoint const & /* coords */,
+                     wxLayoutList *wxllist,
+                     CoordType begin = -1,
+                     CoordType end = -1)  { }
+
+   /** Calculates and returns the size of the object.
+       @param top where to store height above baseline
+       @param bottom where to store height below baseline
+       @return the size of the object's box in pixels
+   */
+   virtual wxPoint GetSize(CoordType * top, CoordType *bottom) const
+      { *top = 0; *bottom = 0; return wxPoint(0,0); }
+
+   /// Return just the width of the object on the screen.
+   virtual CoordType GetWidth(void) const { return 0; }
+   /// returns the number of cursor positions occupied by this object
+   virtual CoordType GetLength(void) const { return 1; }
+   /** Returns the cursor offset relating to the screen x position
+       relative to begin of object.
+       @param dc the wxDC to use for calculations
+       @param xpos relative x position from head of object
+       @return cursor coordinate offset
+   */
+   virtual CoordType GetOffsetScreen(wxDC &dc, CoordType xpos) const { return 0; }
+
+   /// constructor
+   wxLayoutObject() { m_UserData = NULL; }
+   /// delete the user data
+   virtual ~wxLayoutObject() { if(m_UserData) m_UserData->DecRef(); }
+
+#ifdef WXLAYOUT_DEBUG
+   virtual void Debug(void);
+#endif
+
+   /** Tells the object about some user data. This data is associated
+       with the object and will be deleted at destruction time.
+       It is reference counted.
+   */
+   void   SetUserData(UserData *data)
+      {
+         if(m_UserData)
+            m_UserData->DecRef();
+         m_UserData = data;
+         if(m_UserData)
+            m_UserData->IncRef();
+      }
+
+   /** Return the user data.
+    Increments the object's reference count. When no longer needed,
+    caller must call DecRef() on the pointer returned.
+   */
+   UserData * GetUserData(void) const { if(m_UserData) m_UserData->IncRef(); return m_UserData; }
+
+   /** Makes a copy of this object.
+    */
+   virtual wxLayoutObject *Copy(void) = 0;
+
+   /** Clipboard support function. Read and write objects to
+       strings. */
+   //@{
+   /// Writes the object to the string.
+   virtual void Write(wxString &ostr) = 0;
+   /** Reads an object.
+       @param str stream to read from, will bee changed
+       @return true on success
+   */
+   static wxLayoutObject *Read(wxString &istr);
+   //@}
+protected:
+   /// optional data for application's use
+   UserData *m_UserData;
+};
+
+/// Define a list type of wxLayoutObject pointers.
+KBLIST_DEFINE(wxLayoutObjectList, wxLayoutObject);
+
+/// An illegal iterator to save typing.
+#define NULLIT (wxLayoutObjectList::iterator(NULL))
+/// The iterator type.
+#define wxLOiterator   wxLayoutObjectList::iterator
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   wxLayoutObjectText
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/** This class implements a wxLayoutObject holding plain text.
+ */
+class wxLayoutObjectText : public wxLayoutObject
+{
+public:
+   wxLayoutObjectText(const wxString &txt = "");
+
+   virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_TEXT; }
+   virtual void Layout(wxDC &dc, wxLayoutList *llist);
+   virtual void Draw(wxDC &dc, wxPoint const &coords,
+                     wxLayoutList *wxllist,
+                     CoordType begin = -1,
+                     CoordType end = -1);
+   /** Calculates and returns the size of the object.
+       @param top where to store height above baseline
+       @param bottom where to store height below baseline
+       @return the size of the object's box in pixels
+   */
+   virtual wxPoint GetSize(CoordType * top, CoordType *bottom) const;
+   /// Return just the width of the object on the screen.
+   virtual CoordType GetWidth(void) const { return m_Width; }
+   /** Returns the cursor offset relating to the screen x position
+       relative to begin of object.
+       @param dc the wxDC to use for calculations
+       @param xpos relative x position from head of object
+       @return cursor coordinate offset
+   */
+   virtual CoordType GetOffsetScreen(wxDC &dc, CoordType xpos) const;
+
+   virtual void Write(wxString &ostr);
+   static wxLayoutObjectText *Read(wxString &istr);
+
+#ifdef WXLAYOUT_DEBUG
+   virtual void Debug(void);
+#endif
+
+   virtual CoordType GetLength(void) const { return strlen(m_Text.c_str()); }
+
+   // for editing:
+   wxString & GetText(void) { return m_Text; }
+   void SetText(wxString const &text) { m_Text = text; }
+   /** Makes a copy of this object.
+    */
+   virtual wxLayoutObject *Copy(void);
+private:
+   wxString m_Text;
+   /// size of the box containing text
+   long   m_Width, m_Height;
+   /// Height above baseline.
+   long   m_Top;
+   /// Height below baseline.
+   long   m_Bottom;
+};
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   wxLayoutObjectIcon
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/** This class implements a wxLayoutObject holding a graphic.
+ */
+class wxLayoutObjectIcon : public wxLayoutObject
+{
+public:
+   wxLayoutObjectIcon(wxBitmap *icon = NULL);
+   wxLayoutObjectIcon(wxBitmap const &icon);
+
+   ~wxLayoutObjectIcon() { if(m_Icon) delete m_Icon; }
+
+   virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_ICON; }
+   virtual void Layout(wxDC &dc, wxLayoutList *llist);
+   virtual void Draw(wxDC &dc, wxPoint const &coords,
+                     wxLayoutList *wxllist,
+                     CoordType begin = -1,
+                     CoordType end = -1);
+
+   /** Calculates and returns the size of the object.
+       @param top where to store height above baseline
+       @param bottom where to store height below baseline
+       @return the size of the object's box in pixels
+   */
+   virtual wxPoint GetSize(CoordType * top, CoordType *bottom) const;
+   /// Return just the width of the object on the screen.
+   virtual CoordType GetWidth(void) const { return m_Icon->GetWidth(); }
+   // return a pointer to the icon
+   wxBitmap *GetIcon(void) const { return m_Icon; }
+   /** Makes a copy of this object.
+    */
+   virtual wxLayoutObject *Copy(void);
+   virtual void Write(wxString &ostr);
+   static wxLayoutObjectIcon *Read(wxString &istr);
+private:
+   wxBitmap *m_Icon;
+};
+
+/** This structure holds all formatting information. Members which are
+    undefined (for a CmdObject this means: no change), are set to -1.
+*/
+struct wxLayoutStyleInfo
+{
+   wxLayoutStyleInfo(int ifamily = -1,
+                     int isize = -1,
+                     int istyle = -1,
+                     int iweight = -1,
+                     int iul = -1,
+                     wxColour *fg = NULL,
+                     wxColour *bg = NULL);
+   wxColour & GetBGColour()
+      {
+         return m_bg;
+      }
+   wxLayoutStyleInfo & operator=(const wxLayoutStyleInfo &right);
+   /// Font change parameters.
+   int  size, family, style, weight, underline;
+   /// Colours
+   wxColour m_bg, m_fg;
+   int m_fg_valid, m_bg_valid; // bool, but must be int!
+};
+
+
+class wxFontCacheEntry
+{
+public:
+   wxFontCacheEntry(int family, int size, int style, int weight,
+                    bool underline)
+      {
+         m_Family = family; m_Size = size; m_Style = style;
+         m_Weight = weight; m_Underline = underline;
+         m_Font = new wxFont(m_Size, m_Family,
+                             m_Style, m_Weight, m_Underline);
+      }
+   bool Matches(int family, int size, int style, int weight,
+                bool underline) const
+      {
+         return size == m_Size && family == m_Family
+            && style == m_Style && weight == m_Weight
+            && underline == m_Underline;
+      }
+   wxFont & GetFont(void) { return *m_Font; }
+   ~wxFontCacheEntry()
+      {
+         delete m_Font;
+      }
+private:
+   wxFont *m_Font;
+   int  m_Family, m_Size, m_Style, m_Weight;
+   bool m_Underline;
+};
+
+KBLIST_DEFINE(wxFCEList, wxFontCacheEntry);
+
+class wxFontCache
+{
+public:
+   wxFont & GetFont(int family, int size, int style, int weight,
+                   bool underline);
+   wxFont & GetFont(wxLayoutStyleInfo const &si)
+      {
+         return GetFont(si.family, si.size, si.style, si.weight,
+                        si.underline != 0);
+      }
+private:
+   wxFCEList m_FontList;
+};
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   wxLayoutObjectCmd
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/** This class implements a wxLayoutObject holding style change commands.
+ */
+class wxLayoutObjectCmd : public wxLayoutObject
+{
+public:
+   virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_CMD; }
+   virtual void Layout(wxDC &dc, wxLayoutList *llist);
+   virtual void Draw(wxDC &dc, wxPoint const &coords,
+                     wxLayoutList *wxllist,
+                     CoordType begin = -1,
+                     CoordType end = -1);
+   wxLayoutObjectCmd(int family = -1,
+                     int size = -1,
+                     int style = -1,
+                     int weight = -1,
+                     int underline = -1,
+                     wxColour *fg = NULL,
+                     wxColour *bg = NULL);
+   ~wxLayoutObjectCmd();
+   /** Stores the current style in the styleinfo structure */
+   wxLayoutStyleInfo * GetStyle(void) const;
+   /** Makes a copy of this object.
+    */
+   virtual wxLayoutObject *Copy(void);
+   virtual void Write(wxString &ostr);
+   static wxLayoutObjectCmd *Read(wxString &istr);
+private:
+   wxLayoutStyleInfo *m_StyleInfo;
+};
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   The wxLayoutLine object
+
+   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/** This class represents a single line of objects to be displayed.
+    It knows its height and total size and whether it needs to be
+    redrawn or not.
+    It has pointers to its first and next line so it can automatically
+    update them as needed.
+*/
+class wxLayoutLine
+{
+public:
+   /** Constructor.
+       @param prev pointer to previous line or NULL
+       @param next pointer to following line or NULL
+       @param llist pointer to layout list
+   */
+   wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist);
+   /** This function inserts a new object at cursor position xpos.
+       @param xpos where to insert new object
+       @param obj  the object to insert
+       @return true if that xpos existed and the object was inserted
+   */
+   bool Insert(CoordType xpos, wxLayoutObject *obj);
+
+   /** This function inserts text at cursor position xpos.
+       @param xpos where to insert
+       @param text  the text to insert
+       @return true if that xpos existed and the object was inserted
+   */
+   bool Insert(CoordType xpos, const wxString& text);
+
+   /** This function appends an object to the line.
+       @param obj  the object to insert
+   */
+   void Append(wxLayoutObject * obj)
+      {
+         wxASSERT(obj);
+
+         m_ObjectList.push_back(obj);
+         m_Length += obj->GetLength();
+      }
+
+   /** This function appens the next line to this, i.e. joins the two
+       lines into one.
+   */
+   void MergeNextLine(wxLayoutList *llist);
+
+   /** This function deletes npos cursor positions from position xpos.
+       @param xpos where to delete
+       @param npos how many positions
+       @return number of positions still to be deleted
+   */
+   CoordType Delete(CoordType xpos, CoordType npos);
+
+   /** This function breaks the line at a given cursor position.
+       @param xpos where to break it
+       @return pointer to the new line object replacing the old one
+   */
+   wxLayoutLine *Break(CoordType xpos, wxLayoutList *llist);
+
+   /** Deletes the next word from this position, including leading
+       whitespace.
+       This function does not delete over font changes, i.e. a word
+       with formatting instructions in the middle of it is treated as
+       two (three actually!) words. In fact, if the cursor is on a non-text object, that
+       one is treated as a word.
+       @param xpos from where to delete
+       @return true if a word was deleted
+   */
+   bool DeleteWord(CoordType npos);
+
+   /** Finds a suitable position left to the given column to break the
+       line.
+       @param column we want to break the line to the left of this
+       @return column for breaking line or -1 if no suitable location found
+   */
+   CoordType GetWrapPosition(CoordType column);
+
+   /** Finds the object which covers the cursor position xpos in this
+       line.
+       @param xpos the column number
+       @param offset where to store the difference between xpos and
+       the object's head
+       @return iterator to the object or NULLIT
+   */
+   wxLayoutObjectList::iterator FindObject(CoordType xpos, CoordType
+                                           *offset) const ;
+
+   /** Finds the object which covers the screen position xpos in this
+       line.
+       @param dc the wxDC to use for calculations
+       @param xpos the screen x coordinate
+       @param offset where to store the difference between xpos and
+       the object's head
+       @return iterator to the object or NULLIT
+   */
+   wxLayoutObjectList::iterator FindObjectScreen(wxDC &dc,
+                                                 CoordType xpos,
+                                                 CoordType *offset,
+                                                 bool *found = NULL) const ;
+
+   /** Finds text in this line.
+       @param needle the text to find
+       @param xpos the position where to start the search
+       @return the cursoor coord where it was found or -1
+   */
+   CoordType FindText(const wxString &needle, CoordType xpos = 0) const;
+
+   /** Get the first object in the list. This is used by the wxlparser
+       functions to export the list.
+       @return iterator to the first object
+   */
+   wxLayoutObjectList::iterator GetFirstObject(void)
+      {
+         return m_ObjectList.begin();
+      }
+
+   /** Deletes this line, returns pointer to next line.
+       @param update If true, update all following lines.
+   */
+   wxLayoutLine *DeleteLine(bool update, wxLayoutList *llist);
+
+   /**@name Cursor Management */
+   //@{
+   /** Return the line number of this line.
+       @return the line number
+   */
+   inline CoordType GetLineNumber(void) const { return m_LineNumber; }
+   /** Return the length of the line.
+       @return line lenght in cursor positions
+   */
+   inline CoordType GetLength(void) const { return m_Length; }
+   //@}
+
+   /**@name Drawing and Layout */
+   //@{
+   /** Draws the line on a wxDC.
+       @param dc the wxDC to draw on
+       @param llist the wxLayoutList
+       @param offset an optional offset to shift printout
+   */
+   void Draw(wxDC &dc,
+             wxLayoutList *llist,
+             const wxPoint &offset = wxPoint(0,0)) const;
+
+   /** Recalculates the positions of objects and the height of the
+       line.
+       @param dc the wxDC to draw on
+       @param llist th   e wxLayoutList
+       @param cursorPos if not NULL, set cursor screen position in there
+       @param cursorSize if not cursorPos != NULL, set cursor size in there
+       @param cx if cursorPos != NULL, the cursor x position
+       @param suppressStyleUpdate FALSe normally, only to suppress updating of m_StyleInfo
+   */
+   void Layout(wxDC &dc,
+               wxLayoutList *llist,
+               wxPoint *cursorPos = NULL,
+               wxPoint *cursorSize = NULL,
+               int cx = 0,
+               bool suppressStyleUpdate = FALSE);
+   /** This function finds an object belonging to a given cursor
+       position. It assumes that Layout() has been called before.
+       @param dc the wxDC to use for calculations
+       @param xpos screen x position
+       @param found if non-NULL set to false if we return the last
+       object before the cursor, to true if we really have an object
+       for that position
+       @return pointer to the object
+   */
+   wxLayoutObject * FindObjectScreen(wxDC &dc, CoordType xpos, bool
+                                     *found = NULL);
+   /** This sets the style info for the beginning of this line.
+       @param si styleinfo structure
+    */
+   void ApplyStyle(const wxLayoutStyleInfo &si)
+      {   m_StyleInfo = si; }
+
+   //@}
+
+   /**@name List traversal */
+   //@{
+   /// Returns pointer to next line.
+   wxLayoutLine *GetNextLine(void) const { return m_Next; }
+   /// Returns pointer to previous line.
+   wxLayoutLine *GetPreviousLine(void) const { return m_Previous; }
+   /// Sets the link to the next line.
+   void SetNext(wxLayoutLine *next)
+      { m_Next = next; if(next) next->m_Previous = this; }
+   /// Sets the link to the previous line.
+   void SetPrevious(wxLayoutLine *previous)
+      { m_Previous = previous; if(previous) previous->m_Next = this; }
+   //@}
+
+   /// Returns the position of this line on the canvas.
+   wxPoint GetPosition(void) const { return m_Position; }
+   /// Returns the height of this line.
+   CoordType GetHeight(void) const { return m_Height; }
+   /// Returns the width of this line.
+   CoordType GetWidth(void) const { return m_Width; }
+   /** This will recalculate the position and size of this line.
+       If called recursively it will abort if the position of an
+       object is unchanged, assuming that none of the following
+       objects need to move.
+       @param recurse if greater 0 then it will be used as the
+       minimum(!) recursion level, continue with all lines till the end of
+       the list or until the coordinates no longer changed.
+   */
+   void RecalculatePositions(int recurse, wxLayoutList *llist);
+   /// Recalculates the position of this line on the canvas.
+   wxPoint RecalculatePosition(wxLayoutList *llist);
+
+   /** Copies the contents of this line to another wxLayoutList
+       @param llist the wxLayoutList destination
+       @param from x cursor coordinate where to start
+       @param to x cursor coordinate where to stop, -1 for end of line
+   */
+   void Copy(wxLayoutList *llist,
+             CoordType from = 0,
+             CoordType to = -1);
+
+#ifdef WXLAYOUT_DEBUG
+   void Debug(void);
+#endif
+   wxLayoutStyleInfo const & GetStyleInfo() const { return m_StyleInfo; }
+
+   /// Returns dirty state
+   bool IsDirty(void) const { return m_Dirty; }
+   /** Marks this line as diry.
+       @param left xpos from where it is dirty or -1 for all
+   */
+   void MarkDirty(CoordType left = -1)
+   {
+      if ( left != -1 )
+      {
+         if ( m_updateLeft == -1 || left < m_updateLeft )
+            m_updateLeft = left;
+      }
+
+      m_Dirty = true;
+   }
+   /** Marks the following lines as dirty.
+       @param recurse if -1 recurse to end of list, otherwise depth of recursion.
+   */
+   void MarkNextDirty(int recurse = 0);
+   /// Reset the dirty flag
+   void MarkClean() { m_Dirty = false; m_updateLeft = -1; }
+
+private:
+   /// Destructor is private. Use DeleteLine() to remove it.
+   ~wxLayoutLine();
+
+   /**@name Functions to let the lines synchronise with each other. */
+   //@{
+   /** Sets the height of this line. Will mark following lines as
+       dirty.
+       @param height new height
+   */
+   void SetHeight(CoordType height, wxLayoutList *llist)
+      { m_Height = height; RecalculatePositions(true, llist); }
+
+   /** Moves the linenumbers one on, because a line has been inserted
+       or deleted.
+       @param delta either +1 or -1
+    */
+   void MoveLines(int delta)
+      {
+         m_LineNumber += delta;
+         if(m_Next) m_Next->MoveLines(delta);
+      }
+   //@}
+private:
+   /// The line number.
+   CoordType m_LineNumber;
+   /// The line length in cursor positions.
+   CoordType m_Length;
+   /// The total height of the line.
+   CoordType m_Height;
+   /// The total width of the line on screen.
+   CoordType m_Width;
+   /// The baseline for drawing objects
+   CoordType m_BaseLine;
+   /// The position on the canvas.
+   wxPoint   m_Position;
+   /// The list of objects
+   wxLayoutObjectList m_ObjectList;
+   /// Have we been changed since the last layout?
+   bool m_Dirty;
+   /// The coordinate of the left boundary of the update rectangle (if m_Dirty)
+   CoordType m_updateLeft;
+   /// Pointer to previous line if it exists.
+   wxLayoutLine *m_Previous;
+   /// Pointer to next line if it exists.
+   wxLayoutLine *m_Next;
+   /// A StyleInfo structure, holding the current settings.
+   wxLayoutStyleInfo m_StyleInfo;
+   /// Just to suppress gcc compiler warnings.
+   friend class dummy;
+private:
+   wxLayoutLine(const wxLayoutLine &);
+};
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   The wxLayoutList object
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/** The wxLayoutList is a list of wxLayoutLine objects. It provides a
+    higher level of abstraction for the text and can generally be considered
+    as representing "the text".
+ */
+class wxLayoutList
+{
+public:
+   /// Constructor.
+   wxLayoutList();
+   /// Destructor.
+   ~wxLayoutList();
+
+#ifdef WXLAYOUT_USE_CARET
+   /// give us the pointer to the caret to use
+   void SetCaret(wxCaret *caret) { m_caret = caret; }
+#endif // WXLAYOUT_USE_CARET
+
+   /// Clear the list.
+   void Clear(int family = wxROMAN,
+              int size=WXLO_DEFAULTFONTSIZE,
+              int style=wxNORMAL,
+              int weight=wxNORMAL,
+              int underline=0,
+              wxColour *fg=NULL,
+              wxColour *bg=NULL);
+   /// Empty: clear the list but leave font settings.
+   void Empty(void);
+
+   /**@name Cursor Management */
+   //@{
+   /** Set new cursor position.
+       @param p new position
+       @return bool if it could be set
+   */
+   bool MoveCursorTo(wxPoint const &p);
+   /** Move cursor up or down.
+       @param n
+       @return bool if it could be moved
+   */
+   bool MoveCursorVertically(int n);
+   /** Move cursor left or right.
+       @param n = number of positions to move
+       @return bool if it could be moved
+   */
+   bool MoveCursorHorizontally(int n);
+   /** Move cursor to the left or right counting in words
+       @param n = number of positions in words
+       @return bool if it could be moved
+   */
+   bool MoveCursorWord(int n);
+
+   /// Move cursor to end of line.
+   void MoveCursorToEndOfLine(void)
+      {
+         wxASSERT(m_CursorLine);
+         MoveCursorHorizontally(m_CursorLine->GetLength()-m_CursorPos.x);
+      }
+
+   /// Move cursor to begin of line.
+   void MoveCursorToBeginOfLine(void)
+      { MoveCursorHorizontally(-m_CursorPos.x); }
+
+   /// Returns current cursor position.
+   const wxPoint &GetCursorPos(wxDC &dc) const { return m_CursorPos; }
+   const wxPoint &GetCursorPos() const { return m_CursorPos; }
+
+   //@}
+
+   /**@name Editing functions.
+    All of these functions return true on success and false on
+    failure. */
+   //@{
+   /// Insert text at current cursor position.
+   bool Insert(wxString const &text);
+   /// Insert some other object at current cursor position.
+   bool Insert(wxLayoutObject *obj);
+   /// Inserts objects at current cursor positions
+   bool Insert(wxLayoutList *llist);
+
+   /// Inserts a linebreak at current cursor position.
+   bool LineBreak(void);
+   /** Wraps the current line. Searches to the left of the cursor to
+       break the line. Does nothing if the cursor position is before
+       the break position parameter.
+       @param column the break position for the line, maximum length
+       @return true if line got broken
+   */
+   bool WrapLine(CoordType column);
+   /** This function deletes npos cursor positions.
+       @param npos how many positions
+       @return true if everything got deleted
+   */
+   bool Delete(CoordType npos);
+
+   /** Delete the next n lines.
+       @param n how many lines to delete
+       @return how many it could not delete
+   */
+   int DeleteLines(int n);
+
+   /// Delete to end of line.
+   void DeleteToEndOfLine(void)
+      {
+         wxASSERT(m_CursorLine);
+         Delete(m_CursorLine->GetLength()-m_CursorPos.x);
+      }
+   /// Delete to begin of line.
+   void DeleteToBeginOfLine(void)
+      {
+         wxASSERT(m_CursorLine);
+         CoordType n = m_CursorPos.x;
+#ifdef WXLAYOUT_DEBUG
+         wxASSERT(MoveCursorHorizontally(-n));
+#else
+         MoveCursorHorizontally(-n);
+#endif
+         Delete(n);
+      }
+
+   /** Delete the next word.
+   */
+   void DeleteWord(void)
+      {
+         wxASSERT(m_CursorLine);
+         m_CursorLine->DeleteWord(m_CursorPos.x);
+      }
+
+   //@}
+
+   /** Finds text in this list.
+       @param needle the text to find
+       @param cpos the position where to start the search
+       @return the cursor coord where it was found or (-1,-1)
+   */
+   wxPoint FindText(const wxString &needle, const wxPoint &cpos = wxPoint(0,0)) const;
+
+   /**@name Formatting options */
+   //@{
+   /// sets font parameters
+   void SetFont(int family, int size, int style,
+                int weight, int underline,
+                wxColour *fg,
+                wxColour *bg);
+   /// sets font parameters, colours by name
+   void SetFont(int family=-1, int size = -1, int style=-1,
+                int weight=-1, int underline = -1,
+                char const *fg = NULL,
+                char const *bg = NULL);
+   /// changes to the next larger font size
+   inline void SetFontLarger(void)
+      { SetFont(-1,(12*m_CurrentStyleInfo.size)/10); }
+   /// changes to the next smaller font size
+   inline void SetFontSmaller(void)
+      { SetFont(-1,(10*m_CurrentStyleInfo.size)/12); }
+
+   /// set font family
+   inline void SetFontFamily(int family) { SetFont(family); }
+   /// set font size
+   inline void SetFontSize(int size) { SetFont(-1,size); }
+   /// set font style
+   inline void SetFontStyle(int style) { SetFont(-1,-1,style); }
+   /// set font weight
+   inline void SetFontWeight(int weight) { SetFont(-1,-1,-1,weight); }
+   /// toggle underline flag
+   inline void SetFontUnderline(bool ul) { SetFont(-1,-1,-1,-1,(int)ul); }
+   /// set font colours by name
+   inline void SetFontColour(char const *fg, char const *bg = NULL)
+      { SetFont(-1,-1,-1,-1,-1,fg,bg); }
+   /// set font colours by colour
+   inline void SetFontColour(wxColour *fg, wxColour *bg = NULL)
+      { SetFont(-1,-1,-1,-1,-1,fg,bg); }
+
+
+   /**
+      Returns a pointer to the default settings.
+      This is only valid temporarily and should not be stored
+      anywhere.
+      @return the default settings of the list
+   */
+   wxLayoutStyleInfo &GetDefaultStyleInfo(void) { return m_DefaultStyleInfo ; }
+   wxLayoutStyleInfo &GetStyleInfo(void) { return m_CurrentStyleInfo ; }
+   //@}
+
+   /**@name Drawing */
+   //@{
+   /** Draws the complete list on a wxDC.
+       @param dc the wxDC to draw on
+       @param offset an optional offset to shift printout
+       @param top optional y coordinate where to start drawing
+       @param bottom optional y coordinate where to stop drawing
+   */
+   void Draw(wxDC &dc,
+             const wxPoint &offset = wxPoint(0,0),
+             CoordType top = -1, CoordType bottom = -1);
+
+   /** Calculates new layout for the list, like Draw() but does not
+       actually draw it.
+       @param dc the wxDC to draw on
+       @param bottom optional y coordinate where to stop calculating
+       @param forceAll force re-layout of all lines
+   */
+   void Layout(wxDC &dc, CoordType bottom = -1, bool forceAll = false);
+
+   /** Calculates new sizes for everything in the list, like Layout()
+       but this is needed after the list got changed.
+       @param dc the wxDC to draw on
+       @param bottom optional y coordinate where to stop calculating
+   */
+   void Recalculate(wxDC &dc, CoordType bottom = -1);
+
+   /** Returns the size of the list in screen coordinates.
+       The return value only makes sense after the list has been
+       drawn.
+       @return a wxPoint holding the maximal x/y coordinates used for
+       drawing
+   */
+   wxPoint GetSize(void) const;
+
+   /** Returns the cursor position on the screen.
+       @return cursor position in pixels
+   */
+   wxPoint GetCursorScreenPos(wxDC &dc);
+   /** Calculates the cursor position on the screen.
+       @param dc the dc to use for cursor position calculations
+       @param resetCursorMovedFlag: if true, reset "cursor moved" flag
+       @param translate optional translation of cursor coords on screen
+       
+   */
+   void UpdateCursorScreenPos(wxDC &dc,
+                              bool resetCursorMovedFlag = true,
+                              const wxPoint& translate = wxPoint(0,
+                                                                 0));
+
+   /** Draws the cursor.
+       @param active If true, draw a bold cursor to mark window as
+       active.
+       @param translate optional translation of cursor coords on screen
+   */
+   void DrawCursor(wxDC &dc,
+                   bool active = true,
+                   const wxPoint & translate = wxPoint(0,0));
+
+   /** This function finds an object belonging to a given screen
+       position. It assumes that Layout() has been called before.
+       @param pos screen position
+       @param cursorPos if non NULL, store cursor position in there
+       @param found if used, set this to true if we really found an
+       object, to false if we had to take the object near to it
+       @return pointer to the object
+   */
+   wxLayoutObject * FindObjectScreen(wxDC &dc,
+                                     wxPoint const pos,
+                                     wxPoint *cursorPos = NULL,
+                                     bool *found = NULL);
+
+   /** Called by the objects to update the update rectangle.
+       @param x horizontal coordinate to include in rectangle
+       @param y vertical coordinate to include in rectangle
+   */
+   void SetUpdateRect(CoordType x, CoordType y);
+   /** Called by the objects to update the update rectangle.
+       @param p a point to include in it
+   */
+   void SetUpdateRect(const wxPoint &p)
+      { SetUpdateRect(p.x,p.y); }
+   /// adds the cursor position to the update rectangle
+   void AddCursorPosToUpdateRect()
+   {
+      #ifndef WXLAYOUT_USE_CARET
+         SetUpdateRect(m_CursorScreenPos);
+         SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+      //#else - the caret will take care of refreshing itself
+      #endif // !WXLAYOUT_USE_CARET
+   }
+   /// Invalidates the update rectangle.
+   void InvalidateUpdateRect(void) { m_UpdateRectValid = false; }
+   /// Returns the update rectangle.
+   const wxRect *GetUpdateRect(void) const { return &m_UpdateRect; }
+   //@}
+
+   /// get the current cursor size
+   const wxPoint& GetCursorSize() const { return m_CursorSize; }
+
+   /**@name For exporting one object after another. */
+   //@{
+   /** Returns a pointer to the first line in the list. */
+   wxLayoutLine *GetFirstLine(void)
+      {
+         wxASSERT(m_FirstLine);
+         return m_FirstLine;
+      }
+   //@}
+
+   /// Begin selecting text
+   void StartSelection(const wxPoint& cpos = wxPoint(-1,-1),
+                       const wxPoint& spos = wxPoint(-1,-1));
+   // Continue selecting text
+   void ContinueSelection(const wxPoint& cpos = wxPoint(-1,-1),
+                          const wxPoint& spos = wxPoint(-1,-1));
+   /// End selecting text.
+   void EndSelection(const wxPoint& cpos = wxPoint(-1,-1),
+                     const wxPoint& spos = wxPoint(-1,-1));
+   /// Discard the current selection
+   void DiscardSelection();
+   /// Are we still selecting text?
+   bool IsSelecting(void);
+   /// Is the given point (text coords) selected?
+   bool IsSelected(const wxPoint &cursor);
+   /// Do we have a non null selection?
+   bool HasSelection() const
+      { return m_Selection.m_valid || m_Selection.m_selecting; }
+
+   /** Return the selection as a wxLayoutList.
+       @param invalidate if true, the selection will be invalidated after this and can no longer be used.
+       @return Another layout list object holding the selection, must be freed by caller
+   */
+   wxLayoutList *GetSelection(class wxLayoutDataObject *wxldo = NULL, bool invalidate = TRUE);
+   /// Delete selected bit
+   void DeleteSelection(void);
+
+   wxLayoutList *Copy(const wxPoint &from = wxPoint(0,0),
+                      const wxPoint &to = wxPoint(-1,-1));
+
+   /// starts highlighting of text for selections
+   void StartHighlighting(wxDC &dc);
+   /// ends highlighting of text for selections
+   void EndHighlighting(wxDC &dc);
+
+   /** Tests whether this layout line is selected and needs
+       highlighting.
+       @param line to test for
+       @param from set to first cursorpos to be highlighted (for returncode == -1)
+       @param to set to last cursorpos to be highlighted  (for returncode == -1)
+       @return 0 = not selected, 1 = fully selected, -1 = partially
+       selected
+
+   */
+   int IsSelected(const wxLayoutLine *line, CoordType *from, CoordType *to);
+
+   void ApplyStyle(wxLayoutStyleInfo const &si, wxDC &dc);
+#ifdef WXLAYOUT_DEBUG
+   void Debug(void);
+#endif
+
+private:
+   /// Clear the list.
+   void InternalClear(void);
+
+   /// The list of lines.
+   wxLayoutLine *m_FirstLine;
+   /// The update rectangle which needs to be refreshed:
+   wxRect  m_UpdateRect;
+   /// Is the update rectangle valid?
+   bool    m_UpdateRectValid;
+   /**@name Cursor Management */
+   //@{
+   /// Where the text cursor (column,line) is.
+   wxPoint   m_CursorPos;
+   /// Where the cursor should be drawn.
+   wxPoint   m_CursorScreenPos;
+   /// The line where the cursor is.
+   wxLayoutLine *m_CursorLine;
+   /// The size of the cursor.
+   wxPoint   m_CursorSize;
+   /// Has the cursor moved (is m_CursorScreenPos up to date)?
+   bool      m_movedCursor;
+#ifdef WXLAYOUT_USE_CARET
+   /// the caret
+   wxCaret  *m_caret;
+#endif // WXLAYOUT_USE_CARET
+   //@}
+
+   /// selection.state and begin/end coordinates
+   struct Selection
+   {
+      Selection() { m_valid = false; m_selecting = false; }
+      bool m_valid;
+      bool m_selecting;
+
+      // returns true if we already have the screen coordinates of the
+      // selection start and end
+      bool HasValidScreenCoords() const
+          { return m_ScreenA.x != -1 && m_ScreenB.x != -1; }
+
+      // the start and end of the selection coordinates in pixels
+      wxPoint m_ScreenA, m_ScreenB;
+
+      // these coordinates are in text positions, not in pixels
+      wxPoint m_CursorA, m_CursorB;
+   } m_Selection;
+   /** @name Font parameters. */
+   //@{
+   /// this object manages the fonts for us
+   wxFontCache m_FontCache;
+   /// the default setting:
+   wxLayoutStyleInfo m_DefaultStyleInfo;
+   /// the current setting:
+   wxLayoutStyleInfo m_CurrentStyleInfo;
+   //@}
+};
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   The wxLayoutDataObject for exporting data to the clipboard in our
+   own format.
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+class wxLayoutDataObject : public wxPrivateDataObject
+{
+public:
+   wxLayoutDataObject(void)
+      {
+         SetId("application/wxlayoutlist");
+         //m_format.SetAtom((GdkAtom) 222222);
+      }
+};
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+   The wxLayoutPrintout object for printing within the wxWindows print
+   framework.
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/** This class implements a wxPrintout for printing a wxLayoutList within
+    the wxWindows printing framework.
+ */
+class wxLayoutPrintout: public wxPrintout
+{
+public:
+   /** Constructor.
+       @param llist pointer to the wxLayoutList to be printed
+       @param title title for PS file or windows
+   */
+   wxLayoutPrintout(wxLayoutList *llist,
+                    wxString const & title =
+                    "wxLayout Printout");
+   /// Destructor.
+   ~wxLayoutPrintout();
+
+   /** Function which prints the n-th page.
+       @param page the page number to print
+       @return bool true if we are not at end of document yet
+   */
+   bool OnPrintPage(int page);
+   /** Checks whether page exists in document.
+       @param page number of page
+       @return true if page exists
+   */
+   bool HasPage(int page);
+
+   /** Gets called from wxWindows to find out which pages are existing.
+       I'm not totally sure about the parameters though.
+       @param minPage the first page in the document
+       @param maxPage the last page in the document
+       @param selPageFrom the first page to be printed
+       @param selPageTo the last page to be printed
+   */
+   void GetPageInfo(int *minPage, int *maxPage,
+                    int *selPageFrom, int *selPageTo);
+protected:
+   /** This little function scales the DC so that the printout has
+       roughly the same size as the output on screen.
+       @param dc the wxDC to scale
+       @return the scale that was applied
+   */
+   float ScaleDC(wxDC *dc);
+
+   /* no longer used
+     virtual void DrawHeader(wxDC &dc, wxPoint topleft, wxPoint bottomright, int pageno);
+   */
+private:
+   /// The list to print.
+   wxLayoutList *m_llist;
+   /// Title for PS file or window.
+   wxString      m_title;
+   /// The real paper size.
+   int           m_PageHeight, m_PageWidth;
+   /// How much we actually print per page.
+   int           m_PrintoutHeight;
+   /// How many pages we need to print.
+   int           m_NumOfPages;
+   /// Top left corner where we start printing.
+   wxPoint       m_Offset;
+};
+
+
+#endif // WXLLIST_H
diff --git a/samples/richedit/wxlparser.cpp b/samples/richedit/wxlparser.cpp
new file mode 100644 (file)
index 0000000..316247b
--- /dev/null
@@ -0,0 +1,265 @@
+/*-*- c++ -*-********************************************************
+ * wxlparser.h : parsers,  import/export for wxLayoutList           *
+ *                                                                  *
+ * (C) 1998,1999 by Karsten Ballüder (Ballueder@usa.net)            *
+ *                                                                  *
+ * $Id$
+ *******************************************************************/
+
+#ifdef __GNUG__
+#   pragma implementation "wxlparser.h"
+#endif
+
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+#  pragma hdrstop
+#endif
+
+#include "Mpch.h"
+
+#ifdef M_PREFIX
+#   include "gui/wxllist.h"
+#   include "gui/wxlparser.h"
+#else
+#   include "wxllist.h"
+#   include "wxlparser.h"
+#endif
+
+#define   BASE_SIZE 12
+
+inline static bool IsEndOfLine(const char *p)
+{
+   // the end of line is either just '\n' or "\r\n" - we understand both (even
+   // though the second is used only under DOS/Windows) to be able to import
+   // DOS text files even under Unix
+   return (*p == '\n') || ((*p == '\r') && (*(p + 1) == '\n'));
+}
+
+void wxLayoutImportText(wxLayoutList *list, wxString const &str)
+{
+   if ( !str )
+      return;
+
+   // we change the string temporarily inside this function
+   wxString& s = (wxString &)str; // const_cast
+
+   char * cptr = s.GetWriteBuf(s.Len());
+   const char * begin = cptr;
+   char  backup;
+
+   for(;;)
+   {
+      begin = cptr;
+      while( *cptr && !IsEndOfLine(cptr) )
+         cptr++;
+      backup = *cptr;
+      *cptr = '\0';
+      list->Insert(begin);
+      *cptr = backup;
+
+      // check if it's the end of this line
+      if ( IsEndOfLine(cptr) )
+      {
+         // if it was "\r\n", skip the following '\n'
+         if ( *cptr == '\r' )
+            cptr++;
+         list->LineBreak();
+      }
+      else if(backup == '\0') // reached end of string
+         break;
+      cptr++;
+   }
+
+   s.UngetWriteBuf();
+}
+
+static
+wxString wxLayoutExportCmdAsHTML(wxLayoutObjectCmd const & cmd,
+                                 wxLayoutStyleInfo *styleInfo)
+{
+   static char buffer[20];
+   wxString html;
+
+   wxLayoutStyleInfo *si = cmd.GetStyle();
+
+   int size, sizecount;
+
+   html += "<font ";
+
+   if(si->m_fg_valid)
+   {
+      html +="color=";
+      sprintf(buffer,"\"#%02X%02X%02X\"", si->m_fg.Red(),si->m_fg.Green(),si->m_fg.Blue());
+      html += buffer;
+   }
+
+   if(si->m_bg_valid)
+   {
+      html += " bgcolor=";
+      sprintf(buffer,"\"#%02X%02X%02X\"", si->m_bg.Red(),si->m_bg.Green(),si->m_bg.Blue());
+      html += buffer;
+   }
+
+   switch(si->family)
+   {
+   case wxSWISS:
+   case wxMODERN:
+      html += " face=\"Arial,Helvetica\""; break;
+   case wxROMAN:
+      html += " face=\"Times New Roman, Times\""; break;
+   case wxTELETYPE:
+      html += " face=\"Courier New, Courier\""; break;
+   default:
+      ;
+   }
+
+   size = BASE_SIZE; sizecount = 0;
+   while(size < si->size && sizecount < 5)
+   {
+      sizecount ++;
+      size = (size*12)/10;
+   }
+   while(size > si->size && sizecount > -5)
+   {
+      sizecount --;
+      size = (size*10)/12;
+   }
+   html += "size=";
+   sprintf(buffer,"%+1d", sizecount);
+   html += buffer;
+
+   html +=">";
+
+   if(styleInfo != NULL)
+      html ="</font>"+html; // terminate any previous font command
+
+   if((si->weight == wxBOLD) && ( (!styleInfo) || (styleInfo->weight != wxBOLD)))
+      html += "<b>";
+   else
+      if(si->weight != wxBOLD && ( styleInfo && (styleInfo->weight == wxBOLD)))
+         html += "</b>";
+
+   if(si->style == wxSLANT)
+      si->style = wxITALIC; // the same for html
+
+   if((si->style == wxITALIC) && ( (!styleInfo) || (styleInfo->style != wxITALIC)))
+      html += "<i>";
+   else
+      if(si->style != wxITALIC && ( styleInfo && (styleInfo->style == wxITALIC)))
+         html += "</i>";
+
+   if(si->underline && ( (!styleInfo) || ! styleInfo->underline))
+      html += "<u>";
+   else if(si->underline == false && ( styleInfo && styleInfo->underline))
+      html += "</u>";
+
+
+   *styleInfo = *si; // update last style info
+
+   return html;
+}
+
+
+
+wxLayoutExportStatus::wxLayoutExportStatus(wxLayoutList *list)
+{
+   m_si = list->GetDefaultStyleInfo();
+   m_line = list->GetFirstLine();
+   m_iterator = m_line->GetFirstObject();
+}
+
+
+
+#define   WXLO_IS_TEXT(type) \
+( type == WXLO_TYPE_TEXT \
+  || (type == WXLO_TYPE_CMD \
+      && mode == WXLO_EXPORT_AS_HTML))
+
+
+wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status,
+                                     int mode, int flags)
+{
+   wxASSERT(status);
+   wxLayoutExportObject * export;
+
+   if(status->m_iterator == NULLIT) // end of line
+   {
+      if(!status->m_line || status->m_line->GetNextLine() == NULL)
+         // reached end of list
+         return NULL;
+   }
+   export = new wxLayoutExportObject();
+   wxLayoutObjectType type;
+   if(status->m_iterator != NULLIT)
+   {
+      type = (** status->m_iterator).GetType();
+      if( mode == WXLO_EXPORT_AS_OBJECTS || ! WXLO_IS_TEXT(type)) // simple case
+      {
+         export->type = WXLO_EXPORT_OBJECT;
+         export->content.object = *status->m_iterator;
+         status->m_iterator++;
+         return export;
+      }
+   }
+   else
+   {  // iterator == NULLIT
+      if(mode == WXLO_EXPORT_AS_OBJECTS)
+      {
+         export->type = WXLO_EXPORT_EMPTYLINE;
+         export->content.object = NULL; //empty line
+         status->m_line = status->m_line->GetNextLine();
+         if(status->m_line)
+            status->m_iterator = status->m_line->GetFirstObject();
+         return export;
+      }
+      else
+         type = WXLO_TYPE_TEXT;
+   }
+
+   wxString *str = new wxString();
+   // text must be concatenated
+   for(;;)
+   {
+      while(status->m_iterator == NULLIT)
+      {
+         if(flags & WXLO_EXPORT_AS_HTML)
+            *str += "<br>";
+         if(flags & WXLO_EXPORT_WITH_CRLF)
+            *str += "\r\n";
+         else
+            *str += '\n';
+
+         status->m_line = status->m_line->GetNextLine();
+         if(status->m_line)
+            status->m_iterator = status->m_line->GetFirstObject();
+         else
+            break; // end of list
+      }
+      if(! status->m_line)  // reached end of list, fall through
+         break;
+      type = (** status->m_iterator).GetType();
+      if(type == WXLO_TYPE_ICON)
+         break;
+      switch(type)
+      {
+      case WXLO_TYPE_TEXT:
+         *str += ((wxLayoutObjectText *)*status->m_iterator)->GetText();
+         break;
+      case WXLO_TYPE_CMD:
+         if(mode == WXLO_EXPORT_AS_HTML)
+            *str += wxLayoutExportCmdAsHTML(*(wxLayoutObjectCmd const
+                                              *)*status->m_iterator, & status->m_si);
+         break;
+      default:  // ignore icons
+         ;
+      }
+      status->m_iterator++;
+   }
+
+   export->type = (mode == WXLO_EXPORT_AS_HTML)
+      ?  WXLO_EXPORT_HTML : WXLO_EXPORT_TEXT;
+   export->content.text = str;
+   return export;
+}
+
diff --git a/samples/richedit/wxlparser.h b/samples/richedit/wxlparser.h
new file mode 100644 (file)
index 0000000..a594885
--- /dev/null
@@ -0,0 +1,78 @@
+/*-*- c++ -*-********************************************************
+ * wxlparser.h : parsers,  import/export for wxLayoutList           *
+ *                                                                  *
+ * (C) 1998 by Karsten Ballüder (Ballueder@usa.net)                 *
+ *                                                                  *
+ * $Id$
+ *******************************************************************/
+#ifndef WXLPARSER_H
+#   define   WXLPARSER_H
+
+#ifdef __GNUG__
+#   pragma interface "wxlparser.h"
+#endif
+
+#ifndef   NULL
+#   define   NULL 0
+#endif
+
+enum wxLayoutExportType
+{
+   WXLO_EXPORT_TEXT,
+   WXLO_EXPORT_HTML,
+   WXLO_EXPORT_OBJECT,
+   // this can be caused by empty lines:
+   WXLO_EXPORT_EMPTYLINE
+};
+
+enum wxLayoutExportMode
+{
+   WXLO_EXPORT_AS_TEXT = 0x00,
+   WXLO_EXPORT_AS_TEXT_AND_COMMANDS = 0x01,
+   WXLO_EXPORT_AS_HTML = 0x02,
+   WXLO_EXPORT_AS_OBJECTS = 0x03,
+
+   // non 0:
+   WXLO_EXPORT_WITH_CRLF = 0x10,
+   WXLO_EXPORT_WITH_LF_ONLY = 0x20
+};
+
+struct wxLayoutExportObject
+{
+   wxLayoutExportType type;
+   union
+   {
+      wxString           *text;
+      wxLayoutObject *object;
+   }content;
+   ~wxLayoutExportObject()
+      {
+         if(type == WXLO_EXPORT_TEXT || type == WXLO_EXPORT_HTML)
+            delete content.text;
+      }
+};
+
+
+struct wxLayoutExportStatus
+{
+   wxLayoutExportStatus(wxLayoutList *list);
+   wxLayoutLine      * m_line;
+   wxLOiterator        m_iterator;
+   wxLayoutStyleInfo   m_si;
+};
+
+#ifdef OS_WIN
+    #define WXLO_DEFAULT_EXPORT_MODE WXLO_EXPORT_WITH_CRLF
+#else // Unix
+    #define WXLO_DEFAULT_EXPORT_MODE WXLO_EXPORT_WITH_LF_ONLY
+#endif // Win/Unix
+
+/// import text into a wxLayoutList (including linefeeds):
+void wxLayoutImportText(wxLayoutList *list, wxString const &str);
+
+/// export text in a given format
+wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status,
+                                     int mode = WXLO_EXPORT_AS_TEXT,
+                                     int flags = WXLO_DEFAULT_EXPORT_MODE);
+
+#endif //WXLPARSER_H
diff --git a/samples/richedit/wxlwindow.cpp b/samples/richedit/wxlwindow.cpp
new file mode 100644 (file)
index 0000000..5df8db3
--- /dev/null
@@ -0,0 +1,1003 @@
+/*-*- c++ -*-********************************************************
+ * wxLwindow.h : a scrolled Window for displaying/entering rich text*
+ *                                                                  *
+ * (C) 1998, 1999 by Karsten Ballüder (Ballueder@usa.net)           *
+ *                                                                  *
+ * $Id$
+ *******************************************************************/
+
+// ===========================================================================
+// declarations
+// ===========================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#ifdef __GNUG__
+#   pragma implementation "wxlwindow.h"
+#endif
+
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#  pragma hdrstop
+#endif
+
+#include "Mpch.h"
+
+#ifdef M_BASEDIR
+#   ifndef USE_PCH
+#     include "Mcommon.h"
+#     include "gui/wxMenuDefs.h"
+#     include "gui/wxMApp.h"
+#   endif // USE_PCH
+#   include "gui/wxlwindow.h"
+#   include "gui/wxlparser.h"
+#else
+#   ifdef   __WXMSW__
+#       include <wx/msw/private.h>
+#   endif
+
+#   include "wxlwindow.h"
+#   include "wxlparser.h"
+#endif
+
+#include <wx/clipbrd.h>
+#include <wx/textctrl.h>
+#include <wx/dataobj.h>
+
+#ifdef WXLAYOUT_USE_CARET
+#   include <wx/caret.h>
+#endif // WXLAYOUT_USE_CARET
+
+#include <ctype.h>
+
+// ----------------------------------------------------------------------------
+// macros
+// ----------------------------------------------------------------------------
+
+#ifdef WXLAYOUT_DEBUG
+#  define   WXLO_DEBUG(x)      wxLogDebug x
+#else
+#  define WXLO_DEBUG(x)
+#endif
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+/// offsets to put a nice frame around text
+#define WXLO_XOFFSET   4
+#define WXLO_YOFFSET   4
+
+/// offset to the right and bottom for when to redraw scrollbars
+#define   WXLO_ROFFSET   20
+#define   WXLO_BOFFSET   20
+
+/// the size of one scrollbar page in pixels
+static const int X_SCROLL_PAGE = 10;
+static const int Y_SCROLL_PAGE = 20;
+
+// ----------------------------------------------------------------------------
+// event tables
+// ----------------------------------------------------------------------------
+
+BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow)
+   EVT_PAINT    (wxLayoutWindow::OnPaint)
+   EVT_CHAR     (wxLayoutWindow::OnChar)
+   EVT_KEY_UP   (wxLayoutWindow::OnKeyUp)
+   EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseClick)
+   EVT_RIGHT_DOWN(wxLayoutWindow::OnRightMouseClick)
+   EVT_LEFT_DCLICK(wxLayoutWindow::OnMouseDblClick)
+   EVT_MOTION    (wxLayoutWindow::OnMouseMove)
+   EVT_MENU_RANGE(WXLOWIN_MENU_FIRST, WXLOWIN_MENU_LAST, wxLayoutWindow::OnMenu)
+   EVT_SET_FOCUS(wxLayoutWindow::OnSetFocus)
+   EVT_KILL_FOCUS(wxLayoutWindow::OnKillFocus)
+END_EVENT_TABLE()
+
+// ===========================================================================
+// implementation
+// ===========================================================================
+
+/* LEAVE IT HERE UNTIL WXGTK WORKS AGAIN!!! */
+#ifdef __WXGTK__
+/// allows me to compare to wxPoints
+static bool operator != (wxPoint const &p1, wxPoint const &p2)
+{
+   return p1.x != p2.x || p1.y != p2.y;
+}
+#endif // __WXGTK__
+
+#ifndef wxWANTS_CHARS
+   #define wxWANTS_CHARS 0
+#endif
+
+// ----------------------------------------------------------------------------
+// wxLayoutWindow
+// ----------------------------------------------------------------------------
+
+wxLayoutWindow::wxLayoutWindow(wxWindow *parent)
+              : wxScrolledWindow(parent, -1,
+                                 wxDefaultPosition, wxDefaultSize,
+                                 wxHSCROLL | wxVSCROLL |
+                                 wxBORDER |
+                                 wxWANTS_CHARS)
+{
+   SetStatusBar(NULL); // don't use statusbar
+   m_Editable = false;
+   m_doSendEvents = false;
+   m_ViewStartX = 0; m_ViewStartY = 0;
+   m_DoPopupMenu = true;
+   m_PopupMenu = MakeFormatMenu();
+   m_memDC = new wxMemoryDC;
+   m_bitmap = new wxBitmap(4,4);
+   m_bitmapSize = wxPoint(4,4);
+   m_llist = new wxLayoutList();
+
+   m_BGbitmap = NULL;
+   m_ScrollToCursor = false;
+   SetWrapMargin(0);
+   wxPoint max = m_llist->GetSize();
+   SetScrollbars(X_SCROLL_PAGE, Y_SCROLL_PAGE,
+                 max.x / X_SCROLL_PAGE + 1, max.y / Y_SCROLL_PAGE + 1);
+   EnableScrolling(true, true);
+   m_maxx = max.x + X_SCROLL_PAGE;
+   m_maxy = max.y + Y_SCROLL_PAGE;
+   m_Selecting = false;
+
+#ifdef WXLAYOUT_USE_CARET
+   // FIXME cursor size shouldn't be hardcoded
+   wxCaret *caret = new wxCaret(this, 2, 20);
+   SetCaret(caret);
+   m_llist->SetCaret(caret);
+   caret->Show();
+#endif // WXLAYOUT_USE_CARET
+
+   SetCursorVisibility(-1);
+   SetCursor(wxCURSOR_IBEAM);
+   SetDirty();
+}
+
+wxLayoutWindow::~wxLayoutWindow()
+{
+   delete m_memDC; // deletes bitmap automatically (?)
+   delete m_bitmap;
+   delete m_llist;
+   delete m_PopupMenu;
+   SetBackgroundBitmap(NULL);
+}
+
+void
+wxLayoutWindow::Clear(int family,
+                      int size,
+                      int style,
+                      int weight,
+                      int underline,
+                      wxColour *fg,
+                      wxColour *bg)
+{
+   GetLayoutList()->Clear(family,size,style,weight,underline,fg,bg);
+   SetBackgroundColour(GetLayoutList()->GetDefaultStyleInfo().GetBGColour());
+   ResizeScrollbars(true);
+   SetDirty();
+   SetModified(false);
+   wxScrolledWindow::Clear();
+   DoPaint((wxRect *)NULL);
+}
+
+void
+wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event)
+{
+   wxClientDC dc( this );
+   PrepareDC( dc );
+   if ( eventId != WXLOWIN_MENU_MOUSEMOVE )
+   {
+       // moving the mouse in a window shouldn't give it the focus!
+      SetFocus();
+   }
+
+   wxPoint findPos;
+   findPos.x = dc.DeviceToLogicalX(event.GetX());
+   findPos.y = dc.DeviceToLogicalY(event.GetY());
+
+   findPos.x -= WXLO_XOFFSET;
+   findPos.y -= WXLO_YOFFSET;
+
+   if(findPos.x < 0) findPos.x = 0;
+   if(findPos.y < 0) findPos.y = 0;
+
+   m_ClickPosition = wxPoint(event.GetX(), event.GetY());
+
+   wxPoint cursorPos;
+   bool found;
+   wxLayoutObject *obj = m_llist->FindObjectScreen(dc, findPos,
+                                                   &cursorPos, &found);
+   wxLayoutObject::UserData *u = obj ? obj->GetUserData() : NULL;
+
+   //has the mouse only been moved?
+   if(eventId == WXLOWIN_MENU_MOUSEMOVE)
+   {
+      // found is only true if we are really over an object, not just
+      // behind it
+      if(found && u && ! m_Selecting)
+      {
+         if(!m_HandCursor)
+            SetCursor(wxCURSOR_HAND);
+         m_HandCursor = TRUE;
+         if(m_StatusBar && m_StatusFieldLabel != -1)
+         {
+            const wxString &label = u->GetLabel();
+            if(label.Length())
+               m_StatusBar->SetStatusText(label,
+                                          m_StatusFieldLabel);
+         }
+      }
+      else
+      {
+         if(m_HandCursor)
+            SetCursor(wxCURSOR_IBEAM);
+         m_HandCursor = FALSE;
+         if(m_StatusBar && m_StatusFieldLabel != -1)
+            m_StatusBar->SetStatusText("", m_StatusFieldLabel);
+      }
+      if(event.LeftIsDown())
+      {
+         if(! m_Selecting)
+         {
+            m_llist->StartSelection(wxPoint(-1, -1), m_ClickPosition);
+            m_Selecting = true;
+            DoPaint();  // TODO: we don't have to redraw everything!
+         }
+         else
+         {
+            m_llist->ContinueSelection(cursorPos, m_ClickPosition);
+            DoPaint();  // TODO: we don't have to redraw everything!
+         }
+      }
+      if(m_Selecting && ! event.LeftIsDown())
+      {
+         m_llist->EndSelection(cursorPos, m_ClickPosition);
+         m_Selecting = false;
+         DoPaint();     // TODO: we don't have to redraw everything!
+      }
+
+      if ( u )
+      {
+         u->DecRef();
+         u = NULL;
+      }
+   }
+   else if(eventId == WXLOWIN_MENU_LCLICK)
+   {
+      // always move cursor to mouse click:
+      m_llist->MoveCursorTo(cursorPos);
+
+      // clicking a mouse removes the selection
+      if ( m_llist->HasSelection() )
+      {
+         m_llist->DiscardSelection();
+         DoPaint();     // TODO: we don't have to redraw everything!
+      }
+
+      // Calculate where the top of the visible area is:
+      int x0, y0;
+      ViewStart(&x0,&y0);
+      int dx, dy;
+      GetScrollPixelsPerUnit(&dx, &dy);
+      x0 *= dx; y0 *= dy;
+
+      wxPoint offset(-x0+WXLO_XOFFSET, -y0+WXLO_YOFFSET);
+      m_llist->UpdateCursorScreenPos(dc, true, offset);
+
+      if(m_CursorVisibility == -1)
+         m_CursorVisibility = 1;
+
+      // VZ: this should be unnecessary because mouse can only click on a
+      //     visible part of the canvas
+#if 0
+      ScrollToCursor();
+#endif // 0
+
+#ifdef __WXGTK__
+      DoPaint(); // DoPaint suppresses flicker under GTK
+#endif // wxGTK
+   }
+
+   // notify about mouse events?
+   if( m_doSendEvents )
+   {
+      // only do the menu if activated, editable and not on a clickable object
+      if(eventId == WXLOWIN_MENU_RCLICK
+         && IsEditable()
+         && (! obj || u == NULL))
+      {
+         PopupMenu(m_PopupMenu, m_ClickPosition.x, m_ClickPosition.y);
+         if(u) u->DecRef();
+         return;
+      }
+
+      // find the object at this position
+      if(obj)
+      {
+         wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, eventId);
+         commandEvent.SetEventObject( this );
+         commandEvent.SetClientData((char *)obj);
+         GetEventHandler()->ProcessEvent(commandEvent);
+      }
+   }
+
+   if( u )
+      u->DecRef();
+}
+
+/*
+ * Some simple keyboard handling.
+ */
+void
+wxLayoutWindow::OnChar(wxKeyEvent& event)
+{
+   int keyCode = event.KeyCode();
+
+#ifdef WXLAYOUT_DEBUG
+   if(keyCode == WXK_F1)
+   {
+      m_llist->Debug();
+      return;
+   }
+#endif
+
+   if(! m_Selecting && event.ShiftDown())
+   {
+      switch(keyCode)
+      {
+      case WXK_UP:
+      case WXK_DOWN:
+      case WXK_RIGHT:
+      case WXK_LEFT:
+      case WXK_PRIOR:
+      case WXK_NEXT:
+      case WXK_HOME:
+      case WXK_END:
+         m_Selecting = true;
+         m_llist->StartSelection();
+         break;
+      default:
+         ;
+      }
+   }
+
+   // If needed, make cursor visible:
+   if(m_CursorVisibility == -1)
+      m_CursorVisibility = 1;
+
+   /* These two nested switches work like this:
+      The first one processes all non-editing keycodes, to move the
+      cursor, etc. It's default will process all keycodes causing
+      modifications to the buffer, but only if editing is allowed.
+   */
+   bool ctrlDown = event.ControlDown();
+   switch(keyCode)
+   {
+   case WXK_RIGHT:
+      if ( ctrlDown )
+         m_llist->MoveCursorWord(1);
+      else
+         m_llist->MoveCursorHorizontally(1);
+      break;
+   case WXK_LEFT:
+      if ( ctrlDown )
+         m_llist->MoveCursorWord(-1);
+      else
+         m_llist->MoveCursorHorizontally(-1);
+      break;
+   case WXK_UP:
+      m_llist->MoveCursorVertically(-1);
+      break;
+   case WXK_DOWN:
+      m_llist->MoveCursorVertically(1);
+      break;
+   case WXK_PRIOR:
+      m_llist->MoveCursorVertically(-Y_SCROLL_PAGE);
+      break;
+   case WXK_NEXT:
+      m_llist->MoveCursorVertically(Y_SCROLL_PAGE);
+      break;
+   case WXK_HOME:
+      if ( ctrlDown )
+         m_llist->MoveCursorTo(wxPoint(0, 0));
+      else
+         m_llist->MoveCursorToBeginOfLine();
+      break;
+   case WXK_END:
+      if ( ctrlDown )
+         m_llist->MoveCursorTo(m_llist->GetSize());
+      else
+         m_llist->MoveCursorToEndOfLine();
+      break;
+
+   default:
+      if(keyCode == 'c' && ctrlDown)
+      {
+         // this should work even in read-only mode
+         Copy();
+      }
+      else if( IsEditable() )
+      {
+         /* First, handle control keys */
+         if(event.ControlDown() && ! event.AltDown())
+         {
+            switch(keyCode)
+            {
+            case WXK_INSERT:
+               Copy();
+               break;
+            case WXK_DELETE :
+            case 'd':
+               m_llist->Delete(1);
+               break;
+            case 'y':
+               m_llist->DeleteLines(1);
+               break;
+            case 'h': // like backspace
+               if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1);
+               break;
+            case 'u':
+               m_llist->DeleteToBeginOfLine();
+               break;
+            case 'k':
+               m_llist->DeleteToEndOfLine();
+               break;
+            case 'v':
+               Paste();
+               break;
+            case 'x':
+               Cut();
+               break;
+#ifdef WXLAYOUT_DEBUG
+            case WXK_F1:
+               m_llist->SetFont(-1,-1,-1,-1,true);  // underlined
+               break;
+#endif
+            default:
+               ;
+            }
+         }
+         // ALT only:
+         else if( event.AltDown() && ! event.ControlDown() )
+         {
+            switch(keyCode)
+            {
+            case WXK_DELETE:
+            case 'd':
+               m_llist->DeleteWord();
+               break;
+            default:
+               ;
+            }
+         }
+         // no control keys:
+         else if ( ! event.AltDown() && ! event.ControlDown())
+         {
+            switch(keyCode)
+            {
+            case WXK_INSERT:
+               if(event.ShiftDown())
+                  Paste();
+               break;
+            case WXK_DELETE :
+               if(event.ShiftDown())
+                  Cut();
+               else
+                  m_llist->Delete(1);
+               break;
+            case WXK_BACK: // backspace
+               if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1);
+               break;
+            case WXK_RETURN:
+               if(m_WrapMargin > 0)
+                  m_llist->WrapLine(m_WrapMargin);
+               m_llist->LineBreak();
+               break;
+            default:
+               if((!(event.ControlDown() || event.AltDown() || event.MetaDown()))
+                  && (keyCode < 256 && keyCode >= 32)
+                  )
+               {
+                  if(m_WrapMargin > 0 && isspace(keyCode))
+                     m_llist->WrapLine(m_WrapMargin);
+                  m_llist->Insert((char)keyCode);
+               }
+               break;
+            }
+         }
+         SetDirty();
+         SetModified();
+      }// if(IsEditable())
+   }// first switch()
+   if(m_Selecting)
+   {
+      if(event.ShiftDown())
+         m_llist->ContinueSelection();
+      else
+      {
+         m_llist->EndSelection();
+         m_Selecting = false;
+      }
+   }
+
+   // we must call ResizeScrollbars() before ScrollToCursor(), otherwise the
+   // ne cursor position might be outside the current scrolllbar range
+   ResizeScrollbars();
+   ScrollToCursor();
+
+   // refresh the screen
+   DoPaint(m_llist->GetUpdateRect());
+}
+
+void
+wxLayoutWindow::OnKeyUp(wxKeyEvent& event)
+{
+   if(event.KeyCode() == WXK_SHIFT && m_llist->IsSelecting())
+   {
+      m_llist->EndSelection();
+      m_Selecting = false;
+   }
+   event.Skip();
+}
+
+
+void
+wxLayoutWindow::ScrollToCursor(void)
+{
+   wxClientDC dc( this );
+   PrepareDC( dc );
+
+   int x0,y0,x1,y1, dx, dy;
+
+   // Calculate where the top of the visible area is:
+   ViewStart(&x0,&y0);
+   GetScrollPixelsPerUnit(&dx, &dy);
+   x0 *= dx; y0 *= dy;
+
+   WXLO_DEBUG(("ScrollToCursor: ViewStart is %d/%d", x0, y0));
+
+   // Get the size of the visible window:
+   GetClientSize(&x1,&y1);
+
+   // notice that the client size may be (0, 0)...
+   wxASSERT(x1 >= 0 && y1 >= 0);
+
+   // VZ: I think this is false - if you do it here, ResizeScrollbars() won't
+   //     call SetScrollbars() later
+#if 0
+   // As we have the values anyway, use them to avoid unnecessary scrollbar
+   // updates.
+   if(x1 > m_maxx) m_maxx = x1;
+   if(y1 > m_maxy) m_maxy = y1;
+#endif // 0
+
+   // Make sure that the scrollbars are at a position so that the cursor is
+   // visible if we are editing
+   WXLO_DEBUG(("m_ScrollToCursor = %d", (int) m_ScrollToCursor));
+   wxPoint cc = m_llist->GetCursorScreenPos(dc);
+
+   // the cursor should be completely visible in both directions
+   wxPoint cs(m_llist->GetCursorSize());
+   int nx = -1,
+       ny = -1;
+   if ( cc.x < x0 || cc.x >= x0 + x1 - cs.x )
+   {
+      nx = cc.x - x1/2;
+      if ( nx < 0 )
+         nx = 0;
+   }
+
+   if ( cc.y < y0 || cc.y >= y0 + y1 - cs.y )
+   {
+      ny = cc.y - y1/2;
+      if ( ny < 0) 
+         ny = 0;
+   }
+
+   if ( nx != -1 || ny != -1 )
+   {
+      // set new view start
+      Scroll(nx == -1 ? -1 : (nx+dx-1)/dx, ny == -1 ? -1 : (ny+dy-1)/dy);
+
+      // avoid recursion
+      m_ScrollToCursor = false;
+   }
+}
+
+void
+wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event))
+{
+   wxRect region = GetUpdateRegion().GetBox();
+   InternalPaint(&region);
+}
+
+void
+wxLayoutWindow::DoPaint(const wxRect *updateRect)
+{
+#ifndef __WXMSW__
+   InternalPaint(updateRect);
+#else
+   Refresh(FALSE, updateRect); // Causes bad flicker under wxGTK!!!
+
+   if ( !::UpdateWindow(GetHwnd()) )
+      wxLogLastError("UpdateWindow");
+#endif
+}
+
+void
+wxLayoutWindow::InternalPaint(const wxRect *updateRect)
+{
+   wxPaintDC dc( this );
+   PrepareDC( dc );
+
+#ifdef WXLAYOUT_USE_CARET
+   // hide the caret before drawing anything
+   GetCaret()->Hide();
+#endif // WXLAYOUT_USE_CARET
+
+   int x0,y0,x1,y1, dx, dy;
+
+   // Calculate where the top of the visible area is:
+   ViewStart(&x0,&y0);
+   GetScrollPixelsPerUnit(&dx, &dy);
+   x0 *= dx; y0 *= dy;
+
+   // Get the size of the visible window:
+   GetClientSize(&x1,&y1);
+   wxASSERT(x1 >= 0);
+   wxASSERT(y1 >= 0);
+
+   if(updateRect)
+   {
+      WXLO_DEBUG(("Update rect: %ld,%ld / %ld,%ld",
+                  updateRect->x, updateRect->y,
+                  updateRect->x+updateRect->width,
+                  updateRect->y+updateRect->height));
+   }
+   if(IsDirty())
+   {
+      m_llist->Layout(dc);
+      ResizeScrollbars();
+   }
+   /* Check whether the window has grown, if so, we need to reallocate
+      the bitmap to be larger. */
+   if(x1 > m_bitmapSize.x || y1 > m_bitmapSize.y)
+   {
+      wxASSERT(m_bitmapSize.x > 0);
+      wxASSERT(m_bitmapSize.y > 0);
+
+      m_memDC->SelectObject(wxNullBitmap);
+      delete m_bitmap;
+      m_bitmapSize = wxPoint(x1,y1);
+      m_bitmap = new wxBitmap(x1,y1);
+      m_memDC->SelectObject(*m_bitmap);
+   }
+
+   m_memDC->SetDeviceOrigin(0,0);
+   m_memDC->SetBrush(wxBrush(m_llist->GetDefaultStyleInfo().GetBGColour(),wxSOLID));
+   m_memDC->SetPen(wxPen(m_llist->GetDefaultStyleInfo().GetBGColour(),
+                         0,wxTRANSPARENT));
+   m_memDC->SetLogicalFunction(wxCOPY);
+   m_memDC->Clear();
+
+   // fill the background with the background bitmap
+   if(m_BGbitmap)
+   {
+      CoordType
+         y, x,
+         w = m_BGbitmap->GetWidth(),
+         h = m_BGbitmap->GetHeight();
+      for(y = 0; y < y1; y+=h)
+         for(x = 0; x < x1; x+=w)
+            m_memDC->DrawBitmap(*m_BGbitmap, x, y);
+      m_memDC->SetBackgroundMode(wxTRANSPARENT);
+   }
+
+   // This is the important bit: we tell the list to draw itself
+#if WXLO_DEBUG_URECT
+   if(updateRect)
+   {
+      WXLO_DEBUG(("Update rect: %ld,%ld / %ld,%ld",
+                  updateRect->x, updateRect->y,
+                  updateRect->x+updateRect->width,
+                  updateRect->y+updateRect->height));
+   }
+#endif
+
+   // Device origins on the memDC are suspect, we translate manually
+   // with the translate parameter of Draw().
+   wxPoint offset(-x0+WXLO_XOFFSET,-y0+WXLO_YOFFSET);
+   m_llist->Draw(*m_memDC,offset, y0, y0+y1);
+
+   // We start calculating a new update rect before drawing the
+   // cursor, so that the cursor coordinates get included in the next
+   // update rectangle (although they are drawn on the memDC, this is
+   // needed to erase it):
+   m_llist->InvalidateUpdateRect();
+   if(m_CursorVisibility != 0)
+   {
+      m_llist->UpdateCursorScreenPos(dc, true, offset);
+      m_llist->DrawCursor(*m_memDC,
+                          m_HaveFocus && IsEditable(), // draw a thick
+                          // cursor for    editable windows with focus
+                          offset);
+   }
+
+// Now copy everything to the screen:
+#if 0
+   // This somehow doesn't work, but even the following bit with the
+   // whole rect at once is still a bit broken I think.
+   wxRegionIterator ri ( GetUpdateRegion() );
+   if(ri)
+      while(ri)
+      {
+         WXLO_DEBUG(("UpdateRegion: %ld,%ld, %ld,%ld",
+                     ri.GetX(),ri.GetY(),ri.GetW(),ri.GetH()));
+         dc.Blit(x0+ri.GetX(),y0+ri.GetY(),ri.GetW(),ri.GetH(),
+                 m_memDC,ri.GetX(),ri.GetY(),wxCOPY,FALSE);
+         ri++;
+      }
+   else
+#endif
+   {
+      // FIXME: Trying to copy only the changed parts, but it does not seem
+      // to work:
+//      x0 = updateRect->x; y0 = updateRect->y;
+//      if(updateRect->height < y1)
+//         y1 = updateRect->height;
+//      y1 += WXLO_YOFFSET; //FIXME might not be needed
+      dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE);
+   }
+
+#ifdef WXLAYOUT_USE_CARET
+   // show the caret back after everything is redrawn
+   m_caret->Show();
+#endif // WXLAYOUT_USE_CARET
+
+   ResetDirty();
+   m_ScrollToCursor = false;
+
+   if ( m_StatusBar && m_StatusFieldCursor != -1 )
+   {
+      static wxPoint s_oldCursorPos(-1, -1);
+
+      wxPoint pos(m_llist->GetCursorPos());
+
+      // avoid unnecessary status bar refreshes
+      if ( pos != s_oldCursorPos )
+      {
+         s_oldCursorPos = pos;
+
+         wxString label;
+         label.Printf(_("Ln:%d Col:%d"), pos.y + 1, pos.x + 1);
+         m_StatusBar->SetStatusText(label, m_StatusFieldCursor);
+      }
+   }
+}
+
+// change the range and position of scrollbars
+void
+wxLayoutWindow::ResizeScrollbars(bool exact)
+{
+   wxPoint max = m_llist->GetSize();
+
+   WXLO_DEBUG(("ResizeScrollbars: max size = (%ld, %ld)",
+               (long int)max.x, (long int) max.y));
+
+   if( max.x > m_maxx - WXLO_ROFFSET || max.y > m_maxy - WXLO_BOFFSET || exact )
+   {
+      if ( !exact )
+      {
+         // add an extra bit to the sizes to avoid future updates
+         max.x += WXLO_ROFFSET;
+         max.y += WXLO_BOFFSET;
+      }
+
+      ViewStart(&m_ViewStartX, &m_ViewStartY);
+      SetScrollbars(X_SCROLL_PAGE, Y_SCROLL_PAGE,
+                    max.x / X_SCROLL_PAGE + 1, max.y / Y_SCROLL_PAGE + 1,
+                    m_ViewStartX, m_ViewStartY,
+                    true);
+
+      m_maxx = max.x + X_SCROLL_PAGE;
+      m_maxy = max.y + Y_SCROLL_PAGE;
+   }
+}
+
+void
+wxLayoutWindow::Paste(void)
+{
+   // Read some text
+   if (wxTheClipboard->Open())
+   {
+#if wxUSE_PRIVATE_CLIPBOARD_FORMAT
+      wxLayoutDataObject wxldo;
+      if (wxTheClipboard->IsSupported( wxldo.GetFormat() ))
+      {
+         wxTheClipboard->GetData(&wxldo);
+         {
+         }
+         //FIXME: missing functionality m_llist->Insert(wxldo.GetList());
+      }
+      else
+#endif
+      {
+         wxTextDataObject data;
+         if (wxTheClipboard->IsSupported( data.GetFormat() ))
+         {
+            wxTheClipboard->GetData(&data);
+            wxString text = data.GetText();
+            wxLayoutImportText( m_llist, text);
+         }
+      }
+      wxTheClipboard->Close();
+   }
+
+#if 0
+   /* My attempt to get the primary selection, but it does not
+      work. :-( */
+   if(text.Length() == 0)
+   {
+      wxTextCtrl tmp_tctrl(this,-1);
+      tmp_tctrl.Paste();
+      text += tmp_tctrl.GetValue();
+   }
+#endif
+}
+
+bool
+wxLayoutWindow::Copy(bool invalidate)
+{
+   // Calling GetSelection() will automatically do an EndSelection()
+   // on the list, but we need to take a note of it, too:
+   if(m_Selecting)
+   {
+      m_Selecting = false;
+      m_llist->EndSelection();
+   }
+
+   wxLayoutDataObject wldo;
+   wxLayoutList *llist = m_llist->GetSelection(&wldo, invalidate);
+   if(! llist)
+      return FALSE;
+   // Export selection as text:
+   wxString text;
+   wxLayoutExportObject *export;
+   wxLayoutExportStatus status(llist);
+   while((export = wxLayoutExport( &status, WXLO_EXPORT_AS_TEXT)) != NULL)
+   {
+      if(export->type == WXLO_EXPORT_TEXT)
+         text << *(export->content.text);
+      delete export;
+   }
+   delete llist;
+
+   // The exporter always appends a newline, so we chop it off if it
+   // is there:
+   {
+      size_t len = text.Length();
+      if(len > 2 && text[len-2] ==  '\r') // Windows
+         text = text.Mid(0,len-2);
+      else if(len > 1 && text[len-1] == '\n')
+         text = text.Mid(0,len-1);
+   }
+
+
+   if (wxTheClipboard->Open())
+   {
+      wxTextDataObject *data = new wxTextDataObject( text );
+      bool  rc = wxTheClipboard->SetData( data );
+#if wxUSE_PRIVATE_CLIPBOARD_FORMAT
+      rc |= wxTheClipboard->AddData( &wldo );
+#endif
+      wxTheClipboard->Close();
+      return rc;
+   }
+
+   return FALSE;
+}
+
+bool
+wxLayoutWindow::Cut(void)
+{
+   if(Copy(false)) // do not invalidate selection after copy
+   {
+      m_llist->DeleteSelection();
+      return TRUE;
+   }
+   else
+      return FALSE;
+}
+bool
+wxLayoutWindow::Find(const wxString &needle,
+                     wxPoint * fromWhere)
+{
+   wxPoint found;
+
+   if(fromWhere == NULL)
+      found = m_llist->FindText(needle, m_llist->GetCursorPos());
+   else
+      found = m_llist->FindText(needle, *fromWhere);
+   if(found.x != -1)
+   {
+      if(fromWhere)
+      {
+         *fromWhere = found;
+         fromWhere->x ++;
+      }
+      m_llist->MoveCursorTo(found);
+      ScrollToCursor();
+      return true;
+   }
+   return false;
+}
+
+wxMenu *
+wxLayoutWindow::MakeFormatMenu()
+{
+   wxMenu *m = new wxMenu(_("Layout Menu"));
+
+   m->Append(WXLOWIN_MENU_LARGER   ,_("&Larger"),_("Switch to larger font."), false);
+   m->Append(WXLOWIN_MENU_SMALLER  ,_("&Smaller"),_("Switch to smaller font."), false);
+   m->AppendSeparator();
+   m->Append(WXLOWIN_MENU_UNDERLINE_ON, _("&Underline on"),_("Activate underline mode."), false);
+   m->Append(WXLOWIN_MENU_UNDERLINE_OFF,_("&Underline off"),_("Deactivate underline mode."), false);
+   m->Append(WXLOWIN_MENU_BOLD_ON      ,_("&Bold on"),_("Activate bold mode."), false);
+   m->Append(WXLOWIN_MENU_BOLD_OFF     ,_("&Bold off"),_("Deactivate bold mode."), false);
+   m->Append(WXLOWIN_MENU_ITALICS_ON   ,_("&Italics on"),_("Activate italics mode."), false);
+   m->Append(WXLOWIN_MENU_ITALICS_OFF  ,_("&Italics off"),_("Deactivate italics mode."), false);
+   m->AppendSeparator();
+   m->Append(WXLOWIN_MENU_ROMAN     ,_("&Roman"),_("Switch to roman font."), false);
+   m->Append(WXLOWIN_MENU_TYPEWRITER,_("&Typewriter"),_("Switch to typewriter font."), false);
+   m->Append(WXLOWIN_MENU_SANSSERIF ,_("&Sans Serif"),_("Switch to sans serif font."), false);
+   return m;
+}
+
+void wxLayoutWindow::OnMenu(wxCommandEvent& event)
+{
+   switch (event.GetId())
+   {
+   case WXLOWIN_MENU_LARGER:
+      m_llist->SetFontLarger(); break;
+   case WXLOWIN_MENU_SMALLER:
+      m_llist->SetFontSmaller(); break;
+   case WXLOWIN_MENU_UNDERLINE_ON:
+      m_llist->SetFontUnderline(true); break;
+   case WXLOWIN_MENU_UNDERLINE_OFF:
+      m_llist->SetFontUnderline(false); break;
+   case WXLOWIN_MENU_BOLD_ON:
+      m_llist->SetFontWeight(wxBOLD); break;
+   case WXLOWIN_MENU_BOLD_OFF:
+      m_llist->SetFontWeight(wxNORMAL); break;
+   case WXLOWIN_MENU_ITALICS_ON:
+      m_llist->SetFontStyle(wxITALIC); break;
+   case WXLOWIN_MENU_ITALICS_OFF:
+      m_llist->SetFontStyle(wxNORMAL); break;
+   case WXLOWIN_MENU_ROMAN:
+      m_llist->SetFontFamily(wxROMAN); break;
+   case WXLOWIN_MENU_TYPEWRITER:
+      m_llist->SetFontFamily(wxFIXED); break;
+   case WXLOWIN_MENU_SANSSERIF:
+      m_llist->SetFontFamily(wxSWISS); break;
+   }
+}
+
+void
+wxLayoutWindow::OnSetFocus(wxFocusEvent &ev)
+{
+   m_HaveFocus = true;
+   ev.Skip();
+}
+
+void
+wxLayoutWindow::OnKillFocus(wxFocusEvent &ev)
+{
+   m_HaveFocus = false;
+   ev.Skip();
+}
diff --git a/samples/richedit/wxlwindow.h b/samples/richedit/wxlwindow.h
new file mode 100644 (file)
index 0000000..7e4d0ce
--- /dev/null
@@ -0,0 +1,234 @@
+/*-*- c++ -*-********************************************************
+ * wxLwindow.h : a scrolled Window for displaying/entering rich text*
+ *                                                                  *
+ * (C) 1998,1999 by Karsten Ballüder (Ballueder@usa.net)            *
+ *                                                                  *
+ * $Id$
+ *******************************************************************/
+#ifndef WXLWINDOW_H
+#define WXLWINDOW_H
+
+#ifdef __GNUG__
+#   pragma interface "wxlwindow.h"
+#endif
+
+#ifndef USE_PCH
+#  include   <wx/wx.h>
+#endif
+
+#include "wxllist.h"
+
+#ifndef WXLOWIN_MENU_FIRST
+#   define WXLOWIN_MENU_FIRST 12000
+#endif
+
+
+#define wxUSE_PRIVATE_CLIPBOARD_FORMAT 1
+
+enum
+{
+   WXLOWIN_MENU_LARGER = WXLOWIN_MENU_FIRST,
+   WXLOWIN_MENU_SMALLER,
+   WXLOWIN_MENU_UNDERLINE_ON,
+   WXLOWIN_MENU_UNDERLINE_OFF,
+   WXLOWIN_MENU_BOLD_ON,
+   WXLOWIN_MENU_BOLD_OFF,
+   WXLOWIN_MENU_ITALICS_ON,
+   WXLOWIN_MENU_ITALICS_OFF,
+   WXLOWIN_MENU_ROMAN,
+   WXLOWIN_MENU_TYPEWRITER,
+   WXLOWIN_MENU_SANSSERIF,
+   WXLOWIN_MENU_RCLICK,
+   WXLOWIN_MENU_LCLICK,
+   WXLOWIN_MENU_DBLCLICK,
+   WXLOWIN_MENU_MOUSEMOVE,
+   WXLOWIN_MENU_LAST = WXLOWIN_MENU_MOUSEMOVE
+};
+
+/**
+   This class is a rich text editing widget.
+*/
+class wxLayoutWindow : public wxScrolledWindow
+{
+public:
+   /** Constructor.
+       @param parent parent window to display this panel in
+   */
+   wxLayoutWindow(wxWindow *parent);
+
+   /// Destructor.
+   virtual ~wxLayoutWindow();
+
+   /**@name Editing functionality */
+   //@{
+   /// Clears the window and sets default parameters.
+   void Clear(int family = wxROMAN,
+              int size=12,
+              int style=wxNORMAL,
+              int weight=wxNORMAL,
+              int underline=0,
+              wxColour *fg=NULL,
+              wxColour *bg=NULL);
+   /** Sets a background image, only used on screen, not on printouts.
+       @param bitmap a pointer to a wxBitmap or NULL to remove it
+   */
+   void SetBackgroundBitmap(wxBitmap *bitmap = NULL)
+      {
+         if(m_BGbitmap) delete m_BGbitmap;
+         m_BGbitmap = bitmap;
+      }
+   /// Enable or disable editing, i.e. processing of keystrokes.
+   void SetEditable(bool toggle) { m_Editable = toggle; }
+   /// Query whether list can be edited by user.
+   bool IsEditable(void) const { return m_Editable; }
+   /** Sets cursor visibility, visible=1, invisible=0,
+       visible-on-demand=-1, to hide it until moved.
+       @param visibility -1,0 or 1
+       @return the old visibility
+   */
+   inline int SetCursorVisibility(int visibility = -1)
+      { int v =m_CursorVisibility;
+      m_CursorVisibility = visibility; return v;}
+
+   /// Pastes text from clipboard.
+   void Paste(void);
+   /** Copies selection to clipboard.
+       @param invalidate used internally, see wxllist.h for details
+   */
+   bool Copy(bool invalidate = true);
+   /// Copies selection to clipboard and deletes it.
+   bool Cut(void);
+   //@}
+
+   bool Find(const wxString &needle,
+             wxPoint * fromWhere = NULL);
+
+   void EnablePopup(bool enable = true) { m_DoPopupMenu = enable; }
+
+   /** Sets the wrap margin.
+       @param margin set this to 0 to disable it
+   */
+   void SetWrapMargin(CoordType margin) { m_WrapMargin = margin; }
+
+   /** Redraws the window.
+       Internally, this stores the parameter and calls a refresh on
+       wxMSW, draws directly on wxGTK.
+   */
+   void DoPaint(const wxRect *updateRect = NULL);
+
+   /// if exact == false, assume 50% extra size for the future
+   void ResizeScrollbars(bool exact = false);  // don't change this to true!
+
+   /// if the flag is true, we send events when user clicks on embedded objects
+   inline void SetMouseTracking(bool doIt = true) { m_doSendEvents = doIt; }
+
+   /* Returns a pointer to the wxLayoutList object.
+      @return the list
+   */
+   wxLayoutList * GetLayoutList(void) { return m_llist; }
+
+   /**@name Callbacks */
+   //@{
+   void OnPaint(wxPaintEvent &event);
+   void OnChar(wxKeyEvent& event);
+   void OnKeyUp(wxKeyEvent& event);
+   void OnMenu(wxCommandEvent& event);
+   void OnLeftMouseClick(wxMouseEvent& event)  { OnMouse(WXLOWIN_MENU_LCLICK, event); }
+   void OnRightMouseClick(wxMouseEvent& event) { OnMouse(WXLOWIN_MENU_RCLICK, event); }
+   void OnMouseDblClick(wxMouseEvent& event)   { OnMouse(WXLOWIN_MENU_DBLCLICK, event); }
+   void OnMouseMove(wxMouseEvent &event)       { OnMouse(WXLOWIN_MENU_MOUSEMOVE, event) ; }
+   void OnSetFocus(wxFocusEvent &ev);
+   void OnKillFocus(wxFocusEvent &ev);
+   //@}
+
+   /// Creates a wxMenu for use as a format popup.
+   static wxMenu * MakeFormatMenu(void);
+   /**@name Dirty flag handling for optimisations. */
+   //@{
+   /// Set dirty flag.
+   void SetDirty(void) { m_Dirty = true; }
+   /// Query whether window needs redrawing.
+   bool IsDirty(void) const { return m_Dirty; }
+   /// Reset dirty flag.
+   void ResetDirty(void) { m_Dirty = false; }
+   //@}
+   /// Redraws the window, used by DoPaint() or OnPaint().
+   void InternalPaint(const wxRect *updateRect);
+
+   /// Has list been modified/edited?
+   bool IsModified(void) const { return m_Modified; }
+   /// Mark list as modified or unchanged.
+   void SetModified(bool modified = true) { m_Modified = modified; }
+   /** Tell window to update a wxStatusBar with UserData labels and
+       cursor positions.
+       @param bar wxStatusBar pointer
+       @param labelfield field to use in statusbar for URLs/userdata labels, or -1 to disable
+       @param cursorfield field to use for cursor position, or -1 to disable
+   */
+   void SetStatusBar(class wxStatusBar *bar,
+                       int labelfield = -1,
+                       int cursorfield = -1)
+      {
+         m_StatusBar = bar; m_StatusFieldLabel = labelfield;
+         m_StatusFieldCursor = cursorfield;
+      }
+
+protected:
+   /// generic function for mouse events processing
+   void OnMouse(int eventId, wxMouseEvent& event);
+   /// as the name says
+   void ScrollToCursor(void);
+   /// for sending events
+   wxWindow *m_Parent;
+   /// Shall we send events?
+   bool m_doSendEvents;
+   /// Where does the current view start?
+   int m_ViewStartX; int m_ViewStartY;
+   /// Do we currently have the focus?
+   bool m_HaveFocus;
+   /// do we handle clicks of the right mouse button?
+   bool m_DoPopupMenu;
+   /// Should InternalPaint() scroll to cursor (VZ: seems unused any more)
+   bool m_ScrollToCursor;
+   /// Do we currently have a non-standard cursor?
+   bool m_HandCursor;
+   /// the menu
+   wxMenu * m_PopupMenu;
+   /// for derived classes, set when mouse is clicked
+   wxPoint m_ClickPosition;
+   /// for scrollbar calculations:
+   int m_maxx;
+   int m_maxy;
+   int m_lineHeight;
+   /** Visibility parameter for cursor. 0/1 as expected, -1: visible
+       on demand.
+   */
+   int m_CursorVisibility;
+private:
+   /// The layout list to be displayed.
+   wxLayoutList *m_llist;
+   /// Can user edit the window?
+   bool m_Editable;
+   /// Are we currently building a selection with the keyboard?
+   bool m_Selecting;
+   /// wrap margin
+   CoordType    m_WrapMargin;
+   /// Is list dirty (for redraws, internal use)?
+   bool         m_Dirty;
+   /// Has list been edited?
+   bool         m_Modified;
+   wxMemoryDC  *m_memDC;
+   wxBitmap    *m_bitmap;
+   wxPoint      m_bitmapSize;
+   /// A frame's statusbar to update
+   class wxStatusBar *m_StatusBar;
+   /// statusbar field for labels
+   int          m_StatusFieldLabel;
+   /// statusbar field for cursor positions
+   int          m_StatusFieldCursor;
+   /// a pointer to a bitmap for the background
+   wxBitmap    *m_BGbitmap;
+   DECLARE_EVENT_TABLE()
+};
+
+#endif