1 /*-*- c++ -*-********************************************************
2 * wxFTCanvas: a canvas for editing formatted text *
4 * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) *
7 *******************************************************************/
10 - each Object knows its size and how to draw itself
11 - the list is responsible for calculating positions
12 - the draw coordinates for each object are the top left corner
13 - coordinates only get calculated when things get redrawn
14 - during redraw each line gets iterated over twice, first just
15 calculating baselines and positions, second to actually draw it
16 - the cursor position is the position before an object, i.e. if the
17 buffer starts with a text-object, cursor 0,0 is just before the
20 - the cursor position and size must be decided at layout/draw time
21 or the fonts will be wrong
26 - MaxX()/MaxY() don't get set
31 #pragma implementation "wxllist.h"
36 # include "gui/wxllist.h"
42 # include "iostream.h"
44 # include <wx/postscrp.h>
45 # include <wx/print.h>
49 #define BASELINESTRETCH 12
51 // This should never really get created
52 #define WXLLIST_TEMPFILE "__wxllist.tmp"
55 static const char *g_aTypeStrings
[] =
57 "invalid", "text", "cmd", "icon", "linebreak"
60 # define wxLayoutDebug wxLogDebug
61 # define WXL_VAR(x) cerr << #x " = " << x << endl;
62 # define WXL_DBG_POINT(p) wxLogDebug(#p ": (%d, %d)", p.x, p.y)
63 # define WXL_TRACE(f) wxLogDebug(#f ": ")
64 # define TypeString(t) g_aTypeStrings[t]
67 wxLayoutObjectBase::Debug(void)
70 wxLogDebug("%s: size = %dx%d, bl = %d",
71 TypeString(GetType()), GetSize(&bl
).x
, GetSize(&bl
).y
, bl
);
76 # define WXL_DBG_POINT(p)
78 # define ShowCurrentObject()
79 # define TypeString(t) ""
80 inline void wxLayoutDebug(const char *, ...) { }
84 //-------------------------- wxLayoutObjectText
86 wxLayoutObjectText::wxLayoutObjectText(const String
&txt
)
91 m_Position
= wxPoint(-1,-1);
96 wxLayoutObjectText::GetSize(CoordType
*baseLine
) const
98 if(baseLine
) *baseLine
= m_BaseLine
;
99 return wxPoint(m_Width
, m_Height
);
103 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &translate
)
105 dc
.DrawText(Str(m_Text
), m_Position
.x
+ translate
.x
, m_Position
.y
+translate
.y
);
111 wxLayoutObjectText::Layout(wxDC
&dc
, wxPoint position
, CoordType baseLine
)
115 if(m_Position
.x
!= position
.x
|| m_Position
.y
!= position
.y
)
118 m_Position
= position
;
119 dc
.GetTextExtent(Str(m_Text
),&m_Width
, &m_Height
, &descent
);
120 m_BaseLine
= m_Height
- descent
;
121 if(m_Position
.x
!= position
.x
|| m_Position
.y
!= position
.y
)
125 #ifdef WXLAYOUT_DEBUG
127 wxLayoutObjectText::Debug(void)
129 wxLayoutObjectBase::Debug();
130 wxLogDebug(" `%s`", m_Text
.c_str());
134 //-------------------------- wxLayoutObjectIcon
136 wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon
const &icon
)
138 m_Position
= wxPoint(-1,-1);
139 m_Icon
= new wxIcon(icon
);
142 wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon
*icon
)
148 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &translate
)
150 dc
.DrawIcon(m_Icon
,m_Position
.x
+translate
.x
, m_Position
.y
+translate
.y
);
154 wxLayoutObjectIcon::Layout(wxDC
&dc
, wxPoint position
, CoordType baseLine
)
156 if(m_Position
.x
!= position
.x
|| m_Position
.y
!= position
.y
)
158 m_Position
= position
;
162 wxLayoutObjectIcon::GetSize(CoordType
*baseLine
) const
164 if(baseLine
) *baseLine
= m_Icon
->GetHeight();
165 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
168 //-------------------------- wxLayoutObjectCmd
171 wxLayoutObjectCmd::wxLayoutObjectCmd(int size
, int family
, int style
, int
172 weight
, bool underline
,
173 wxColour
const *fg
, wxColour
const *bg
)
176 m_font
= new wxFont(size
,family
,style
,weight
,underline
);
181 wxLayoutObjectCmd::~wxLayoutObjectCmd()
187 wxLayoutObjectCmd::GetStyle(void) const
189 wxLayoutStyleInfo
*si
= new wxLayoutStyleInfo();
192 si
->size
= m_font
->GetPointSize();
193 si
->family
= m_font
->GetFamily();
194 si
->style
= m_font
->GetStyle();
195 si
->underline
= m_font
->GetUnderlined();
196 si
->weight
= m_font
->GetWeight();
198 si
->fg_red
= m_ColourFG
->Red();
199 si
->fg_green
= m_ColourFG
->Green();
200 si
->fg_blue
= m_ColourFG
->Blue();
201 si
->bg_red
= m_ColourBG
->Red();
202 si
->bg_green
= m_ColourBG
->Green();
203 si
->bg_blue
= m_ColourBG
->Blue();
209 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const &translate
)
214 dc
.SetTextForeground(*m_ColourFG
);
216 dc
.SetTextBackground(*m_ColourBG
);
219 wxLayoutObjectCmd::Layout(wxDC
&dc
, wxPoint p
, CoordType baseline
)
221 m_Position
= p
; // required so we can find the right object for cursor
222 // this get called, so that recalculation uses right font sizes
223 Draw(dc
,wxPoint(0,0));
226 //-------------------------- wxLayoutList
228 wxLayoutList::wxLayoutList()
230 m_DefaultSetting
= NULL
;
234 wxLayoutList::~wxLayoutList()
237 delete m_DefaultSetting
;
238 // no deletion of objects, they are owned by the list
242 wxLayoutList::LineBreak(void)
244 Insert(new wxLayoutObjectLineBreak
);
245 m_CursorPosition
.x
= 0; m_CursorPosition
.y
++;
249 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
250 int underline
, wxColour
const *fg
,
253 if(family
!= -1) m_FontFamily
= family
;
254 if(size
!= -1) m_FontPtSize
= size
;
255 if(style
!= -1) m_FontStyle
= style
;
256 if(weight
!= -1) m_FontWeight
= weight
;
257 if(underline
!= -1) m_FontUnderline
= underline
!= 0;
259 if(fg
!= NULL
) m_ColourFG
= fg
;
260 if(bg
!= NULL
) m_ColourBG
= bg
;
263 new wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,m_FontWeight
,m_FontUnderline
,
264 m_ColourFG
, m_ColourBG
));
268 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
269 int underline
, char const *fg
, char const *bg
)
277 cfg
= wxTheColourDatabase
->FindColour(fg
);
279 cbg
= wxTheColourDatabase
->FindColour(bg
);
281 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
285 /// for access by wxLayoutWindow:
287 wxLayoutList::GetSize(CoordType
*max_x
, CoordType
*max_y
,
288 CoordType
*lineHeight
)
291 if(max_x
) *max_x
= m_MaxX
;
292 if(max_y
) *max_y
= m_MaxY
;
293 if(lineHeight
) *lineHeight
= m_LineHeight
;
297 wxLayoutList::ResetSettings(wxDC
&dc
)
299 // setting up the default:
300 dc
.SetTextForeground( *wxBLACK
);
301 dc
.SetTextBackground( *wxWHITE
);
302 dc
.SetBackgroundMode( wxSOLID
); // to enable setting of text background
303 dc
.SetFont( *wxNORMAL_FONT
);
305 m_DefaultSetting
->Draw(dc
,wxPoint(0,0));
309 wxLayoutList::Layout(wxDC
&dc
, wxLayoutMargins
*margins
)
313 // first object in current line
314 wxLayoutObjectList::iterator headOfLine
;
315 // where we draw next
316 wxPoint position
, position_HeadOfLine
;
317 // size of last object
319 CoordType baseLine
= m_FontPtSize
;
320 CoordType baseLineSkip
= (BASELINESTRETCH
* baseLine
)/10;
321 CoordType objBaseLine
= baseLine
;
322 wxLayoutObjectType type
;
324 // we need to count cursor positions
325 wxPoint cursorPos
= wxPoint(0,0);
327 wxLayoutObjectBase
*cursorObject
= NULL
; // let's find it again
331 position
.y
= margins
->top
;
332 position
.x
= margins
->left
;
344 position_HeadOfLine
= position
;
351 type
= (*i
)->GetType();
352 (*i
)->Layout(dc
, position
, baseLine
);
353 size
= (*i
)->GetSize(&objBaseLine
);
354 // calculate next object's position:
355 position
.x
+= size
.x
;
357 // do we need to increase the line's height?
358 if(size
.y
> baseLineSkip
)
360 baseLineSkip
= size
.y
;
361 i
= headOfLine
; position
= position_HeadOfLine
;
364 if(objBaseLine
> baseLine
)
366 baseLine
= objBaseLine
;
367 i
= headOfLine
; position
= position_HeadOfLine
;
371 // when we reach here, the coordinates are valid, this part of
372 // the loop gets run only once per object
373 if(position
.x
> m_MaxX
)
375 if(type
== WXLO_TYPE_LINEBREAK
)
377 cursorPos
.x
= 0; cursorPos
.y
++;
380 cursorPos
.x
+= (**i
).CountPositions();
382 // now check whether we have finished handling this line:
383 if(type
== WXLO_TYPE_LINEBREAK
&& i
!= tail())
385 position
.x
= margins
? margins
->left
: 0;
386 position
.y
+= baseLineSkip
;
387 baseLine
= m_FontPtSize
;
388 objBaseLine
= baseLine
; // not all objects set it
389 baseLineSkip
= (BASELINESTRETCH
* baseLine
)/10;
392 position_HeadOfLine
= position
;
394 if(cursorObject
== NULL
&& cursorPos
.y
== m_CursorPosition
.y
) // look for cursor
396 if(cursorPos
.x
>= m_CursorPosition
.x
&&
397 m_CursorPosition
.x
-cursorPos
.x
+(**i
).CountPositions()) // cursor is in current object
406 m_MaxY
= position
.y
+ baseLineSkip
;
410 wxLayoutList::Draw(wxDC
&dc
,
411 CoordType fromLine
, CoordType toLine
,
413 wxPoint
const &translate
)
415 Layout(dc
); // FIXME just for now
419 wxLayoutObjectList::iterator i
;
421 if(start
== iterator(NULL
))
423 else // we need to restore font settings
425 for( i
= begin() ; i
!= start
; i
++)
426 if((**i
).GetType() == WXLO_TYPE_CMD
)
427 (**i
).Draw(dc
,translate
); // apply font settings
430 while( start
!= end() && (**start
).GetPosition().y
< fromLine
)
432 if((**start
).GetType() == WXLO_TYPE_CMD
)
433 (**start
).Draw(dc
,translate
); // apply font settings
437 i
!= end() && (toLine
== -1 || (**i
).GetPosition().y
< toLine
) ;
439 (*i
)->Draw(dc
,translate
);
442 /** Erase at least to end of line */
444 wxLayoutList::EraseAndDraw(wxDC
&dc
, iterator start
)
446 //look for begin of line
447 while(start
!= end() && start
!= begin() && (**start
).GetType() !=
450 if(start
== iterator(NULL
))
452 if(start
== iterator(NULL
))
455 wxPoint p
= (**start
).GetPosition();
457 WXL_VAR(p
.x
);WXL_VAR(p
.y
);
458 //FIXME: wxGTK: MaxX()/MaxY() broken
459 //WXL_VAR(dc.MaxX()); WXL_VAR(dc.MaxY());
460 dc
.SetBrush(*wxWHITE_BRUSH
);
461 dc
.SetPen(wxPen(*wxWHITE
,0,wxTRANSPARENT
));
462 dc
.DrawRectangle(p
.x
,p
.y
,2000,2000); //dc.MaxX(),dc.MaxY());
463 Draw(dc
,-1,-1,start
,wxPoint(0,0));
464 //dc.DrawRectangle(p.x,p.y,2000,2000); //dc.MaxX(),dc.MaxY());
469 wxLayoutList::CalculateCursor(wxDC
&dc
)
471 CoordType width
, height
, descent
;
472 CoordType baseLineSkip
= 20; //FIXME
475 wxLayoutObjectBase
&obj
= **FindCurrentObject(&offset
);
478 DrawCursor(dc
,true); // erase it
479 m_CursorCoords
= obj
.GetPosition();
480 WXL_VAR(m_CursorCoords
.x
);
481 if(obj
.GetType() == WXLO_TYPE_TEXT
)
483 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)&obj
;
484 String
& str
= tobj
->GetText();
485 String sstr
= str
.substr(0,offset
);
487 dc
.GetTextExtent(sstr
,&width
,&height
,&descent
);
489 m_CursorCoords
= wxPoint(m_CursorCoords
.x
+width
,
491 m_CursorSize
= wxPoint(2,height
);
493 else if(obj
.GetType() == WXLO_TYPE_LINEBREAK
)
495 m_CursorCoords
= wxPoint(0, m_CursorCoords
.y
);
496 m_CursorSize
= wxPoint(2,baseLineSkip
);
500 // this is not necessarily the most "beautiful" solution:
501 //cursorPosition = wxPoint(position.x, position.y);
502 //cursorSize = wxPoint(size.x > 0 ? size.x : 1,size.y > 0 ? size.y : baseLineSkip);
503 m_CursorCoords
= wxPoint(m_CursorCoords
.x
+obj
.GetSize().x
, m_CursorCoords
.y
);
504 m_CursorSize
= wxPoint(2, obj
.GetSize().y
);
505 if(m_CursorSize
.y
< 1) m_CursorSize
.y
= baseLineSkip
;
507 WXL_VAR(m_CursorCoords
.x
);
508 m_CursorMoved
= false; // coords are valid
512 wxLayoutList::DrawCursor(wxDC
&dc
, bool erase
)
516 //dc.SetBrush(*wxWHITE_BRUSH);
517 //dc.SetPen(wxPen(*wxWHITE,1,wxSOLID));
518 //dc.DrawRectangle(m_CursorCoords.x, m_CursorCoords.y, m_CursorSize.x, m_CursorSize.y);
519 dc
.Blit(m_CursorCoords
.x
, m_CursorCoords
.y
, m_CursorSize
.x
,
520 m_CursorSize
.y
, &m_CursorMemDC
,
525 if(IsDirty() || CursorMoved())
531 wxBitmap
bm(m_CursorSize
.x
+1,m_CursorSize
.y
+1);
532 m_CursorMemDC
.SelectObject(bm
);
533 m_CursorMemDC
.Blit(0, 0, m_CursorSize
.x
, m_CursorSize
.y
,
534 &dc
, m_CursorCoords
.x
,
535 m_CursorCoords
.y
, 0, 0);
536 dc
.SetBrush(*wxBLACK_BRUSH
);
537 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
538 dc
.DrawRectangle(m_CursorCoords
.x
, m_CursorCoords
.y
,
539 m_CursorSize
.x
, m_CursorSize
.y
);
549 #ifdef WXLAYOUT_DEBUG
551 wxLayoutList::Debug(void)
554 wxLayoutObjectList::iterator i
;
556 wxLogDebug("------------------------debug start-------------------------");
557 for(i
= begin(); i
!= end(); i
++)
559 wxLogDebug("-----------------------debug end----------------------------");
561 // show current object:
563 i
= FindCurrentObject(&offs
);
564 wxLogDebug(" line length: %l", (long int) GetLineLength(i
,offs
));
567 wxLogDebug("<<no object found>>");
568 return; // FIXME we should set cursor position to maximum allowed
571 if((*i
)->GetType() == WXLO_TYPE_TEXT
)
572 wxLogDebug(" \"%s\", offs=%d",((wxLayoutObjectText
*)(*i
))->GetText().c_str(), (int) offs
);
574 wxLogDebug(g_aTypeStrings
[(*i
)->GetType()]);
579 wxLayoutList::ShowCurrentObject()
582 wxLayoutObjectList::iterator i
= FindCurrentObject(&offs
);
584 wxLayoutDebug("Cursor is at (%d, %d)",
585 m_CursorPosition
.x
, m_CursorPosition
.y
);
587 i
= FindCurrentObject(&offs
);
588 wxLogDebug(" Line length: %d", GetLineLength(i
));
592 wxLogDebug("<<no object found>>");
593 return; // FIXME we should set cursor position to maximum allowed
596 if((*i
)->GetType() == WXLO_TYPE_TEXT
)
597 wxLogDebug(" \"%s\", offs: %d",
598 ((wxLayoutObjectText
*)(*i
))->GetText().c_str(), offs
);
600 wxLogDebug(" %s", TypeString((*i
)->GetType()));
605 /******************** editing stuff ********************/
607 // don't change this, I know how to optimise this and will do it real
612 * Finds the object belonging to a given cursor position cpos and
613 * returns an iterator to that object and stores the relative cursor
614 * position in offset.
616 * For linebreaks, the offset can be 0=before or 1=after.
618 * If the cpos coordinates don't exist, they are modified.
621 wxLayoutObjectList::iterator
622 wxLayoutList::FindObjectCursor(wxPoint
*cpos
, CoordType
*offset
)
624 wxPoint object
= wxPoint(0,0); // runs along the objects
626 wxLayoutObjectList::iterator i
, begin_it
;
629 //#ifdef WXLAYOUT_DEBUG
630 // wxLayoutDebug("Looking for object at (%d, %d)", cpos->x, cpos->y);
633 // optimisation: compare to last looked at object:
634 if(cpos
->y
> m_FoundCursor
.y
|| (cpos
->y
== m_FoundCursor
.y
&&
635 cpos
->x
>= m_FoundCursor
.x
))
640 //broken at the moment
641 //begin_it = m_FoundIterator;
642 //m_FoundCursor = *cpos;
645 for(i
= begin_it
; i
!= end() && object
.y
<= cpos
->y
; )
647 width
= (**i
).CountPositions();
648 if(cpos
->y
== object
.y
) // a possible candidate
650 if((**i
).GetType() ==WXLO_TYPE_LINEBREAK
)
652 if(cpos
->x
== object
.x
)
654 if(offset
) *offset
= 0;
655 return m_FoundIterator
= i
;
657 if(offset
) *offset
=1;
659 return m_FoundIterator
= i
;
661 if(cpos
->x
>= object
.x
&& cpos
->x
<= object
.x
+width
) // overlap
663 if(offset
) *offset
= cpos
->x
-object
.x
;
664 //#ifdef WXLAYOUT_DEBUG
665 // wxLayoutDebug(" found object at (%d, %d), type: %s",
666 // object.x, object.y, TypeString((*i)->GetType()));
668 return m_FoundIterator
= i
;
671 // no overlap, increment coordinates
673 if((**i
).GetType() == WXLO_TYPE_LINEBREAK
)
683 //#ifdef WXLAYOUT_DEBUG
684 // wxLayoutDebug(" not found");
686 // return last object, coordinates of that one:
689 return m_FoundIterator
= i
;
690 if((**i
).GetType()==WXLO_TYPE_LINEBREAK
)
694 return m_FoundIterator
= i
;
696 cpos
->x
= object
.x
; // would be the coordinate of next object
698 cpos
->x
+= width
; // last object's width
699 if(*offset
) *offset
= cpos
->x
-object
.x
;
700 return m_FoundIterator
= i
; // not found
703 wxLayoutObjectList::iterator
704 wxLayoutList::FindCurrentObject(CoordType
*offset
)
706 wxLayoutObjectList::iterator obj
= end();
708 obj
= FindObjectCursor(&m_CursorPosition
, offset
);
709 if(obj
== end()) // not ideal yet
712 if(obj
!= end()) // tail really exists
713 *offset
= (*obj
)->CountPositions(); // at the end of it
719 wxLayoutList::MoveCursor(int dx
, int dy
)
721 CoordType offs
, lineLength
;
722 wxLayoutObjectList::iterator i
;
724 m_CursorMoved
= true;
726 bool rc
= true; // have we moved?
728 if(dy
> 0 && m_CursorPosition
.y
< m_MaxLine
)
729 m_CursorPosition
.y
+= dy
;
730 else if(dy
< 0 && m_CursorPosition
.y
> 0)
731 m_CursorPosition
.y
+= dy
; // dy is negative
732 if(m_CursorPosition
.y
< 0)
734 m_CursorPosition
.y
= 0;
737 else if (m_CursorPosition
.y
> m_MaxLine
)
739 m_CursorPosition
.y
= m_MaxLine
;
745 i
= FindCurrentObject(&offs
);
746 lineLength
= GetLineLength(i
,offs
);
747 if(m_CursorPosition
.x
< lineLength
)
749 m_CursorPosition
.x
++;
755 if(m_CursorPosition
.y
< m_MaxLine
)
757 m_CursorPosition
.y
++;
758 m_CursorPosition
.x
= 0;
764 break; // cannot move there
770 if(m_CursorPosition
.x
> 0)
772 m_CursorPosition
.x
--;
777 if(m_CursorPosition
.y
> 0)
779 m_CursorPosition
.y
--;
780 m_CursorPosition
.x
= 0;
781 i
= FindCurrentObject(&offs
);
782 lineLength
= GetLineLength(i
,offs
);
783 m_CursorPosition
.x
= lineLength
;
790 break; // cannot move left any more
795 i
= FindCurrentObject(&offs
);
796 lineLength
= GetLineLength(i
,offs
);
797 if(m_CursorPosition
.x
> lineLength
)
799 m_CursorPosition
.x
= lineLength
;
802 #ifdef WXLAYOUT_DEBUG
809 wxLayoutList::Delete(CoordType count
)
821 wxLayoutObjectList::iterator i
;
825 i
= FindCurrentObject(&offs
);
826 startover
: // ugly, but easiest way to do it
828 return; // we cannot delete anything more
830 /* Here we need to treat linebreaks differently.
831 If offs==0 we are before the linebreak, otherwise behind. */
832 if((*i
)->GetType() == WXLO_TYPE_LINEBREAK
)
839 continue; // we're done
841 else // delete the object behind the linebreak
843 i
++; // we increment and continue as normal
848 else if((*i
)->GetType() == WXLO_TYPE_TEXT
)
850 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
851 CoordType len
= tobj
->CountPositions();
852 // If we find the end of a text object, this means that we
853 // have to delete from the object following it.
860 else if(len
<= count
) // delete this object
869 tobj
->GetText().erase(offs
,len
);
870 return; // we are done
873 else// all other objects: delete the object
874 // this only works as expected if the non-text object has 0/1
875 // as offset values. Not tested with "longer" objects.
877 CoordType len
= (*i
)->CountPositions();
880 count
= count
> len
? count
-= len
: 0;
881 erase(i
); // after this, i is the iterator for the following object
884 else // delete the following object
886 i
++; // we increment and continue as normal
892 while(count
&& i
!= end());
896 wxLayoutList::Insert(wxLayoutObjectBase
*obj
)
898 wxCHECK_RET( obj
, "no object to insert" );
903 wxLayoutObjectList::iterator i
= FindCurrentObject(&offs
);
905 // WXL_TRACE(Insert(obj));
911 // do we have to split a text object?
912 else if((*i
)->GetType() == WXLO_TYPE_TEXT
&& offs
!= (*i
)->CountPositions())
914 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
915 #ifdef WXLAYOUT_DEBUG
916 wxLayoutDebug("text: %s", tobj
->GetText().c_str());
919 String left
= tobj
->GetText().substr(0,offs
); // get part before cursor
920 WXL_VAR(left
.c_str());
921 tobj
->GetText() = tobj
->GetText().substr(offs
,(*i
)->CountPositions()-offs
); // keeps the right half
922 WXL_VAR(tobj
->GetText().c_str());
924 insert(i
,new wxLayoutObjectText(left
)); // inserts before
928 // all other cases, append after object:
929 wxLayoutObjectList::iterator j
= i
; // we want to apend after this object
937 m_CursorPosition
.x
+= obj
->CountPositions();
938 if(obj
->GetType() == WXLO_TYPE_LINEBREAK
)
940 m_CursorMoved
= true;
944 wxLayoutList::Insert(String
const &text
)
946 wxLayoutObjectText
*tobj
= NULL
;
947 wxLayoutObjectList::iterator j
;
949 // WXL_TRACE(Insert(text));
957 wxLayoutObjectList::iterator i
= FindCurrentObject(&offs
);
961 Insert(new wxLayoutObjectText(text
));
965 switch((**i
).GetType())
968 // insert into an existing text object:
969 WXL_TRACE(inserting into existing object
);
970 tobj
= (wxLayoutObjectText
*)*i
;
972 tobj
->GetText().insert(offs
,text
);
974 case WXLO_TYPE_LINEBREAK
:
977 if(offs
== 0) // try to append to previous object
980 if(j
!= end() && (**j
).GetType() == WXLO_TYPE_TEXT
)
982 tobj
= (wxLayoutObjectText
*)*j
;
983 tobj
->GetText()+=text
;
986 insert(i
,new wxLayoutObjectText(text
));
988 else // cursor after linebreak
991 if(j
!= end() && (**j
).GetType() == WXLO_TYPE_TEXT
)
993 tobj
= (wxLayoutObjectText
*)*j
;
994 tobj
->GetText()=text
+tobj
->GetText();
999 push_back(new wxLayoutObjectText(text
));
1001 insert(j
,new wxLayoutObjectText(text
));
1006 m_CursorPosition
.x
+= strlen(text
.c_str());
1007 m_CursorMoved
= true;
1011 wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i
, CoordType offs
)
1018 if(offs
== 0 && (**i
).GetType() == WXLO_TYPE_LINEBREAK
)
1019 // we are before a linebrak
1021 // search backwards for beginning of line:
1022 while(i
!= begin() && (*i
)->GetType() != WXLO_TYPE_LINEBREAK
)
1024 if((*i
)->GetType() == WXLO_TYPE_LINEBREAK
)
1026 // now we can start counting:
1027 while(i
!= end() && (*i
)->GetType() != WXLO_TYPE_LINEBREAK
)
1029 len
+= (*i
)->CountPositions();
1036 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1037 int underline
, char const *fg
, char const *bg
)
1040 m_CursorMoved
= true;
1041 m_dirty
= true; // force redraw/recalc
1042 wxLayoutObjectList::iterator i
= begin();
1045 m_CursorMemDC
.SelectObject(bm
);
1047 while(i
!= end()) // == while valid
1051 m_FontPtSize
= size
;
1052 m_FontUnderline
= false;
1053 m_FontFamily
= family
;
1054 m_FontStyle
= style
;
1055 m_FontWeight
= weight
;
1056 m_ColourFG
= wxTheColourDatabase
->FindColour(fg
);
1057 m_ColourBG
= wxTheColourDatabase
->FindColour(bg
);
1059 if(! m_ColourFG
) m_ColourFG
= wxBLACK
;
1060 if(! m_ColourBG
) m_ColourBG
= wxWHITE
;
1062 m_Position
= wxPoint(0,0);
1063 m_CursorPosition
= wxPoint(0,0);
1065 m_LineHeight
= (BASELINESTRETCH
*m_FontPtSize
)/10;
1066 m_MaxX
= 0; m_MaxY
= 0;
1069 m_FoundCursor
= wxPoint(0,0);
1070 m_FoundIterator
= begin();
1072 if(m_DefaultSetting
)
1073 delete m_DefaultSetting
;
1075 m_DefaultSetting
= new
1076 wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,
1077 m_FontWeight
,m_FontUnderline
,
1078 m_ColourFG
, m_ColourBG
);
1082 wxLayoutObjectBase
*
1083 wxLayoutList::Find(wxPoint coords
) const
1085 wxLayoutObjectList::iterator i
= begin();
1087 wxPoint topleft
, bottomright
;
1089 while(i
!= end()) // == while valid
1091 wxLayoutObjectBase
*object
= *i
;
1092 topleft
= object
->GetPosition();
1093 if(coords
.y
>= topleft
.y
&& coords
.x
>= topleft
.x
)
1095 bottomright
= topleft
;
1096 bottomright
.x
+= object
->GetSize().x
;
1097 bottomright
.y
+= object
->GetSize().y
;
1098 if(coords
.x
<= bottomright
.x
&& coords
.y
<= bottomright
.y
)
1107 /******************** printing stuff ********************/
1109 bool wxLayoutPrintout::OnPrintPage(int page
)
1114 DrawHeader(*dc
,wxPoint(m_Margins
.left
,m_Margins
.top
/2),wxPoint(m_Margins
.right
,m_Margins
.top
),page
);
1116 top
= (page
- 1)*m_PrintoutHeight
;
1117 bottom
= top
+ m_PrintoutHeight
;
1118 // SetDeviceOrigin() doesn't work here, so we need to manually
1119 // translate all coordinates.
1120 wxPoint
translate(m_Margins
.left
,-top
+m_Margins
.top
);
1121 m_llist
->Draw(*dc
,top
,bottom
,wxLayoutObjectList::iterator(NULL
),translate
);
1128 bool wxLayoutPrintout::OnBeginDocument(int startPage
, int endPage
)
1130 if (!wxPrintout::OnBeginDocument(startPage
, endPage
))
1137 wxLayoutPrintout::OnPreparePrinting(void)
1143 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
1145 // ugly hack to get number of pages
1147 wxPrinterDC
psdc(WXLLIST_TEMPFILE
,false);
1149 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
1151 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
); // that's all we need it for
1153 // We do 5% margins on top and bottom, and a 5% high header line.
1154 m_Margins
.top
= m_PageHeight
/ 10 ; // 10%, half of it header
1155 m_Margins
.bottom
= m_PageHeight
- m_PageHeight
/ 20; // 95%
1156 // On the sides we reserve 10% each for the margins.
1157 m_Margins
.left
= m_PageWidth
/ 10;
1158 m_Margins
.right
= m_PageWidth
- m_PageWidth
/ 10;
1160 // This is the length of the printable area.
1161 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
1163 //FIXME this is wrong but not used at the moment
1164 m_PageWidth
= m_Margins
.right
- m_Margins
.left
;
1166 m_NumOfPages
= (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
) + 0.5);
1168 *maxPage
= m_NumOfPages
;
1171 *selPageTo
= m_NumOfPages
;
1172 wxRemoveFile(WXLLIST_TEMPFILE
);
1175 bool wxLayoutPrintout::HasPage(int pageNum
)
1177 return pageNum
< m_NumOfPages
;
1182 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
1183 wxPoint topleft
, wxPoint bottomright
,
1186 // make backups of all essential parameters
1187 wxBrush
*brush
= dc
.GetBrush();
1188 wxPen
*pen
= dc
.GetPen();
1189 wxFont
*font
= dc
.GetFont(),
1192 dc
.SetBrush(*wxWHITE_BRUSH
);
1193 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
1194 dc
.DrawRoundedRectangle(topleft
.x
,
1195 topleft
.y
,bottomright
.x
-topleft
.x
,
1196 bottomright
.y
-topleft
.y
);
1197 dc
.SetBrush(*wxBLACK_BRUSH
);
1198 myfont
= new wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
1199 dc
.SetFont(*myfont
);
1202 page
= "9999/9999 "; // many pages...
1204 dc
.GetTextExtent(page
,&w
,&h
);
1205 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
1206 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
1207 dc
.GetTextExtent("XXXX", &w
,&h
);
1208 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
1212 dc
.SetBrush(*brush
);
1220 wxLayoutList::MakePrintout(wxString
const &name
)
1222 return new wxLayoutPrintout(*this,name
);