--- /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
+/*
+ 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;
+
--- /dev/null
+
+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
+
--- /dev/null
+
+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.
--- /dev/null
+/*-*- 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
--- /dev/null
+/*-*- 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
--- /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 "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;
+};
+
+
+
+
+
--- /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 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__
--- /dev/null
+/*-*- 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();
+}
+
--- /dev/null
+/*-*- 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
--- /dev/null
+/*-*- 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;
+}
+
--- /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,
+ // 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
--- /dev/null
+/*-*- 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(®ion);
+}
+
+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();
+}
--- /dev/null
+/*-*- 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