--- /dev/null
+# WXXT base directory
+WXBASEDIR=@WXBASEDIR@
+
+# set the OS type for compilation
+OS=@OS@
+# compile a library only
+RULE=bin
+
+# define library name
+BIN_TARGET=wxLayout
+# define library sources
+BIN_SRC=\
+wxLayout.cpp kbList.cpp wxlist.cpp wxlwindow.cpp wxlparser.cpp
+
+#define library objects
+BIN_OBJ=\
+wxLayout.o kbList.o wxllist.o wxlwindow.o wxlparser.o
+
+# additional things needed to link
+BIN_LINK=
+
+# additional things needed to compile
+ADD_COMPILE=
+
+# include the definitions now
+include ../../../template.mak
--- /dev/null
+/* 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........"
+};
--- /dev/null
+
+README for wxLayout classes
+---------------------------
+
+All the source in this directory is copyrighted under the
+LGPL (GNU LIBRARY PUBLIC LICENSE), 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 richt 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
+
--- /dev/null
+/*-*- c++ -*-********************************************************
+ * kbList.cc : a double linked list *
+ * *
+ * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) *
+ * *
+ * $Id$ *
+ * *
+ * $Log$
+ * Revision 1.1 1998/06/29 12:44:36 KB
+ * Added my wxWindows based layout engine to the repository.
+ * It arranges text and graphics for display on a wxDC.
+ * This code is licensed under the LGPL.
+ *
+ * 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);
+ return;
+ }
+ else if(i.Node() == last)
+ {
+ push_back(element);
+ return;
+ }
+ i = kbList::iterator(new kbListNode(element, i.Node()->prev, i.Node()));
+}
+
+void
+kbList::erase(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:
+ 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
--- /dev/null
+/*-*- c++ -*-********************************************************
+ * kbList.h : a double linked list *
+ * *
+ * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) *
+ * *
+ * $Id$
+ * $Log$
+ * Revision 1.1 1998/06/29 12:44:36 KB
+ * Added my wxWindows based layout engine to the repository.
+ * It arranges text and graphics for display on a wxDC.
+ * This code is licensed under the LGPL.
+ *
+ * Revision 1.6 1998/06/27 20:06:10 KB
+ * Added my layout code.
+ *
+ *******************************************************************/
+
+#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*();
+
+ /** 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);
+
+ /** Erase an element, move iterator to following element.
+ @param i iterator pointing to the element to be deleted
+ */
+ void erase(iterator & 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
+ */
+ bool empty(void) const
+ { return first == NULL ; }
+
+private:
+ /// if true, list owns entries
+ bool ownsEntries;
+ /// pointer to first element in list
+ kbListNode *first;
+ /// pointer to last element in list
+ kbListNode *last;
+
+ /// 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 void push_back(type *element) \
+ { kbList::push_back((void *)element); } \
+ \
+ inline void push_front(type *element) \
+ { kbList::push_front((void *)element); } \
+ \
+ inline type *pop_back(void) \
+ { return (type *) kbList::pop_back(); } \
+ \
+ inline type *pop_front(void) \
+ { return (type *) kbList::pop_front(); } \
+ \
+ inline void insert(iterator & i, type *element) \
+ { kbList::insert(i, (void *) element); } \
+ \
+ void erase(iterator & i) \
+ { kbList::erase(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(); } \
+}
+
+#ifdef MCONFIG_H
+/// define the most commonly used list type once:
+KBLIST_DEFINE(kbStringList, String);
+#endif
+
+#endif // KBLIST_H
--- /dev/null
+/*
+ * Program: wxLayout
+ *
+ * Author: Karsten Ballüder
+ *
+ * Copyright: (C) 1998, Karsten Ballüder <Ballueder@usa.net>
+ *
+ */
+
+#ifdef __GNUG__
+#pragma implementation "wxLayout.h"
+#endif
+
+#include "wxLayout.h"
+#include "wx/textfile.h"
+
+
+#include "Micon.xpm"
+
+// for testing only:
+#include <stdio.h>
+
+//-----------------------------------------------------------------------------
+// main program
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_APP(MyApp)
+
+//-----------------------------------------------------------------------------
+// MyFrame
+//-----------------------------------------------------------------------------
+
+ enum ids{ ID_EDIT = 1, ID_ADD_SAMPLE, ID_CLEAR, ID_PRINT, ID_DPRINT,
+ ID_DEBUG, ID_QUIT, ID_CLICK, ID_HTML, ID_TEXT };
+
+
+IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
+
+ BEGIN_EVENT_TABLE(MyFrame,wxFrame)
+ EVT_MENU (-1, MyFrame::OnCommand)
+ EVT_COMMAND (-1,-1, MyFrame::OnCommand)
+ EVT_CHAR (wxLayoutWindow::OnChar)
+ END_EVENT_TABLE()
+
+ MyFrame::MyFrame(void) :
+ wxFrame( NULL, -1, "wxLayout", wxPoint(20,20), wxSize(600,360) )
+{
+ CreateStatusBar( 1 );
+
+ SetStatusText( "wxLayout by Karsten Ballüder." );
+
+ wxMenu *file_menu = new wxMenu( "Menu 1" );
+ file_menu->Append( ID_CLEAR, "Clear");
+ file_menu->Append( ID_ADD_SAMPLE, "Example");
+ file_menu->Append( ID_EDIT, "Edit");
+ file_menu->Append( ID_DEBUG, "Debug");
+ file_menu->Append( ID_PRINT, "Print");
+ file_menu->Append( ID_DPRINT, "Direct Print");
+ file_menu->Append( ID_TEXT, "Export Text");
+ file_menu->Append( ID_HTML, "Export HTML");
+ file_menu->Append( ID_QUIT, "Exit");
+
+ wxMenuBar *menu_bar = new wxMenuBar();
+ menu_bar->Append(file_menu, "File" );
+ menu_bar->Show( TRUE );
+
+ SetMenuBar( menu_bar );
+
+ m_lwin = new wxLayoutWindow(this);
+ m_lwin->SetEventId(ID_CLICK);
+ m_lwin->GetLayoutList().SetEditable(true);
+ m_lwin->SetFocus();
+};
+
+void
+MyFrame::AddSampleText(wxLayoutList &llist)
+{
+
+ llist.SetFont(wxROMAN,24,wxNORMAL,wxNORMAL, false);
+
+ llist.Insert("The quick brown fox jumps over the lazy dog.");
+ llist.LineBreak();
+
+ llist.Insert("Hello ");
+ llist.Insert(new wxLayoutObjectIcon(new wxIcon(Micon_xpm,-1,-1)));
+ llist.Insert("World!");
+
+
+ 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,"red","black");
+ llist.Insert("red on black");
+ llist.SetFont(-1,-1,-1,-1,-1,"black");
+ 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);
+ char buffer[1024];
+ FILE *in = fopen("wxLayout.cpp","r");
+ if(in)
+ {
+ for(;;)
+ {
+ fgets(buffer,1024,in);
+ if(feof(in))
+ break;
+ llist.Insert(buffer);
+ llist.LineBreak();
+ }
+ }
+
+ m_lwin->Refresh();
+ m_lwin->UpdateScrollbars();
+}
+
+void
+MyFrame::Clear(void)
+{
+ m_lwin->Erase();
+ m_lwin->UpdateScrollbars();
+}
+
+/* test the editing */
+void MyFrame::Edit(void)
+{
+ wxLayoutList & llist = m_lwin->GetLayoutList();
+ m_lwin->SetEventId(ID_CLICK);
+
+ llist.MoveCursor(0);
+ llist.MoveCursor(5);
+ llist.MoveCursor(0,2);
+ llist.Delete(2);
+ llist.MoveCursor(2);
+ llist.Insert("not all so ");
+ llist.LineBreak();
+ m_lwin->Refresh();
+}
+
+void MyFrame::OnCommand( wxCommandEvent &event )
+{
+ cerr << "id:" << event.GetId() << endl;
+ switch (event.GetId())
+ {
+ case ID_QUIT:
+ Close( TRUE );
+ break;
+ case ID_PRINT:
+ m_lwin->Print();
+ break;
+ case ID_DPRINT:
+ {
+ wxLayoutList llist;
+ AddSampleText(llist);
+ wxPostScriptDC dc("layout.ps",true,this);
+ if (dc.Ok() && dc.StartDoc((char *)_("Printing message...")))
+ {
+ //dc.SetUserScale(1.0, 1.0);
+ llist.Draw(dc);
+ dc.EndDoc();
+ }
+ }
+ break;
+ case ID_EDIT:
+ Edit();
+ break;
+ case ID_ADD_SAMPLE:
+ AddSampleText(m_lwin->GetLayoutList());
+ break;
+ case ID_CLEAR:
+ Clear();
+ break;
+ case ID_DEBUG:
+ m_lwin->GetLayoutList().Debug();
+ break;
+ case ID_CLICK:
+ cerr << "Received click event." << endl;
+ break;
+ case ID_HTML:
+ {
+ wxLayoutExportObject *export;
+ wxLayoutList::iterator i = m_lwin->GetLayoutList().begin();
+
+ while((export = wxLayoutExport(m_lwin->GetLayoutList(),
+ i,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;
+ wxLayoutList::iterator i = m_lwin->GetLayoutList().begin();
+
+ while((export = wxLayoutExport(m_lwin->GetLayoutList(),
+ i,WXLO_EXPORT_AS_TEXT)) != NULL)
+ {
+ if(export->type == WXLO_EXPORT_TEXT)
+ cout << *(export->content.text);
+ else
+ cout << "<!--UNKNOWN OBJECT>";
+ delete export;
+ }
+ }
+ break;
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// 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;
+};
+
+
+
+
+
--- /dev/null
+/* -*- 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 Edit(void);
+ void AddSampleText(wxLayoutList &llist);
+ void Clear(void);
+ void OnCommand( wxCommandEvent &event );
+ DECLARE_EVENT_TABLE()
+
+private:
+ wxLayoutWindow *m_lwin;
+
+};
+
+//-----------------------------------------------------------------------------
+// MyApp
+//-----------------------------------------------------------------------------
+
+class MyApp: public wxApp
+{
+ public:
+
+ MyApp(void);
+ virtual bool OnInit(void);
+};
+
+#endif // __WXCONVERTH__
--- /dev/null
+/*-*- c++ -*-********************************************************
+ * wxFTCanvas: a canvas for editing formatted text *
+ * *
+ * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) *
+ * *
+ * $Id$ *
+ *******************************************************************/
+
+/*
+ - each Object knows its size and how to draw itself
+ - the list is responsible for calculating positions
+ - the draw coordinates for each object are the top left corner
+ - coordinates only get calculated when things get redrawn
+ - during redraw each line gets iterated over twice, first just
+ calculating baselines and positions, second to actually draw it
+ - the cursor position is the position before an object, i.e. if the
+ buffer starts with a text-object, cursor 0,0 is just before the
+ first character
+*/
+
+#ifdef __GNUG__
+#pragma implementation "wxllist.h"
+#endif
+
+#include "wxllist.h"
+#include "iostream"
+
+#define VAR(x) cerr << #x"=" << x << endl;
+#define DBG_POINT(p) cerr << #p << ": " << p.x << ',' << p.y << endl
+#define TRACE(f) cerr << #f":" << endl;
+
+#ifdef DEBUG
+static const char *_t[] = { "invalid", "text", "cmd", "icon",
+ "linebreak"};
+
+void
+wxLayoutObjectBase::Debug(void)
+{
+ CoordType bl = 0;
+ cerr << _t[GetType()] << ": size=" << GetSize(&bl).x << ","
+ << GetSize(&bl).y << " bl=" << bl;
+}
+#endif
+
+//-------------------------- wxLayoutObjectText
+
+wxLayoutObjectText::wxLayoutObjectText(const wxString &txt)
+{
+ m_Text = txt;
+ m_Width = 0;
+ m_Height = 0;
+}
+
+
+wxPoint
+wxLayoutObjectText::GetSize(CoordType *baseLine) const
+{
+ if(baseLine) *baseLine = m_BaseLine;
+ return wxPoint(m_Width, m_Height);
+}
+
+void
+wxLayoutObjectText::Draw(wxDC &dc, wxPoint position, CoordType baseLine,
+ bool draw)
+{
+ long descent = 0l;
+ dc.GetTextExtent(m_Text,&m_Width, &m_Height, &descent);
+ //FIXME: wxGTK does not set descent to a descent value yet.
+ if(descent == 0)
+ descent = (2*m_Height)/10; // crude fix
+ m_BaseLine = m_Height - descent;
+ position.y += baseLine-m_BaseLine;
+ if(draw)
+ dc.DrawText(m_Text,position.x,position.y);
+# ifdef DEBUG
+// dc.DrawRectangle(position.x, position.y, m_Width, m_Height);
+# endif
+}
+
+#ifdef DEBUG
+void
+wxLayoutObjectText::Debug(void)
+{
+ wxLayoutObjectBase::Debug();
+ cerr << " `" << m_Text << '\'';
+}
+#endif
+
+//-------------------------- wxLayoutObjectIcon
+
+wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon *icon)
+{
+ m_Icon = icon;
+}
+
+void
+wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint position, CoordType baseLine,
+ bool draw)
+{
+ position.y += baseLine - m_Icon->GetHeight();
+ if(draw)
+ dc.DrawIcon(m_Icon,position.x,position.y);
+}
+
+wxPoint
+wxLayoutObjectIcon::GetSize(CoordType *baseLine) const
+{
+ wxASSERT(baseLine);
+ *baseLine = m_Icon->GetHeight();
+ return wxPoint(m_Icon->GetWidth(), m_Icon->GetHeight());
+}
+
+//-------------------------- wxLayoutObjectCmd
+
+
+wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int
+ weight, bool underline,
+ wxColour const *fg, wxColour const *bg)
+
+{
+ m_font = new wxFont(size,family,style,weight,underline);
+ m_ColourFG = fg;
+ m_ColourBG = bg;
+}
+
+wxLayoutObjectCmd::~wxLayoutObjectCmd()
+{
+ delete m_font;
+}
+
+wxLayoutStyleInfo *
+wxLayoutObjectCmd::GetStyle(void) const
+{
+ wxLayoutStyleInfo *si = new wxLayoutStyleInfo();
+
+
+ si->size = m_font->GetPointSize();
+ si->family = m_font->GetFamily();
+ si->style = m_font->GetStyle();
+ si->underline = m_font->GetUnderlined();
+ si->weight = m_font->GetWeight();
+
+ si->fg_red = m_ColourFG->Red();
+ si->fg_green = m_ColourFG->Green();
+ si->fg_blue = m_ColourFG->Blue();
+ si->bg_red = m_ColourBG->Red();
+ si->bg_green = m_ColourBG->Green();
+ si->bg_blue = m_ColourBG->Blue();
+
+ return si;
+}
+
+void
+wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint position, CoordType lineHeight,
+ bool draw)
+{
+ wxASSERT(m_font);
+ // this get called even when draw==false, so that recalculation
+ // uses right font sizes
+ dc.SetFont(m_font);
+ if(m_ColourFG)
+ dc.SetTextForeground(*m_ColourFG);
+ if(m_ColourBG)
+ dc.SetTextBackground(*m_ColourBG);
+}
+
+//-------------------------- wxwxLayoutList
+
+wxLayoutList::wxLayoutList()
+{
+ Clear();
+}
+
+wxLayoutList::~wxLayoutList()
+{
+}
+
+
+void
+wxLayoutList::LineBreak(void)
+{
+ Insert(new wxLayoutObjectLineBreak);
+ m_CursorPosition.x = 0; m_CursorPosition.y++;
+}
+
+void
+wxLayoutList::SetFont(int family, int size, int style, int weight,
+ int underline, wxColour const *fg,
+ wxColour const *bg)
+{
+ if(family != -1) m_FontFamily = family;
+ if(size != -1) m_FontPtSize = size;
+ if(style != -1) m_FontStyle = style;
+ if(weight != -1) m_FontWeight = weight;
+ if(underline != -1) m_FontUnderline = underline;
+
+ if(fg != NULL) m_ColourFG = fg;
+ if(bg != NULL) m_ColourBG = bg;
+
+ Insert(
+ new wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,m_FontWeight,m_FontUnderline,
+ m_ColourFG, m_ColourBG));
+}
+
+void
+wxLayoutList::SetFont(int family, int size, int style, int weight,
+ int underline, char const *fg, char const *bg)
+{
+ wxColour const
+ * cfg = NULL,
+ * cbg = NULL;
+
+ if( fg )
+ cfg = wxTheColourDatabase->FindColour(fg);
+ if( bg )
+ cbg = wxTheColourDatabase->FindColour(bg);
+
+ SetFont(family,size,style,weight,underline,cfg,cbg);
+}
+
+
+/// for access by wxLayoutWindow:
+void
+wxLayoutList::GetSize(CoordType *max_x, CoordType *max_y,
+ CoordType *lineHeight)
+{
+ wxASSERT(max_x); wxASSERT(max_y); wxASSERT(lineHeight);
+ *max_x = m_MaxX;
+ *max_y = m_MaxY;
+ *lineHeight = m_LineHeight;
+}
+
+wxLayoutObjectBase *
+wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const &findCoords)
+{
+ wxLayoutObjectList::iterator i;
+
+ // in case we need to look for an object
+ wxLayoutObjectBase *foundObject = NULL;
+
+ // first object in current line
+ wxLayoutObjectList::iterator headOfLine;
+
+ // do we need to recalculate current line?
+ bool recalculate = false;
+
+ // do we calculate or draw? Either true or false.
+ bool draw = false;
+ // drawing parameters:
+ wxPoint position = wxPoint(0,0);
+ wxPoint position_HeadOfLine;
+ CoordType baseLine = m_FontPtSize;
+ CoordType baseLineSkip = (12 * baseLine)/10;
+
+ // we trace the objects' cursor positions so we can draw the cursor
+ wxPoint cursor = wxPoint(0,0);
+ // the cursor position inside the object
+ CoordType cursorOffset = 0;
+ // object under cursor
+ wxLayoutObjectList::iterator cursorObject = FindCurrentObject(&cursorOffset);
+
+ // queried from each object:
+ wxPoint size = wxPoint(0,0);
+ CoordType objBaseLine = baseLine;
+ wxLayoutObjectType type;
+
+ VAR(findObject); VAR(findCoords.x); VAR(findCoords.y);
+ // if the cursorobject is a cmd, we need to find the first
+ // printable object:
+ while(cursorObject != end()
+ && (*cursorObject)->GetType() == WXLO_TYPE_CMD)
+ cursorObject++;
+
+ headOfLine = begin();
+ position_HeadOfLine = position;
+
+ // setting up the default:
+ dc.SetTextForeground( *wxBLACK );
+ dc.SetFont( *wxNORMAL_FONT );
+
+ // we calculate everything for drawing a line, then rewind to the
+ // begin of line and actually draw it
+ i = begin();
+ for(;;)
+ {
+ recalculate = false;
+
+ if(i == end())
+ break;
+ type = (*i)->GetType();
+
+ // to initialise sizes of objects, we need to call Draw
+ (*i)->Draw(dc, position, baseLine, draw);
+
+ // update coordinates for next object:
+ size = (*i)->GetSize(&objBaseLine);
+ if(findObject && draw) // we need to look for an object
+ {
+ if(findCoords.y >= position.y
+ && findCoords.y <= position.y+size.y
+ && findCoords.x >= position.x
+ && findCoords.x <= position.x+size.x)
+ {
+ foundObject = *i;
+ findObject = false; // speeds things up
+ }
+ }
+ // draw the cursor
+ if(m_Editable && draw && i == cursorObject)
+ {
+ if(type == WXLO_TYPE_TEXT) // special treatment
+ {
+ long descent = 0l; long width, height;
+ wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
+ wxString str = tobj->GetText();
+ VAR(m_CursorPosition.x); VAR(cursor.x);
+ str = str.substr(0, cursorOffset);
+ VAR(str);
+ dc.GetTextExtent(str, &width,&height, &descent);
+ VAR(height);
+ VAR(width); VAR(descent);
+ dc.DrawLine(position.x+width,
+ position.y+(baseLineSkip-height),
+ position.x+width, position.y+baseLineSkip);
+ }
+ else
+ {
+ if(type == WXLO_TYPE_LINEBREAK)
+ dc.DrawLine(0, position.y+baseLineSkip, 0, position.y+2*baseLineSkip);
+ else
+ {
+ if(size.x == 0)
+ {
+ if(size.y == 0)
+ dc.DrawLine(position.x, position.y, position.x, position.y+baseLineSkip);
+ else
+ dc.DrawLine(position.x, position.y, position.x, position.y+size.y);
+ }
+ else
+ dc.DrawRectangle(position.x, position.y, size.x, size.y);
+ }
+ }
+ }
+
+ // calculate next object's position:
+ position.x += size.x;
+
+ // do we need to increase the line's height?
+ if(size.y > baseLineSkip)
+ {
+ baseLineSkip = size.y;
+ recalculate = true;
+ }
+ if(objBaseLine > baseLine)
+ {
+ baseLine = objBaseLine;
+ recalculate = true;
+ }
+
+ // now check whether we have finished handling this line:
+ if(type == WXLO_TYPE_LINEBREAK || i == tail())
+ {
+ if(recalculate) // do this line again
+ {
+ position.x = position_HeadOfLine.x;
+ i = headOfLine;
+ continue;
+ }
+
+ if(! draw) // finished calculating sizes
+ { // do this line again, this time drawing it
+ position = position_HeadOfLine;
+ draw = true;
+ i = headOfLine;
+ continue;
+ }
+ else // we have drawn a line, so continue calculating next one
+ draw = false;
+ }
+
+ if(position.x+size.x > m_MaxX)
+ m_MaxX = position.x+size.x;
+ // is it a linebreak?
+ if(type == WXLO_TYPE_LINEBREAK || i == tail())
+ {
+ position.x = 0;
+ position.y += baseLineSkip;
+ baseLine = m_FontPtSize;
+ baseLineSkip = (12 * baseLine)/10;
+ headOfLine = i;
+ headOfLine++;
+ position_HeadOfLine = position;
+ }
+ i++;
+ }
+ m_MaxY = position.y;
+ return foundObject;
+}
+
+#ifdef DEBUG
+void
+wxLayoutList::Debug(void)
+{
+ CoordType offs;
+ wxLayoutObjectList::iterator i;
+
+ cerr <<
+ "------------------------debug start-------------------------" << endl;
+ for(i = begin(); i != end(); i++)
+ {
+ (*i)->Debug();
+ cerr << endl;
+ }
+ cerr <<
+ "-----------------------debug end----------------------------"
+ << endl;
+ // show current object:
+ cerr << "Cursor: "
+ << m_CursorPosition.x << ','
+ << m_CursorPosition.y;
+
+ i = FindCurrentObject(&offs);
+ cerr << " line length: " << GetLineLength(i) << " ";
+ if(i == end())
+ {
+ cerr << "<<no object found>>" << endl;
+ return; // FIXME we should set cursor position to maximum allowed
+ // value then
+ }
+ if((*i)->GetType() == WXLO_TYPE_TEXT)
+ {
+ cerr << " \"" << ((wxLayoutObjectText *)(*i))->GetText() << "\", offs: "
+ << offs << endl;
+ }
+ else
+ cerr << ' ' << _t[(*i)->GetType()] << endl;
+
+}
+#endif
+
+/******************** editing stuff ********************/
+
+wxLayoutObjectList::iterator
+wxLayoutList::FindObjectCursor(wxPoint const &cpos, CoordType *offset)
+{
+ wxPoint cursor = wxPoint(0,0); // runs along the objects
+ CoordType width;
+ wxLayoutObjectList::iterator i;
+
+#ifdef DEBUG
+ cerr << "Looking for object at " << cpos.x << ',' << cpos.y <<
+ endl;
+#endif
+ for(i = begin(); i != end() && cursor.y <= cpos.y; i++)
+ {
+ width = 0;
+ if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
+ {
+ if(cpos.y == cursor.y)
+ {
+ --i;
+ if(offset)
+ *offset = (*i)->CountPositions();
+ return i;
+ }
+ cursor.x = 0; cursor.y ++;
+ }
+ else
+ cursor.x += (width = (*i)->CountPositions());
+ if(cursor.y == cpos.y && (cursor.x > cpos.x ||
+ ((*i)->GetType() != WXLO_TYPE_CMD && cursor.x == cpos.x))
+ ) // found it ?
+ {
+ if(offset)
+ *offset = cpos.x-(cursor.x-width); // 0==cursor before
+ // the object
+#ifdef DEBUG
+ cerr << " found object at " << cursor.x-width << ',' <<
+ cursor.y << ", type:" << _t[(*i)->GetType()] <<endl;
+#endif
+ return i;
+ }
+ }
+#ifdef DEBUG
+ cerr << " not found" << endl;
+#endif
+ return end(); // not found
+}
+
+wxLayoutObjectList::iterator
+wxLayoutList::FindCurrentObject(CoordType *offset)
+{
+ wxLayoutObjectList::iterator obj = end();
+
+ obj = FindObjectCursor(m_CursorPosition, offset);
+ if(obj == end()) // not ideal yet
+ {
+ obj = tail();
+ if(obj != end()) // tail really exists
+ *offset = (*obj)->CountPositions(); // at the end of it
+ }
+ return obj;
+}
+
+void
+wxLayoutList::MoveCursor(int dx, int dy)
+{
+ CoordType offs, lineLength;
+ wxLayoutObjectList::iterator i;
+
+
+ if(dy > 0 && m_CursorPosition.y < m_MaxLine)
+ m_CursorPosition.y += dy;
+ else if(dy < 0 && m_CursorPosition.y > 0)
+ m_CursorPosition.y += dy; // dy is negative
+ if(m_CursorPosition.y < 0)
+ m_CursorPosition.y = 0;
+ else if (m_CursorPosition.y > m_MaxLine)
+ m_CursorPosition.y = m_MaxLine;
+
+ while(dx > 0)
+ {
+ i = FindCurrentObject(&offs);
+ lineLength = GetLineLength(i);
+ if(m_CursorPosition.x < lineLength)
+ {
+ m_CursorPosition.x ++;
+ dx--;
+ continue;
+ }
+ else
+ {
+ if(m_CursorPosition.y < m_MaxLine)
+ {
+ m_CursorPosition.y++;
+ m_CursorPosition.x = 0;
+ dx--;
+ }
+ else
+ break; // cannot move there
+ }
+ }
+ while(dx < 0)
+ {
+ if(m_CursorPosition.x > 0)
+ {
+ m_CursorPosition.x --;
+ dx++;
+ }
+ else
+ {
+ if(m_CursorPosition.y > 0)
+ {
+ m_CursorPosition.y --;
+ m_CursorPosition.x = 0;
+ i = FindCurrentObject(&offs);
+ lineLength = GetLineLength(i);
+ m_CursorPosition.x = lineLength;
+ dx++;
+ continue;
+ }
+ else
+ break; // cannot move left any more
+ }
+ }
+ // final adjustment:
+ i = FindCurrentObject(&offs);
+ lineLength = GetLineLength(i);
+ if(m_CursorPosition.x > lineLength)
+ m_CursorPosition.x = lineLength;
+
+#ifdef DEBUG
+ i = FindCurrentObject(&offs);
+ cerr << "Cursor: "
+ << m_CursorPosition.x << ','
+ << m_CursorPosition.y;
+
+ if(i == end())
+ {
+ cerr << "<<no object found>>" << endl;
+ return; // FIXME we should set cursor position to maximum allowed
+ // value then
+ }
+ if((*i)->GetType() == WXLO_TYPE_TEXT)
+ {
+ cerr << " \"" << ((wxLayoutObjectText *)(*i))->GetText() << "\", offs: "
+ << offs << endl;
+ }
+ else
+ cerr << ' ' << _t[(*i)->GetType()] << endl;
+#endif
+}
+
+void
+wxLayoutList::Delete(CoordType count)
+{
+ TRACE(Delete);
+
+ if(!m_Editable)
+ return;
+
+ VAR(count);
+
+ CoordType offs, len;
+ wxLayoutObjectList::iterator i;
+
+ do
+ {
+ i = FindCurrentObject(&offs);
+ if(i == end())
+ return;
+#ifdef DEBUG
+ cerr << "trying to delete: " << _t[(*i)->GetType()] << endl;
+#endif
+ if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
+ m_MaxLine--;
+ if((*i)->GetType() == WXLO_TYPE_TEXT)
+ {
+ wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
+ len = tobj->CountPositions();
+ // If we find the end of a text object, this means that we
+ // have to delete from the object following it.
+ if(offs == len)
+ {
+ i++;
+ if((*i)->GetType() == WXLO_TYPE_TEXT)
+ {
+ offs = 0; // delete from begin of next string
+ tobj = (wxLayoutObjectText *)*i;
+ len = tobj->CountPositions();
+ }
+ else
+ {
+ erase(i);
+ return;
+ }
+ }
+ if(len <= count) // delete this object
+ {
+ count -= len;
+ erase(i);
+ }
+ else
+ {
+ len = count;
+ VAR(offs); VAR(len);
+ tobj->GetText().erase(offs,len);
+ return; // we are done
+ }
+ }
+ else // delete the object
+ {
+ len = (*i)->CountPositions();
+ erase(i); // after this, i is the iterator for the following object
+ if(count > len)
+ count -= len;
+ else
+ count = 0;
+ }
+ }
+ while(count && i != end());
+}
+
+void
+wxLayoutList::Insert(wxLayoutObjectBase *obj)
+{
+ wxASSERT(obj);
+ CoordType offs;
+ wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
+
+ TRACE(Insert(obj));
+
+ if(i == end())
+ push_back(obj);
+ else
+ {
+ // do we have to split a text object?
+ if((*i)->GetType() == WXLO_TYPE_TEXT && offs != 0 && offs != (*i)->CountPositions())
+ {
+ wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
+#ifdef DEBUG
+ cerr << "text: '" << tobj->GetText() << "'" << endl;
+ VAR(offs);
+#endif
+ wxString left = tobj->GetText().substr(0,offs); // get part before cursor
+ VAR(left);
+ tobj->GetText() = tobj->GetText().substr(offs,(*i)->CountPositions()-offs); // keeps the right half
+ VAR(tobj->GetText());
+ insert(i,obj);
+ insert(i,new wxLayoutObjectText(left)); // inserts before
+ }
+ else
+ {
+ wxLayoutObjectList::iterator j = i; // we want to apend after this object
+ j++;
+ if(j != end())
+ insert(j, obj);
+ else
+ push_back(obj);
+ }
+ }
+ m_CursorPosition.x += obj->CountPositions();
+ if(obj->GetType() == WXLO_TYPE_LINEBREAK)
+ m_MaxLine++;
+}
+
+void
+wxLayoutList::Insert(wxString const &text)
+{
+ TRACE(Insert(text));
+
+ if(! m_Editable)
+ return;
+
+ CoordType offs;
+ wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
+
+ if(i != end() && (*i)->GetType() == WXLO_TYPE_TEXT)
+ { // insert into an existing text object:
+ TRACE(inserting into existing object);
+ wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
+ tobj->GetText().insert(offs,text);
+ }
+ else
+ {
+ // check whether the previous object is text:
+ wxLayoutObjectList::iterator j = i;
+ j--;
+ TRACE(checking previous object);
+ if(0 && j != end() && (*j)->GetType() == WXLO_TYPE_TEXT)
+ {
+ wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
+ tobj->GetText()+=text;
+ }
+ else // insert a new text object
+ {
+ TRACE(creating new object);
+ Insert(new wxLayoutObjectText(text)); //FIXME not too optimal, slow
+ return; // position gets incremented in Insert(obj)
+ }
+ }
+ m_CursorPosition.x += strlen(text.c_str());
+}
+
+CoordType
+wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i)
+{
+ if(i == end())
+ return 0;
+
+ CoordType len = 0;
+
+ // search backwards for beginning of line:
+ while(i != begin() && (*i)->GetType() != WXLO_TYPE_LINEBREAK)
+ i--;
+ if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
+ i++;
+ // now we can start counting:
+ while(i != end() && (*i)->GetType() != WXLO_TYPE_LINEBREAK)
+ {
+ len += (*i)->CountPositions();
+ i++;
+ }
+ return len;
+}
+
+void
+wxLayoutList::Clear(void)
+{
+ wxLayoutObjectList::iterator i = begin();
+
+ while(i != end()) // == while valid
+ erase(i);
+
+ // set defaults
+ m_FontPtSize = 12;
+ m_FontUnderline = false;
+ m_FontFamily = wxDEFAULT;
+ m_FontStyle = wxNORMAL;
+ m_FontWeight = wxNORMAL;
+ m_ColourFG = wxTheColourDatabase->FindColour("BLACK");
+ m_ColourBG = wxTheColourDatabase->FindColour("WHITE");
+
+ m_Position = wxPoint(0,0);
+ m_CursorPosition = wxPoint(0,0);
+ m_MaxLine = 0;
+ m_LineHeight = (12*m_FontPtSize)/10;
+ m_MaxX = 0; m_MaxY = 0;
+}
--- /dev/null
+/*-*- c++ -*-********************************************************
+ * wxLayoutList.h - a formatted text rendering engine for wxWindows *
+ * *
+ * (C) 1998 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>
+
+#ifndef DEBUG
+# define DEBUG
+#endif
+
+
+enum wxLayoutObjectType { WXLO_TYPE_INVALID, WXLO_TYPE_TEXT, WXLO_TYPE_CMD, WXLO_TYPE_ICON, WXLO_TYPE_LINEBREAK };
+
+typedef long CoordType;
+
+class wxLayoutList;
+class wxLayoutObjectBase;
+
+KBLIST_DEFINE(wxLayoutObjectList, wxLayoutObjectBase);
+KBLIST_DEFINE(wxLayoutOLinesList, wxLayoutObjectList::iterator);
+
+
+class wxLayoutObjectBase
+{
+public:
+ virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_INVALID; } ;
+ /** Draws an object.
+ @param dc the wxDC to draw on
+ @param position where to draw the top left corner
+ @param baseLine the baseline for alignment, from top of box
+ @draw if set to false, do not draw but just calculate sizes
+ */
+ virtual void Draw(wxDC &dc, wxPoint position, CoordType baseLine,
+ bool draw = true) {};
+
+ virtual wxPoint GetSize(CoordType *baseLine) const { return
+ wxPoint(0,0); };
+ /// returns the number of cursor positions occupied by this object
+ virtual CoordType CountPositions(void) const { return 1; }
+
+ wxLayoutObjectBase() { m_UserData = NULL; }
+ virtual ~wxLayoutObjectBase() {}
+#ifdef DEBUG
+ virtual void Debug(void);
+#endif
+
+ void SetUserData(void *data) { m_UserData = data; }
+ void * GetUserData(void) const { return m_UserData; }
+private:
+ /// optional data for application's use
+ void * m_UserData;
+};
+
+/// object for text block
+class wxLayoutObjectText : public wxLayoutObjectBase
+{
+public:
+ virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_TEXT; }
+ virtual void Draw(wxDC &dc, wxPoint position, CoordType baseLine,
+ bool draw = true);
+ /** This returns the height and in baseLine the position of the
+ text's baseline within it's box. This is needed to properly
+ align text objects.
+ */
+ virtual wxPoint GetSize(CoordType *baseLine) const;
+#ifdef DEBUG
+ virtual void Debug(void);
+#endif
+
+ wxLayoutObjectText(const wxString &txt);
+ virtual CoordType CountPositions(void) const { return strlen(m_Text.c_str()); }
+
+ // for editing:
+ wxString & GetText(void) { return m_Text; }
+ void SetText(wxString const &text) { m_Text = text; }
+private:
+ wxString m_Text;
+ /// size of the box containing text
+ long m_Width, m_Height;
+ /// the position of the baseline counted from the top of the box
+ long m_BaseLine;
+};
+
+/// icon/pictures:
+class wxLayoutObjectIcon : public wxLayoutObjectBase
+{
+public:
+ virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_ICON; }
+ virtual void Draw(wxDC &dc, wxPoint position, CoordType baseLine,
+ bool draw = true);
+ virtual wxPoint GetSize(CoordType *baseLine) const;
+ wxLayoutObjectIcon(wxIcon *icon);
+private:
+ wxIcon * m_Icon;
+};
+
+/// for export to html:
+struct wxLayoutStyleInfo
+{
+ int size, family, style, weight;
+ bool underline;
+ unsigned fg_red, fg_green, fg_blue;
+ unsigned bg_red, bg_green, bg_blue;
+};
+
+/// pseudo-object executing a formatting command in Draw()
+class wxLayoutObjectCmd : public wxLayoutObjectBase
+{
+public:
+ virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_CMD; }
+ virtual void Draw(wxDC &dc, wxPoint position, CoordType baseLine,
+ bool draw = true);
+ wxLayoutObjectCmd(int size, int family, int style, int weight,
+ bool underline,
+ wxColour const *fg, wxColour const *bg);
+ ~wxLayoutObjectCmd();
+ // caller must free pointer:
+ wxLayoutStyleInfo *GetStyle(void) const ;
+private:
+ /// the font to use
+ wxFont *m_font;
+ /// foreground colour
+ wxColour const *m_ColourFG;
+ /// background colour
+ wxColour const *m_ColourBG;
+};
+
+/// this object doesn't do anything at all
+class wxLayoutObjectLineBreak : public wxLayoutObjectBase
+{
+public:
+ virtual wxLayoutObjectType GetType(void) const { return WXLO_TYPE_LINEBREAK; }
+};
+
+
+/**
+ This class provides a high level abstraction to the wxFText
+ classes.
+ It handles most of the character events with its own callback
+ functions, providing an editing ability. All events which cannot be
+ handled get passed to the parent window's handlers.
+*/
+class wxLayoutList : public wxLayoutObjectList
+{
+public:
+ wxLayoutList();
+
+ /// Destructor.
+ ~wxLayoutList();
+
+ /// adds an object:
+ void AddObject(wxLayoutObjectBase *obj);
+ void AddText(wxString const &txt);
+
+ void LineBreak(void);
+ void SetFont(int family, int size, int style,
+ int weight, int underline,
+ wxColour const *fg,
+ wxColour const *bg);
+ 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);
+ /** Draw the list on a given DC.
+ @param findObject if true, return the object occupying the
+ position specified by coords
+ @param coords position where to find the object
+ @return if findObject == true, the object or NULL
+ */
+ wxLayoutObjectBase *Draw(wxDC &dc, bool findObject = false,
+ wxPoint const &coords = wxPoint(0,0));
+
+#ifdef DEBUG
+ void Debug(void);
+#endif
+
+
+ /// for access by wxLayoutWindow:
+ void GetSize(CoordType *max_x, CoordType *max_y,
+ CoordType *lineHeight);
+
+ /**@name Functionality for editing */
+ //@{
+ /// set list editable or read only
+ void SetEditable(bool editable = true) { m_Editable = true; }
+ /// move cursor
+ void MoveCursor(int dx = 0, int dy = 0);
+ void SetCursor(wxPoint const &p) { m_CursorPosition = p; }
+ /// delete one or more cursor positions
+ void Delete(CoordType count = 1);
+ void Insert(wxString const &text);
+ void Insert(wxLayoutObjectBase *obj);
+ void Clear(void);
+
+ //@}
+protected:
+ /// font parameters:
+ int m_FontFamily, m_FontStyle, m_FontWeight;
+ int m_FontPtSize;
+ bool m_FontUnderline;
+ /// colours:
+ wxColour const * m_ColourFG;
+ wxColour const * m_ColourBG;
+
+ /// needs recalculation?
+ bool m_dirty;
+
+ // the currently updated line:
+ /// where do we draw next:
+ wxPoint m_Position;
+ /// the height of the current line:
+ CoordType m_LineHeight;
+ /// maximum drawn x position so far
+ CoordType m_MaxX;
+ /// maximum drawn y position:
+ CoordType m_MaxY;
+
+ //---- this is needed for editing:
+ /// where is the text cursor:
+ wxPoint m_CursorPosition;
+ /// which is the last line
+ CoordType m_MaxLine;
+ /// can we edit it?
+ bool m_Editable;
+ /// find the object to the cursor position and returns the offset
+ /// in there
+ wxLayoutObjectList::iterator FindObjectCursor(wxPoint const &cpos, CoordType *offset = NULL);
+ wxLayoutObjectList::iterator FindCurrentObject(CoordType *offset = NULL);
+ // get the length of the line with the object pointed to by i
+ CoordType GetLineLength(wxLayoutObjectList::iterator i);
+
+};
+
+#endif // WXLLIST_H
--- /dev/null
+/*-*- c++ -*-********************************************************
+ * wxlparser.h : parsers, import/export for wxLayoutList *
+ * *
+ * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) *
+ * *
+ * $Id$
+ *******************************************************************/
+
+#ifdef __GNUG__
+# pragma implementation "wxlparser.h"
+#endif
+
+#include "wxllist.h"
+#include "wxlparser.h"
+
+#define BASE_SIZE 12
+
+void wxLayoutImportText(wxLayoutList &list, wxString const &str)
+{
+ char * cptr = (char *)str.c_str(); // string gets changed only temporarily
+ const char * begin = cptr;
+ char backup;
+
+ for(;;)
+ {
+ begin = cptr++;
+ while(*cptr && *cptr != '\n')
+ cptr++;
+ backup = *cptr;
+ *cptr = '\0';
+ list.Insert(begin);
+ *cptr = backup;
+ if(backup == '\n')
+ list.LineBreak();
+ else if(backup == '\0') // reached end of string
+ break;
+ cptr++;
+ }
+}
+
+static
+wxString wxLayoutExportCmdAsHTML(wxLayoutObjectCmd const & cmd,
+ wxLayoutStyleInfo **lastStylePtr)
+{
+ static char buffer[20];
+ wxString html;
+
+ wxLayoutStyleInfo *si = cmd.GetStyle();
+ wxLayoutStyleInfo *last_si = NULL;
+
+ int size, sizecount;
+
+ if(lastStylePtr != NULL)
+ last_si = *lastStylePtr;
+
+ html += "<font ";
+
+ html +="color=";
+ sprintf(buffer,"\"#%02X%02X%02X\"", si->fg_red,si->fg_green,si->fg_blue);
+ html += buffer;
+
+
+ html += " bgcolor=";
+ sprintf(buffer,"\"#%02X%02X%02X\"", si->bg_red,si->bg_green,si->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(last_si != NULL)
+ html ="</font>"+html; // terminate any previous font command
+
+ if((si->weight == wxBOLD) && ( (!last_si) || (last_si->weight != wxBOLD)))
+ html += "<b>";
+ else
+ if(si->weight != wxBOLD && ( last_si && (last_si->weight == wxBOLD)))
+ html += "</b>";
+
+ if(si->style == wxSLANT)
+ si->style = wxITALIC; // the same for html
+
+ if((si->style == wxITALIC) && ( (!last_si) || (last_si->style != wxITALIC)))
+ html += "<i>";
+ else
+ if(si->style != wxITALIC && ( last_si && (last_si->style == wxITALIC)))
+ html += "</i>";
+
+ if(si->underline && ( (!last_si) || ! last_si->underline))
+ html += "<u>";
+ else if(si->underline == false && ( last_si && last_si->underline))
+ html += "</u>";
+
+ if(last_si)
+ delete last_si;
+ *lastStylePtr = si;
+ return html;
+}
+
+
+
+#define WXLO_IS_TEXT(type) \
+( (type == WXLO_TYPE_TEXT || type == WXLO_TYPE_LINEBREAK) \
+ || (type == WXLO_TYPE_CMD \
+ && mode == WXLO_EXPORT_AS_HTML))
+
+
+
+ wxLayoutExportObject *wxLayoutExport(wxLayoutList &list,
+ wxLayoutList::iterator &from,
+ wxLayoutExportMode mode)
+{
+ if(from == list.end())
+ return NULL;
+
+ wxLayoutObjectType type = (*from)->GetType();
+ wxLayoutExportObject * export = new wxLayoutExportObject();
+
+ static wxLayoutStyleInfo *s_si = NULL;
+
+ if( mode == WXLO_EXPORT_AS_OBJECTS || ! WXLO_IS_TEXT(type)) // simple case
+ {
+ export->type = WXLO_EXPORT_OBJECT;
+ export->content.object = *from;
+ from++;
+ return export;
+ }
+
+ wxString *str = new wxString();
+
+ // text must be concatenated
+ while(from != list.end() && WXLO_IS_TEXT(type))
+ {
+ switch(type)
+ {
+ case WXLO_TYPE_TEXT:
+ *str += ((wxLayoutObjectText *)*from)->GetText();
+ break;
+ case WXLO_TYPE_LINEBREAK:
+ if(mode == WXLO_EXPORT_AS_HTML)
+ *str += "<br>";
+ *str += '\n';
+ break;
+ case WXLO_TYPE_CMD:
+ //wxASSERT(mode == WXLO_EXPORT_AS_HTML,"reached cmd object in text mode")
+ assert(mode == WXLO_EXPORT_AS_HTML);
+ *str += wxLayoutExportCmdAsHTML(*(wxLayoutObjectCmd const
+ *)*from, &s_si);
+ break;
+ default: // ignore icons
+ ;
+ }
+ from++;
+ if(from != list.end())
+ type = (*from)->GetType();
+ }
+ export->type = (mode == WXLO_EXPORT_AS_HTML) ? WXLO_EXPORT_HTML : WXLO_EXPORT_TEXT;
+ export->content.text = str;
+ return export;
+}
--- /dev/null
+/*-*- 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
+};
+
+enum wxLayoutExportMode
+{
+ WXLO_EXPORT_AS_TEXT,
+ WXLO_EXPORT_AS_TEXT_AND_COMMANDS,
+ WXLO_EXPORT_AS_HTML,
+ WXLO_EXPORT_AS_OBJECTS
+};
+
+struct wxLayoutExportObject
+{
+ wxLayoutExportType type;
+ union
+ {
+ wxString *text;
+ wxLayoutObjectBase *object;
+ }content;
+ ~wxLayoutExportObject()
+ {
+ if(type == WXLO_EXPORT_TEXT || type == WXLO_EXPORT_HTML)
+ delete content.text;
+ }
+};
+
+/// import text into a wxLayoutList (including linefeeds):
+void wxLayoutImportText(wxLayoutList &list, wxString const &str);
+
+
+wxLayoutExportObject *wxLayoutExport(wxLayoutList &list,
+ wxLayoutList::iterator &from,
+ wxLayoutExportMode WXLO_EXPORT_AS_TEXT);
+
+#endif //WXLPARSER_H
--- /dev/null
+/*-*- c++ -*-********************************************************
+ * wxLwindow.h : a scrolled Window for displaying/entering rich text*
+ * *
+ * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) *
+ * *
+ * $Id$
+ *******************************************************************/
+
+#ifdef __GNUG__
+# pragma implementation "wxlwindow.h"
+#endif
+
+#include "wxlwindow.h"
+
+#define VAR(x) cout << #x"=" << x << endl;
+
+BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow)
+ EVT_PAINT (wxLayoutWindow::OnPaint)
+ EVT_CHAR (wxLayoutWindow::OnChar)
+ EVT_LEFT_DOWN(wxLayoutWindow::OnMouse)
+END_EVENT_TABLE()
+
+wxLayoutWindow::wxLayoutWindow(wxWindow *parent)
+ : wxScrolledWindow(parent)
+{
+ m_ScrollbarsSet = false;
+ m_EventId = 0;
+}
+
+void
+wxLayoutWindow::OnMouse(wxMouseEvent& event)
+{
+ if(m_EventId == 0) // nothing to do
+ return;
+
+ m_FindPos.x = event.GetX();
+ m_FindPos.y = event.GetY();
+ m_FoundObject = NULL;
+
+#ifdef DEBUG
+ cerr << "OnMouse: " << m_FindPos.x << ',' << m_FindPos.y << endl;
+#endif
+ Refresh();
+ if(m_FoundObject)
+ {
+ if(m_EventId)
+ {
+ wxCommandEvent commandEvent(wxEVENT_TYPE_MENU_COMMAND, m_EventId);
+ commandEvent.SetEventObject( this );
+ GetEventHandler()->ProcessEvent(commandEvent);
+ }
+ }
+}
+
+/*
+ * some simple keyboard handling
+ */
+void
+wxLayoutWindow::OnChar(wxKeyEvent& event)
+{
+ long keyCode = event.KeyCode();
+
+ switch(event.KeyCode())
+ {
+ case WXK_RIGHT:
+ m_llist.MoveCursor(1);
+ break;
+ case WXK_LEFT:
+ m_llist.MoveCursor(-1);
+ break;
+ case WXK_UP:
+ m_llist.MoveCursor(0,-1);
+ break;
+ case WXK_DOWN:
+ m_llist.MoveCursor(0,1);
+ break;
+ case WXK_PRIOR:
+ m_llist.MoveCursor(0,-20);
+ break;
+ case WXK_NEXT:
+ m_llist.MoveCursor(0,20);
+ break;
+ case WXK_DELETE :
+ m_llist.Delete(1);
+ break;
+ case WXK_BACK: // backspace
+ m_llist.MoveCursor(-1);
+ m_llist.Delete(1);
+ break;
+ case WXK_RETURN:
+ m_llist.LineBreak();
+ break;
+#ifdef DEBUG
+ case WXK_F1:
+ m_llist.Debug();
+ break;
+#endif
+ default:
+ if(keyCode < 256 && keyCode >= 32)
+ {
+ wxString tmp;
+ tmp += keyCode;
+ m_llist.Insert(tmp);
+ }
+ break;
+ }
+ Refresh();
+ UpdateScrollbars();
+}
+
+void
+wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)w) // or: OnDraw(wxDC& dc)
+{
+ wxPaintDC dc( this ); // only when used as OnPaint for OnDraw we
+ PrepareDC( dc ); // can skip the first two lines
+
+ if(m_EventId) // look for keyclicks
+ m_FoundObject = m_llist.Draw(dc,true,m_FindPos);
+ else
+ m_llist.Draw(dc);
+ if(! m_ScrollbarsSet)
+ {
+ m_ScrollbarsSet = true; // avoid recursion
+ UpdateScrollbars();
+ }
+}
+
+void
+wxLayoutWindow::UpdateScrollbars(void)
+{
+ CoordType
+ max_x, max_y, lineHeight;
+
+ m_llist.GetSize(&max_x, &max_y, &lineHeight);
+ SetScrollbars(10, lineHeight, max_x/10+1, max_y/lineHeight+1);
+ EnableScrolling(true,true);
+}
+
+void
+wxLayoutWindow::Print(void)
+{
+ wxPostScriptDC dc("layout.ps",true,this);
+ if (dc.Ok() && dc.StartDoc((char *)_("Printing message...")))
+ {
+ //dc.SetUserScale(1.0, 1.0);
+ m_llist.Draw(dc);
+ dc.EndDoc();
+ }
+}
--- /dev/null
+/*-*- c++ -*-********************************************************
+ * wxLwindow.h : a scrolled Window for displaying/entering rich text*
+ * *
+ * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) *
+ * *
+ * $Id$
+ *******************************************************************/
+#ifndef WXLWINDOW_H
+#define WXLWINDOW_H
+
+#ifdef __GNUG__
+# pragma interface "wxlwindow.h"
+#endif
+
+#include <wx/wx.h>
+
+#include "wxllist.h"
+
+class wxLayoutWindow : public wxScrolledWindow
+{
+public:
+ wxLayoutWindow(wxWindow *parent);
+
+ wxLayoutList & GetLayoutList(void) { return m_llist; }
+
+ //virtual void OnDraw(wxDC &dc);
+ void OnPaint(wxPaintEvent &WXUNUSED(event));
+ virtual void OnMouse(wxMouseEvent& event);
+ virtual void OnChar(wxKeyEvent& event);
+ void UpdateScrollbars(void);
+ void Print(void);
+ void Erase(void)
+ { m_llist.Clear(); Clear(); }
+ void SetEventId(int id) { m_EventId = id; }
+private:
+ int m_EventId;
+ /// the layout list to be displayed
+ wxLayoutList m_llist;
+ /// have we already set the scrollbars?
+ bool m_ScrollbarsSet;
+ /// if we want to find an object:
+ wxPoint m_FindPos;
+ wxLayoutObjectBase *m_FoundObject;
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif