]>
git.saurik.com Git - wxWidgets.git/blob - user/wxLayout/wxllist.cpp
1 /*-*- c++ -*-********************************************************
2 * wxllist: wxLayoutList, a layout engine for text and graphics *
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 - The cursor position is the position before an object, i.e. if the
15 buffer starts with a text-object, cursor 0,0 is just before the
16 first character. For all non-text objects, the cursor positions
17 are 0==before or 1==behind. So that all non-text objects count as
19 - Linebreaks are at the end of a line, that is a line like "abc\n"
20 is four cursor positions long. This makes sure that cursor
21 positions are "as expected", i.e. in "abc\ndef" the 'd' would be
22 at positions (x=0,y=1).
28 - cursor redraw problems
30 - mouse click positions cursor
31 - selection (SetMark(), GetSelection())
32 - DND acceptance of text / clipboard support
33 - wxlwindow: formatting menu: problem with checked/unchecked consistency gtk bug?
38 - MaxX()/MaxY() don't get set
43 #pragma implementation "wxllist.h"
48 # include "gui/wxllist.h"
54 # include "iostream.h"
56 # include <wx/postscrp.h>
57 # include <wx/print.h>
61 #define BASELINESTRETCH 12
63 // This should never really get created
64 #define WXLLIST_TEMPFILE "__wxllist.tmp"
67 static const char *g_aTypeStrings
[] =
69 "invalid", "text", "cmd", "icon", "linebreak"
72 # define wxLayoutDebug wxLogDebug
73 # define WXL_VAR(x) cerr << #x " = " << x << endl;
74 # define WXL_DBG_POINT(p) wxLayoutDebug(#p ": (%d, %d)", p.x, p.y)
75 # define WXL_TRACE(f) wxLayoutDebug(#f ": ")
76 # define TypeString(t) g_aTypeStrings[t]
79 wxLayoutObjectBase::Debug(void)
82 wxLayoutDebug("%s: size = %dx%d, pos=%d,%d, bl = %d",
83 TypeString(GetType()), GetSize(&bl
).x
,
85 GetPosition().x
, GetPosition().y
, bl
);
90 # define WXL_DBG_POINT(p)
92 # define ShowCurrentObject()
93 # define TypeString(t) ""
94 inline void wxLayoutDebug(const char *, ...) { }
98 //-------------------------- wxLayoutObjectText
100 wxLayoutObjectText::wxLayoutObjectText(const String
&txt
)
105 m_Position
= wxPoint(-1,-1);
110 wxLayoutObjectText::GetSize(CoordType
*baseLine
) const
112 if(baseLine
) *baseLine
= m_BaseLine
;
113 return wxPoint(m_Width
, m_Height
);
117 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &translate
)
119 dc
.DrawText(Str(m_Text
), m_Position
.x
+ translate
.x
, m_Position
.y
+translate
.y
);
125 wxLayoutObjectText::Layout(wxDC
&dc
, wxPoint position
, CoordType baseLine
)
129 if(m_Position
.x
!= position
.x
|| m_Position
.y
!= position
.y
)
132 m_Position
= position
;
133 dc
.GetTextExtent(Str(m_Text
),&m_Width
, &m_Height
, &descent
);
134 m_BaseLine
= m_Height
- descent
;
135 if(m_Position
.x
!= position
.x
|| m_Position
.y
!= position
.y
)
139 #ifdef WXLAYOUT_DEBUG
141 wxLayoutObjectText::Debug(void)
143 wxLayoutObjectBase::Debug();
144 wxLayoutDebug(" `%s`", m_Text
.c_str());
148 //-------------------------- wxLayoutObjectIcon
150 wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon
const &icon
)
152 m_Position
= wxPoint(-1,-1);
153 m_Icon
= new wxIcon(icon
);
156 wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon
*icon
)
162 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &translate
)
164 dc
.DrawIcon(m_Icon
,wxPoint(m_Position
.x
+translate
.x
, m_Position
.y
+translate
.y
));
168 wxLayoutObjectIcon::Layout(wxDC
&dc
, wxPoint position
, CoordType baseLine
)
170 if(m_Position
.x
!= position
.x
|| m_Position
.y
!= position
.y
)
172 m_Position
= position
;
176 wxLayoutObjectIcon::GetSize(CoordType
*baseLine
) const
178 if(baseLine
) *baseLine
= m_Icon
->GetHeight();
179 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
182 //-------------------------- wxLayoutObjectCmd
185 wxLayoutObjectCmd::wxLayoutObjectCmd(int size
, int family
, int style
, int
186 weight
, bool underline
,
187 wxColour
const *fg
, wxColour
const *bg
)
190 m_font
= new wxFont(size
,family
,style
,weight
,underline
);
195 wxLayoutObjectCmd::~wxLayoutObjectCmd()
201 wxLayoutObjectCmd::GetStyle(void) const
203 wxLayoutStyleInfo
*si
= new wxLayoutStyleInfo();
206 si
->size
= m_font
->GetPointSize();
207 si
->family
= m_font
->GetFamily();
208 si
->style
= m_font
->GetStyle();
209 si
->underline
= m_font
->GetUnderlined();
210 si
->weight
= m_font
->GetWeight();
212 si
->fg_red
= m_ColourFG
->Red();
213 si
->fg_green
= m_ColourFG
->Green();
214 si
->fg_blue
= m_ColourFG
->Blue();
215 si
->bg_red
= m_ColourBG
->Red();
216 si
->bg_green
= m_ColourBG
->Green();
217 si
->bg_blue
= m_ColourBG
->Blue();
223 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const &translate
)
228 dc
.SetTextForeground(*m_ColourFG
);
230 dc
.SetTextBackground(*m_ColourBG
);
233 wxLayoutObjectCmd::Layout(wxDC
&dc
, wxPoint p
, CoordType baseline
)
235 m_Position
= p
; // required so we can find the right object for cursor
236 // this get called, so that recalculation uses right font sizes
237 Draw(dc
,wxPoint(0,0));
240 //-------------------------- wxLayoutList
242 wxLayoutList::wxLayoutList()
244 m_DefaultSetting
= NULL
;
251 wxLayoutList::~wxLayoutList()
254 delete m_DefaultSetting
;
255 // no deletion of objects, they are owned by the list
259 wxLayoutList::LineBreak(void)
261 Insert(new wxLayoutObjectLineBreak
);
262 // m_CursorPos.x = 0; m_CursorPos.y++;
266 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
267 int underline
, wxColour
const *fg
,
270 if(family
!= -1) m_FontFamily
= family
;
271 if(size
!= -1) m_FontPtSize
= size
;
272 if(style
!= -1) m_FontStyle
= style
;
273 if(weight
!= -1) m_FontWeight
= weight
;
274 if(underline
!= -1) m_FontUnderline
= underline
!= 0;
276 if(fg
!= NULL
) m_ColourFG
= fg
;
277 if(bg
!= NULL
) m_ColourBG
= bg
;
280 new wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,m_FontWeight
,m_FontUnderline
,
281 m_ColourFG
, m_ColourBG
));
285 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
286 int underline
, char const *fg
, char const *bg
)
294 cfg
= wxTheColourDatabase
->FindColour(fg
);
296 cbg
= wxTheColourDatabase
->FindColour(bg
);
298 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
302 /// for access by wxLayoutWindow:
304 wxLayoutList::GetSize(CoordType
*max_x
, CoordType
*max_y
,
305 CoordType
*lineHeight
)
308 if(max_x
) *max_x
= m_MaxX
;
309 if(max_y
) *max_y
= m_MaxY
;
310 if(lineHeight
) *lineHeight
= m_LineHeight
;
314 wxLayoutList::ResetSettings(wxDC
&dc
)
316 // setting up the default:
317 dc
.SetTextForeground( *wxBLACK
);
318 dc
.SetTextBackground( *wxWHITE
);
319 dc
.SetBackgroundMode( wxSOLID
); // to enable setting of text background
320 dc
.SetFont( *wxNORMAL_FONT
);
322 m_DefaultSetting
->Draw(dc
,wxPoint(0,0));
326 wxLayoutList::Layout(wxDC
&dc
, wxLayoutMargins
*margins
)
330 // first object in current line
331 wxLayoutObjectList::iterator headOfLine
;
332 // where we draw next
333 wxPoint position
, position_HeadOfLine
;
334 // size of last object
336 CoordType baseLine
= m_FontPtSize
;
337 CoordType baseLineSkip
= (BASELINESTRETCH
* baseLine
)/10;
338 CoordType objBaseLine
= baseLine
;
339 wxLayoutObjectType type
;
341 // we need to count cursor positions
342 wxPoint cursorPos
= wxPoint(0,0);
346 position
.y
= margins
->top
;
347 position
.x
= margins
->left
;
359 position_HeadOfLine
= position
;
366 type
= (*i
)->GetType();
367 (*i
)->Layout(dc
, position
, baseLine
);
368 size
= (*i
)->GetSize(&objBaseLine
);
369 // calculate next object's position:
370 position
.x
+= size
.x
;
372 // do we need to increase the line's height?
373 if(size
.y
> baseLineSkip
)
375 baseLineSkip
= size
.y
;
376 i
= headOfLine
; position
= position_HeadOfLine
;
379 if(objBaseLine
> baseLine
)
381 baseLine
= objBaseLine
;
382 i
= headOfLine
; position
= position_HeadOfLine
;
386 // when we reach here, the coordinates are valid, this part of
387 // the loop gets run only once per object
388 if(position
.x
> m_MaxX
)
390 if(type
== WXLO_TYPE_LINEBREAK
)
392 cursorPos
.x
= 0; cursorPos
.y
++;
395 cursorPos
.x
+= (**i
).CountPositions();
397 // now check whether we have finished handling this line:
398 if(type
== WXLO_TYPE_LINEBREAK
&& i
!= tail())
400 position
.x
= margins
? margins
->left
: 0;
401 position
.y
+= baseLineSkip
;
402 baseLine
= m_FontPtSize
;
403 objBaseLine
= baseLine
; // not all objects set it
404 baseLineSkip
= (BASELINESTRETCH
* baseLine
)/10;
407 position_HeadOfLine
= position
;
409 if(i
== m_CursorObject
)
414 m_MaxY
= position
.y
+ baseLineSkip
;
418 wxLayoutList::Draw(wxDC
&dc
,
419 CoordType fromLine
, CoordType toLine
,
421 wxPoint
const &translate
)
423 Layout(dc
); // FIXME just for now
427 wxLayoutObjectList::iterator i
;
429 if(start
== iterator(NULL
))
431 else // we need to restore font settings
433 for( i
= begin() ; i
!= start
; i
++)
434 if((**i
).GetType() == WXLO_TYPE_CMD
)
435 (**i
).Draw(dc
,translate
); // apply font settings
438 while( start
!= end() && (**start
).GetPosition().y
< fromLine
)
440 if((**start
).GetType() == WXLO_TYPE_CMD
)
441 (**start
).Draw(dc
,translate
); // apply font settings
445 i
!= end() && (toLine
== -1 || (**i
).GetPosition().y
< toLine
) ;
447 (*i
)->Draw(dc
,translate
);
450 /** Erase at least to end of line */
452 wxLayoutList::EraseAndDraw(wxDC
&dc
, iterator start
)
454 //look for begin of line
455 while(start
!= end() && start
!= begin() && (**start
).GetType() !=
458 if(start
== iterator(NULL
))
460 if(start
== iterator(NULL
))
463 wxPoint p
= (**start
).GetPosition();
465 //FIXME: wxGTK: MaxX()/MaxY() broken
466 //WXL_VAR(dc.MaxX()); WXL_VAR(dc.MaxY());
468 dc
.SetBrush(wxBrush(*m_ColourBG
, wxSOLID
));
469 dc
.SetPen(wxPen(*m_ColourBG
,0,wxTRANSPARENT
));
470 dc
.DrawRectangle(p
.x
,p
.y
,2000,2000); //dc.MaxX(),dc.MaxY());
471 Draw(dc
,-1,-1,start
,wxPoint(0,0));
472 //dc.DrawRectangle(p.x,p.y,2000,2000); //dc.MaxX(),dc.MaxY());
477 wxLayoutList::CalculateCursor(wxDC
&dc
)
479 CoordType width
, height
, descent
;
480 CoordType baseLineSkip
= 20; //FIXME
482 if( m_CursorObject
== iterator(NULL
)) // empty list
484 m_CursorCoords
= wxPoint(0,0);
485 m_CursorSize
= wxPoint(2,baseLineSkip
);
486 m_CursorMoved
= false; // coords are valid
489 wxLayoutObjectBase
&obj
= **m_CursorObject
;
491 m_CursorCoords
= obj
.GetPosition();
492 if(obj
.GetType() == WXLO_TYPE_TEXT
)
494 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)&obj
;
495 String
& str
= tobj
->GetText();
496 String sstr
= str
.substr(0,m_CursorOffset
);
497 dc
.GetTextExtent(sstr
,&width
,&height
,&descent
);
498 m_CursorCoords
= wxPoint(m_CursorCoords
.x
+width
,
500 m_CursorSize
= wxPoint(2,height
);
502 else if(obj
.GetType() == WXLO_TYPE_LINEBREAK
)
504 if(m_CursorOffset
== 1) // behind linebreak
505 m_CursorCoords
= wxPoint(0, m_CursorCoords
.y
+ baseLineSkip
);
506 //m_CursorCoords = wxPoint(0, m_CursorCoords.y);
507 m_CursorSize
= wxPoint(2,baseLineSkip
);
511 // this is not necessarily the most "beautiful" solution:
512 //cursorPosition = wxPoint(position.x, position.y);
513 //cursorSize = wxPoint(size.x > 0 ? size.x : 1,size.y > 0 ? size.y : baseLineSkip);
514 m_CursorCoords
= wxPoint(m_CursorCoords
.x
+obj
.GetSize().x
, m_CursorCoords
.y
);
515 m_CursorSize
= wxPoint(2, obj
.GetSize().y
);
516 if(m_CursorSize
.y
< 1) m_CursorSize
.y
= baseLineSkip
;
518 m_CursorMoved
= false; // coords are valid
522 wxLayoutList::DrawCursor(wxDC
&dc
, bool erase
)
529 //dc.SetBrush(*wxWHITE_BRUSH);
530 //dc.SetPen(wxPen(*wxWHITE,1,wxSOLID));
531 //dc.DrawRectangle(m_CursorCoords.x, m_CursorCoords.y, m_CursorSize.x, m_CursorSize.y);
532 dc
.Blit(m_CursorCoords
.x
, m_CursorCoords
.y
, m_CursorSize
.x
,
533 m_CursorSize
.y
, &m_CursorMemDC
,
538 if(IsDirty() || CursorMoved())
544 wxBitmap
bm(m_CursorSize
.x
+1,m_CursorSize
.y
+1);
545 m_CursorMemDC
.SelectObject(bm
);
546 m_CursorMemDC
.Blit(0, 0, m_CursorSize
.x
, m_CursorSize
.y
,
547 &dc
, m_CursorCoords
.x
,
548 m_CursorCoords
.y
, 0, 0);
549 dc
.SetBrush(*wxBLACK_BRUSH
);
550 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
551 dc
.DrawRectangle(m_CursorCoords
.x
, m_CursorCoords
.y
,
552 m_CursorSize
.x
, m_CursorSize
.y
);
562 #ifdef WXLAYOUT_DEBUG
564 wxLayoutList::Debug(void)
566 wxLayoutObjectList::iterator i
;
568 wxLayoutDebug("------------------------ debug start ------------------------");
569 for(i
= begin(); i
!= end(); i
++)
571 wxLayoutDebug("-------------------------- list end -------------------------");
573 // show current object:
575 wxLayoutDebug("------------------------- debug end -------------------------");
579 wxLayoutList::ShowCurrentObject()
581 wxLayoutDebug("CursorPos (%d, %d)", (int) m_CursorPos
.x
, (int) m_CursorPos
.y
);
582 wxLayoutDebug("CursorOffset = %d", (int) m_CursorOffset
);
583 wxLayoutDebug("CursorObject = %p", m_CursorObject
);
584 if(m_CursorObject
== iterator(NULL
))
585 wxLayoutDebug("<<no object found>>");
588 if((*m_CursorObject
)->GetType() == WXLO_TYPE_TEXT
)
589 wxLayoutDebug(" \"%s\", offs: %d",
590 ((wxLayoutObjectText
*)(*m_CursorObject
))->GetText().c_str(),
593 wxLayoutDebug(" %s", TypeString((*m_CursorObject
)->GetType()));
595 wxLayoutDebug("Line length: %d", GetLineLength(m_CursorObject
));
601 /******************** editing stuff ********************/
603 // don't change this, I know how to optimise this and will do it real
608 * Finds the object belonging to a given cursor position cpos and
609 * returns an iterator to that object and stores the relative cursor
610 * position in offset.
612 * For linebreaks, the offset can be 0=before or 1=after.
614 * If the cpos coordinates don't exist, they are modified.
617 wxLayoutObjectList::iterator
618 wxLayoutList::FindObjectCursor(wxPoint
*cpos
, CoordType
*offset
)
620 wxPoint object
= wxPoint(0,0); // runs along the objects
622 wxLayoutObjectList::iterator i
, begin_it
;
625 //#ifdef WXLAYOUT_DEBUG
626 // wxLayoutDebug("Looking for object at (%d, %d)", cpos->x, cpos->y);
629 // optimisation: compare to last looked at object:
630 if(cpos
->y
> m_FoundCursor
.y
|| (cpos
->y
== m_FoundCursor
.y
&&
631 cpos
->x
>= m_FoundCursor
.x
))
636 //broken at the moment
637 //begin_it = m_FoundIterator;
638 //m_FoundCursor = *cpos;
641 for(i
= begin_it
; i
!= end() && object
.y
<= cpos
->y
; )
643 width
= (**i
).CountPositions();
644 if(cpos
->y
== object
.y
) // a possible candidate
646 if((**i
).GetType() ==WXLO_TYPE_LINEBREAK
)
648 if(cpos
->x
== object
.x
)
650 if(offset
) *offset
= 0;
651 return m_FoundIterator
= i
;
653 if(offset
) *offset
=1;
655 return m_FoundIterator
= i
;
657 if(cpos
->x
>= object
.x
&& cpos
->x
<= object
.x
+width
) // overlap
659 if(offset
) *offset
= cpos
->x
-object
.x
;
660 //#ifdef WXLAYOUT_DEBUG
661 // wxLayoutDebug(" found object at (%d, %d), type: %s",
662 // object.x, object.y, TypeString((*i)->GetType()));
664 return m_FoundIterator
= i
;
667 // no overlap, increment coordinates
669 if((**i
).GetType() == WXLO_TYPE_LINEBREAK
)
679 //#ifdef WXLAYOUT_DEBUG
680 // wxLayoutDebug(" not found");
682 // return last object, coordinates of that one:
685 return m_FoundIterator
= i
;
686 if((**i
).GetType()==WXLO_TYPE_LINEBREAK
)
690 return m_FoundIterator
= i
;
692 cpos
->x
= object
.x
; // would be the coordinate of next object
694 cpos
->x
+= width
; // last object's width
695 if(*offset
) *offset
= cpos
->x
-object
.x
;
696 return m_FoundIterator
= i
; // not found
700 wxLayoutList::MoveCursor(int dx
, int dy
)
704 m_CursorMoved
= true;
706 enum { up
, down
} direction
;
708 wxPoint newPos
= wxPoint(m_CursorPos
.x
+ dx
,
712 //if(newPos.x < 0) newPos.x = 0;
713 if(newPos
.y
< 0) newPos
.y
= 0;
714 else if(newPos
.y
> m_MaxLine
) newPos
.y
= m_MaxLine
;
716 if(newPos
.y
> m_CursorPos
.y
||
717 newPos
.y
== m_CursorPos
.y
&&
718 newPos
.x
>= m_CursorPos
.x
)
723 wxASSERT(m_CursorObject
);
724 // now move cursor forwards until at the new position:
726 // first, go to the right line:
727 while(newPos
.y
!= m_CursorPos
.y
)
729 if(direction
== down
)
732 (**m_CursorObject
).CountPositions() - m_CursorOffset
;
733 if(m_CursorObject
== tail())
734 break; // can't go any further
735 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
736 && m_CursorOffset
== 0)
738 m_CursorPos
.y
++; m_CursorPos
.x
= 0;
740 m_CursorObject
++; m_CursorOffset
= 0;
744 if(m_CursorObject
== begin())
745 break; // can't go any further
747 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
&&
751 m_CursorPos
.x
= GetLineLength(m_CursorObject
);
753 m_CursorPos
.x
-= m_CursorOffset
;
754 m_CursorObject
--; m_CursorOffset
= (**m_CursorObject
).CountPositions();
757 if(newPos
.y
!= m_CursorPos
.y
) // reached begin/end of list,
758 newPos
.y
= m_CursorPos
.y
; // exited by break
760 // now line is right, go to right column:
761 direction
= newPos
.x
>= m_CursorPos
.x
? down
: up
;
762 while(newPos
.x
!= m_CursorPos
.x
)
764 if(direction
== down
)
766 diff
= newPos
.x
- m_CursorPos
.x
;
767 if(diff
> (**m_CursorObject
).CountPositions()-m_CursorOffset
)
770 (**m_CursorObject
).CountPositions()-m_CursorOffset
;
771 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
&&
773 m_CursorPos
= wxPoint(0, m_CursorPos
.y
+1);
774 if(m_CursorObject
== tail())
775 break; // cannot go further
776 m_CursorObject
++; m_CursorOffset
= 0;
780 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
)
782 newPos
.y
++; newPos
.x
-= m_CursorPos
.x
+1;
783 m_CursorPos
= wxPoint(0,m_CursorPos
.y
+1);
786 m_CursorPos
.x
+= diff
;
787 m_CursorOffset
+= diff
;
792 if(m_CursorPos
.x
== 0 && m_CursorOffset
== 1 &&
793 (**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
) // can we go further up?
798 m_CursorPos
.x
= GetLineLength(m_CursorObject
)-1;
799 newPos
.x
+= m_CursorPos
.x
+1;
802 diff
= m_CursorPos
.x
- newPos
.x
;
803 if(diff
>= m_CursorOffset
)
805 if(m_CursorObject
== begin())
809 break; // cannot go further
812 m_CursorPos
.x
-= m_CursorOffset
;
813 m_CursorOffset
= (**m_CursorObject
).CountPositions();
817 m_CursorPos
.x
-= diff
;
818 m_CursorOffset
-= diff
;
822 return true; // FIXME: when return what?
826 wxLayoutList::Delete(CoordType count
)
836 wxLayoutObjectList::iterator i
;
841 startover
: // ugly, but easiest way to do it
843 return; // we cannot delete anything more
845 /* Here we need to treat linebreaks differently.
846 If m_CursorOffset==0 we are before the linebreak, otherwise behind. */
847 if((*i
)->GetType() == WXLO_TYPE_LINEBREAK
)
849 if(m_CursorOffset
== 0)
853 m_CursorObject
= i
; // new i!
854 m_CursorOffset
= 0; // Pos unchanged
856 continue; // we're done
858 else // delete the object behind the linebreak
860 i
++; // we increment and continue as normal
865 else if((*i
)->GetType() == WXLO_TYPE_TEXT
)
867 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
868 CoordType len
= tobj
->CountPositions();
869 // If we find the end of a text object, this means that we
870 // have to delete from the object following it.
871 if(len
== m_CursorOffset
)
877 else if(len
<= count
) // delete this object
888 tobj
->GetText().erase(m_CursorOffset
,len
);
890 return; // we are done
893 else// all other objects: delete the object
894 // this only works as expected if the non-text object has 0/1
895 // as offset values. Not tested with "longer" objects.
897 CoordType len
= (*i
)->CountPositions();
900 count
= count
> len
? count
-= len
: 0;
901 erase(i
); // after this, i is the iterator for the
907 else // delete the following object
909 i
++; // we increment and continue as normal
915 while(count
&& i
!= end());
919 wxLayoutList::Insert(wxLayoutObjectBase
*obj
)
921 wxCHECK_RET( obj
, "no object to insert" );
925 wxLayoutObjectList::iterator i
= m_CursorObject
;
927 if(i
!= iterator(NULL
) && (*obj
).GetType() == WXLO_TYPE_LINEBREAK
)
929 m_CursorPos
.x
= 0; m_CursorPos
.y
++;
935 m_CursorObject
= tail();
937 else if(m_CursorOffset
== 0)
942 // do we have to split a text object?
943 else if((*i
)->GetType() == WXLO_TYPE_TEXT
&& m_CursorOffset
!= (*i
)->CountPositions())
945 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
946 String left
= tobj
->GetText().substr(0,m_CursorOffset
); // get part before cursor
947 tobj
->GetText() = tobj
->GetText().substr(m_CursorOffset
,(*i
)->CountPositions()-m_CursorOffset
); // keeps the right half
949 m_CursorObject
= i
; // == obj
950 insert(i
,new wxLayoutObjectText(left
)); // inserts before
954 // all other cases, append after object:
955 wxLayoutObjectList::iterator j
= i
; // we want to apend after this object
965 m_CursorObject
= tail();
969 if(obj
->GetType() != WXLO_TYPE_LINEBREAK
) // handled separately above
970 m_CursorPos
.x
+= obj
->CountPositions();
971 // applies also for linebreak:
972 m_CursorOffset
= obj
->CountPositions();
974 if(obj
->GetType() == WXLO_TYPE_LINEBREAK
)
976 m_CursorMoved
= true;
980 wxLayoutList::Insert(String
const &text
)
982 wxLayoutObjectText
*tobj
= NULL
;
983 wxLayoutObjectList::iterator j
;
985 // WXL_TRACE(Insert(text));
992 wxLayoutObjectList::iterator i
= m_CursorObject
;
996 Insert(new wxLayoutObjectText(text
));
1000 switch((**i
).GetType())
1002 case WXLO_TYPE_TEXT
:
1003 // insert into an existing text object:
1004 tobj
= (wxLayoutObjectText
*)*i
;
1006 tobj
->GetText().insert(m_CursorOffset
,text
);
1008 m_CursorOffset
= m_CursorOffset
+ text
.length();
1009 m_CursorPos
.x
+= text
.length();
1011 case WXLO_TYPE_LINEBREAK
:
1014 if(m_CursorOffset
== 0) // try to append to previous object
1017 if(j
!= end() && (**j
).GetType() == WXLO_TYPE_TEXT
)
1019 tobj
= (wxLayoutObjectText
*)*j
;
1020 tobj
->GetText()+=text
;
1022 m_CursorOffset
= (**j
).CountPositions();
1023 m_CursorPos
.x
+= text
.length();
1027 insert(i
,new wxLayoutObjectText(text
));
1029 m_CursorOffset
= (**i
).CountPositions();
1030 m_CursorPos
.x
+= m_CursorOffset
;
1033 else // offset == 1 : cursor after linebreak
1038 if(j
!= end() && (**j
).GetType() == WXLO_TYPE_TEXT
)
1040 tobj
= (wxLayoutObjectText
*)*j
;
1041 tobj
->GetText()=text
+tobj
->GetText();
1042 m_CursorOffset
= text
.length();
1043 m_CursorPos
.x
+= m_CursorOffset
;
1049 push_back(new wxLayoutObjectText(text
));
1050 m_CursorObject
= tail();
1051 m_CursorOffset
= (**m_CursorObject
).CountPositions();
1052 m_CursorPos
.x
+= text
.length();
1056 insert(j
,new wxLayoutObjectText(text
));
1058 m_CursorOffset
= (**j
).CountPositions();
1059 m_CursorPos
.x
+= text
.length();
1065 m_CursorMoved
= true;
1069 wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i
, CoordType offs
)
1076 if(offs
== 0 && (**i
).GetType() == WXLO_TYPE_LINEBREAK
)
1079 // search backwards for beginning of line:
1080 while(i
!= begin() && (*i
)->GetType() != WXLO_TYPE_LINEBREAK
)
1082 if((*i
)->GetType() == WXLO_TYPE_LINEBREAK
)
1084 // now we can start counting:
1085 while(i
!= end() && (*i
)->GetType() != WXLO_TYPE_LINEBREAK
)
1087 len
+= (*i
)->CountPositions();
1090 len
++; // one extra for the linebreak
1095 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1096 int underline
, char const *fg
, char const *bg
)
1099 m_CursorMoved
= true;
1100 m_dirty
= true; // force redraw/recalc
1101 wxLayoutObjectList::iterator i
= begin();
1104 m_CursorMemDC
.SelectObject(bm
);
1106 while(i
!= end()) // == while valid
1110 m_FontPtSize
= size
;
1111 m_FontUnderline
= false;
1112 m_FontFamily
= family
;
1113 m_FontStyle
= style
;
1114 m_FontWeight
= weight
;
1115 m_ColourFG
= wxTheColourDatabase
->FindColour(fg
);
1116 m_ColourBG
= wxTheColourDatabase
->FindColour(bg
);
1118 if(! m_ColourFG
) m_ColourFG
= wxBLACK
;
1119 if(! m_ColourBG
) m_ColourBG
= wxWHITE
;
1121 m_Position
= wxPoint(0,0);
1122 m_CursorPos
= wxPoint(0,0);
1123 m_CursorObject
= iterator(NULL
);
1125 m_CursorSize
= wxPoint(2,(BASELINESTRETCH
*m_FontPtSize
)/10);
1128 m_LineHeight
= (BASELINESTRETCH
*m_FontPtSize
)/10;
1129 m_MaxX
= 0; m_MaxY
= 0;
1132 m_FoundCursor
= wxPoint(0,0);
1133 m_FoundIterator
= begin();
1135 if(m_DefaultSetting
)
1136 delete m_DefaultSetting
;
1138 m_DefaultSetting
= new
1139 wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,
1140 m_FontWeight
,m_FontUnderline
,
1141 m_ColourFG
, m_ColourBG
);
1145 wxLayoutObjectBase
*
1146 wxLayoutList::Find(wxPoint coords
) const
1148 wxLayoutObjectList::iterator i
= begin();
1150 wxPoint topleft
, bottomright
;
1152 while(i
!= end()) // == while valid
1154 wxLayoutObjectBase
*object
= *i
;
1155 topleft
= object
->GetPosition();
1156 if(coords
.y
>= topleft
.y
&& coords
.x
>= topleft
.x
)
1158 bottomright
= topleft
;
1159 bottomright
.x
+= object
->GetSize().x
;
1160 bottomright
.y
+= object
->GetSize().y
;
1161 if(coords
.x
<= bottomright
.x
&& coords
.y
<= bottomright
.y
)
1171 wxLayoutList::SetWrapMargin(long n
)
1177 wxLayoutList::WrapLine(void)
1179 wxASSERT(m_CursorObject
);
1181 iterator i
= m_CursorObject
;
1183 if(!DoWordWrap() || !i
) // empty list
1185 int cursorpos
= m_CursorPos
.x
, cpos
, offset
;
1187 if(cursorpos
< m_WrapMargin
)
1192 // find the right object to break:
1193 // is it the current one?
1196 cpos
= cursorpos
-m_CursorOffset
;
1197 while(i
!= begin() && cpos
>= m_WrapMargin
)
1200 cpos
-= (**i
).CountPositions();
1202 // now i is the object to break and cpos its position
1204 offset
= m_WrapMargin
- cpos
;
1205 wxASSERT(offset
<= (**i
).CountPositions());
1208 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1210 wxLayoutObjectText
&t
= *(wxLayoutObjectText
*)*i
;
1211 for(; offset
> 0; offset
--)
1212 if(t
.GetText().c_str()[offset
] == ' ' || t
.GetText().c_str()[offset
] == '\t')
1214 String left
= t
.GetText().substr(0,offset
-1); // get part before cursor
1215 t
.GetText() = t
.GetText().substr(offset
,t
.CountPositions()-offset
); // keeps the right halve
1216 insert(i
,new wxLayoutObjectLineBreak
);
1217 insert(i
,new wxLayoutObjectText(left
)); // inserts before
1222 // only insert a line break if there isn't already one
1223 iterator j
= i
; j
--;
1224 if(j
&& j
!= begin() && (**j
).GetType() != WXLO_TYPE_LINEBREAK
)
1225 insert(i
,new wxLayoutObjectLineBreak
);
1227 return; // do nothing
1231 insert(i
,new wxLayoutObjectLineBreak
);
1234 m_CursorPos
.x
-= offset
;
1235 m_CursorOffset
-= offset
;
1237 /******************** printing stuff ********************/
1239 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
&llist
,
1240 wxString
const & title
)
1247 bool wxLayoutPrintout::OnPrintPage(int page
)
1252 DrawHeader(*dc
,wxPoint(m_Margins
.left
,m_Margins
.top
/2),wxPoint(m_Margins
.right
,m_Margins
.top
),page
);
1254 top
= (page
- 1)*m_PrintoutHeight
;
1255 bottom
= top
+ m_PrintoutHeight
;
1256 // SetDeviceOrigin() doesn't work here, so we need to manually
1257 // translate all coordinates.
1258 wxPoint
translate(m_Margins
.left
,-top
+m_Margins
.top
);
1259 m_llist
->Draw(*dc
,top
,bottom
,wxLayoutObjectList::iterator(NULL
),translate
);
1266 bool wxLayoutPrintout::OnBeginDocument(int startPage
, int endPage
)
1268 if (!wxPrintout::OnBeginDocument(startPage
, endPage
))
1275 wxLayoutPrintout::OnPreparePrinting(void)
1281 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
1283 // ugly hack to get number of pages
1285 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
1287 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
1289 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
); // that's all we need it for
1291 // We do 5% margins on top and bottom, and a 5% high header line.
1292 m_Margins
.top
= m_PageHeight
/ 10 ; // 10%, half of it header
1293 m_Margins
.bottom
= m_PageHeight
- m_PageHeight
/ 20; // 95%
1294 // On the sides we reserve 10% each for the margins.
1295 m_Margins
.left
= m_PageWidth
/ 10;
1296 m_Margins
.right
= m_PageWidth
- m_PageWidth
/ 10;
1298 // This is the length of the printable area.
1299 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
1301 //FIXME this is wrong but not used at the moment
1302 m_PageWidth
= m_Margins
.right
- m_Margins
.left
;
1304 m_NumOfPages
= (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
) + 0.5);
1306 *maxPage
= m_NumOfPages
;
1309 *selPageTo
= m_NumOfPages
;
1310 wxRemoveFile(WXLLIST_TEMPFILE
);
1313 bool wxLayoutPrintout::HasPage(int pageNum
)
1315 return pageNum
<= m_NumOfPages
;
1320 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
1321 wxPoint topleft
, wxPoint bottomright
,
1324 // make backups of all essential parameters
1325 wxBrush
&brush
= dc
.GetBrush();
1326 wxPen
&pen
= dc
.GetPen();
1327 wxFont
&font
= dc
.GetFont(),
1330 dc
.SetBrush(*wxWHITE_BRUSH
);
1331 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
1332 dc
.DrawRoundedRectangle(topleft
.x
,
1333 topleft
.y
,bottomright
.x
-topleft
.x
,
1334 bottomright
.y
-topleft
.y
);
1335 dc
.SetBrush(*wxBLACK_BRUSH
);
1336 myfont
= new wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
1337 dc
.SetFont(*myfont
);
1340 page
= "9999/9999 "; // many pages...
1342 dc
.GetTextExtent(page
,&w
,&h
);
1343 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
1344 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
1345 dc
.GetTextExtent("XXXX", &w
,&h
);
1346 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
1358 wxLayoutList::MakePrintout(wxString
const &name
)
1360 return new wxLayoutPrintout(*this,name
);