]>
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
,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
;
249 wxLayoutList::~wxLayoutList()
252 delete m_DefaultSetting
;
253 // no deletion of objects, they are owned by the list
257 wxLayoutList::LineBreak(void)
259 Insert(new wxLayoutObjectLineBreak
);
260 // m_CursorPos.x = 0; m_CursorPos.y++;
264 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
265 int underline
, wxColour
const *fg
,
268 if(family
!= -1) m_FontFamily
= family
;
269 if(size
!= -1) m_FontPtSize
= size
;
270 if(style
!= -1) m_FontStyle
= style
;
271 if(weight
!= -1) m_FontWeight
= weight
;
272 if(underline
!= -1) m_FontUnderline
= underline
!= 0;
274 if(fg
!= NULL
) m_ColourFG
= fg
;
275 if(bg
!= NULL
) m_ColourBG
= bg
;
278 new wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,m_FontWeight
,m_FontUnderline
,
279 m_ColourFG
, m_ColourBG
));
283 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
284 int underline
, char const *fg
, char const *bg
)
292 cfg
= wxTheColourDatabase
->FindColour(fg
);
294 cbg
= wxTheColourDatabase
->FindColour(bg
);
296 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
300 /// for access by wxLayoutWindow:
302 wxLayoutList::GetSize(CoordType
*max_x
, CoordType
*max_y
,
303 CoordType
*lineHeight
)
306 if(max_x
) *max_x
= m_MaxX
;
307 if(max_y
) *max_y
= m_MaxY
;
308 if(lineHeight
) *lineHeight
= m_LineHeight
;
312 wxLayoutList::ResetSettings(wxDC
&dc
)
314 // setting up the default:
315 dc
.SetTextForeground( *wxBLACK
);
316 dc
.SetTextBackground( *wxWHITE
);
317 dc
.SetBackgroundMode( wxSOLID
); // to enable setting of text background
318 dc
.SetFont( *wxNORMAL_FONT
);
320 m_DefaultSetting
->Draw(dc
,wxPoint(0,0));
324 wxLayoutList::Layout(wxDC
&dc
, wxLayoutMargins
*margins
)
328 // first object in current line
329 wxLayoutObjectList::iterator headOfLine
;
330 // where we draw next
331 wxPoint position
, position_HeadOfLine
;
332 // size of last object
334 CoordType baseLine
= m_FontPtSize
;
335 CoordType baseLineSkip
= (BASELINESTRETCH
* baseLine
)/10;
336 CoordType objBaseLine
= baseLine
;
337 wxLayoutObjectType type
;
339 // we need to count cursor positions
340 wxPoint cursorPos
= wxPoint(0,0);
344 position
.y
= margins
->top
;
345 position
.x
= margins
->left
;
357 position_HeadOfLine
= position
;
364 type
= (*i
)->GetType();
365 (*i
)->Layout(dc
, position
, baseLine
);
366 size
= (*i
)->GetSize(&objBaseLine
);
367 // calculate next object's position:
368 position
.x
+= size
.x
;
370 // do we need to increase the line's height?
371 if(size
.y
> baseLineSkip
)
373 baseLineSkip
= size
.y
;
374 i
= headOfLine
; position
= position_HeadOfLine
;
377 if(objBaseLine
> baseLine
)
379 baseLine
= objBaseLine
;
380 i
= headOfLine
; position
= position_HeadOfLine
;
384 // when we reach here, the coordinates are valid, this part of
385 // the loop gets run only once per object
386 if(position
.x
> m_MaxX
)
388 if(type
== WXLO_TYPE_LINEBREAK
)
390 cursorPos
.x
= 0; cursorPos
.y
++;
393 cursorPos
.x
+= (**i
).CountPositions();
395 // now check whether we have finished handling this line:
396 if(type
== WXLO_TYPE_LINEBREAK
&& i
!= tail())
398 position
.x
= margins
? margins
->left
: 0;
399 position
.y
+= baseLineSkip
;
400 baseLine
= m_FontPtSize
;
401 objBaseLine
= baseLine
; // not all objects set it
402 baseLineSkip
= (BASELINESTRETCH
* baseLine
)/10;
405 position_HeadOfLine
= position
;
407 if(i
== m_CursorObject
)
412 m_MaxY
= position
.y
+ baseLineSkip
;
416 wxLayoutList::Draw(wxDC
&dc
,
417 CoordType fromLine
, CoordType toLine
,
419 wxPoint
const &translate
)
421 Layout(dc
); // FIXME just for now
425 wxLayoutObjectList::iterator i
;
427 if(start
== iterator(NULL
))
429 else // we need to restore font settings
431 for( i
= begin() ; i
!= start
; i
++)
432 if((**i
).GetType() == WXLO_TYPE_CMD
)
433 (**i
).Draw(dc
,translate
); // apply font settings
436 while( start
!= end() && (**start
).GetPosition().y
< fromLine
)
438 if((**start
).GetType() == WXLO_TYPE_CMD
)
439 (**start
).Draw(dc
,translate
); // apply font settings
443 i
!= end() && (toLine
== -1 || (**i
).GetPosition().y
< toLine
) ;
445 (*i
)->Draw(dc
,translate
);
448 /** Erase at least to end of line */
450 wxLayoutList::EraseAndDraw(wxDC
&dc
, iterator start
)
452 //look for begin of line
453 while(start
!= end() && start
!= begin() && (**start
).GetType() !=
456 if(start
== iterator(NULL
))
458 if(start
== iterator(NULL
))
461 wxPoint p
= (**start
).GetPosition();
463 //FIXME: wxGTK: MaxX()/MaxY() broken
464 //WXL_VAR(dc.MaxX()); WXL_VAR(dc.MaxY());
465 dc
.SetBrush(*wxWHITE_BRUSH
);
466 dc
.SetPen(wxPen(*wxWHITE
,0,wxTRANSPARENT
));
467 dc
.DrawRectangle(p
.x
,p
.y
,2000,2000); //dc.MaxX(),dc.MaxY());
468 Draw(dc
,-1,-1,start
,wxPoint(0,0));
469 //dc.DrawRectangle(p.x,p.y,2000,2000); //dc.MaxX(),dc.MaxY());
474 wxLayoutList::CalculateCursor(wxDC
&dc
)
476 CoordType width
, height
, descent
;
477 CoordType baseLineSkip
= 20; //FIXME
479 if( m_CursorObject
== iterator(NULL
)) // empty list
481 m_CursorCoords
= wxPoint(0,0);
482 m_CursorSize
= wxPoint(2,baseLineSkip
);
483 m_CursorMoved
= false; // coords are valid
486 wxLayoutObjectBase
&obj
= **m_CursorObject
;
488 m_CursorCoords
= obj
.GetPosition();
489 if(obj
.GetType() == WXLO_TYPE_TEXT
)
491 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)&obj
;
492 String
& str
= tobj
->GetText();
493 String sstr
= str
.substr(0,m_CursorOffset
);
494 dc
.GetTextExtent(sstr
,&width
,&height
,&descent
);
495 m_CursorCoords
= wxPoint(m_CursorCoords
.x
+width
,
497 m_CursorSize
= wxPoint(2,height
);
499 else if(obj
.GetType() == WXLO_TYPE_LINEBREAK
)
501 if(m_CursorOffset
== 1) // behind linebreak
502 m_CursorCoords
= wxPoint(0, m_CursorCoords
.y
+ baseLineSkip
);
503 //m_CursorCoords = wxPoint(0, m_CursorCoords.y);
504 m_CursorSize
= wxPoint(2,baseLineSkip
);
508 // this is not necessarily the most "beautiful" solution:
509 //cursorPosition = wxPoint(position.x, position.y);
510 //cursorSize = wxPoint(size.x > 0 ? size.x : 1,size.y > 0 ? size.y : baseLineSkip);
511 m_CursorCoords
= wxPoint(m_CursorCoords
.x
+obj
.GetSize().x
, m_CursorCoords
.y
);
512 m_CursorSize
= wxPoint(2, obj
.GetSize().y
);
513 if(m_CursorSize
.y
< 1) m_CursorSize
.y
= baseLineSkip
;
515 m_CursorMoved
= false; // coords are valid
519 wxLayoutList::DrawCursor(wxDC
&dc
, bool erase
)
526 //dc.SetBrush(*wxWHITE_BRUSH);
527 //dc.SetPen(wxPen(*wxWHITE,1,wxSOLID));
528 //dc.DrawRectangle(m_CursorCoords.x, m_CursorCoords.y, m_CursorSize.x, m_CursorSize.y);
529 dc
.Blit(m_CursorCoords
.x
, m_CursorCoords
.y
, m_CursorSize
.x
,
530 m_CursorSize
.y
, &m_CursorMemDC
,
535 if(IsDirty() || CursorMoved())
541 wxBitmap
bm(m_CursorSize
.x
+1,m_CursorSize
.y
+1);
542 m_CursorMemDC
.SelectObject(bm
);
543 m_CursorMemDC
.Blit(0, 0, m_CursorSize
.x
, m_CursorSize
.y
,
544 &dc
, m_CursorCoords
.x
,
545 m_CursorCoords
.y
, 0, 0);
546 dc
.SetBrush(*wxBLACK_BRUSH
);
547 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
548 dc
.DrawRectangle(m_CursorCoords
.x
, m_CursorCoords
.y
,
549 m_CursorSize
.x
, m_CursorSize
.y
);
559 #ifdef WXLAYOUT_DEBUG
561 wxLayoutList::Debug(void)
563 wxLayoutObjectList::iterator i
;
565 wxLayoutDebug("------------------------ debug start ------------------------");
566 for(i
= begin(); i
!= end(); i
++)
568 wxLayoutDebug("-------------------------- list end -------------------------");
570 // show current object:
572 wxLayoutDebug("------------------------- debug end -------------------------");
576 wxLayoutList::ShowCurrentObject()
578 wxLayoutDebug("CursorPos (%d, %d)", (int) m_CursorPos
.x
, (int) m_CursorPos
.y
);
579 wxLayoutDebug("CursorOffset = %d", (int) m_CursorOffset
);
580 wxLayoutDebug("CursorObject = %p", m_CursorObject
);
581 if(m_CursorObject
== iterator(NULL
))
582 wxLayoutDebug("<<no object found>>");
585 if((*m_CursorObject
)->GetType() == WXLO_TYPE_TEXT
)
586 wxLayoutDebug(" \"%s\", offs: %d",
587 ((wxLayoutObjectText
*)(*m_CursorObject
))->GetText().c_str(),
590 wxLayoutDebug(" %s", TypeString((*m_CursorObject
)->GetType()));
592 wxLayoutDebug("Line length: %d", GetLineLength(m_CursorObject
));
598 /******************** editing stuff ********************/
600 // don't change this, I know how to optimise this and will do it real
605 * Finds the object belonging to a given cursor position cpos and
606 * returns an iterator to that object and stores the relative cursor
607 * position in offset.
609 * For linebreaks, the offset can be 0=before or 1=after.
611 * If the cpos coordinates don't exist, they are modified.
614 wxLayoutObjectList::iterator
615 wxLayoutList::FindObjectCursor(wxPoint
*cpos
, CoordType
*offset
)
617 wxPoint object
= wxPoint(0,0); // runs along the objects
619 wxLayoutObjectList::iterator i
, begin_it
;
622 //#ifdef WXLAYOUT_DEBUG
623 // wxLayoutDebug("Looking for object at (%d, %d)", cpos->x, cpos->y);
626 // optimisation: compare to last looked at object:
627 if(cpos
->y
> m_FoundCursor
.y
|| (cpos
->y
== m_FoundCursor
.y
&&
628 cpos
->x
>= m_FoundCursor
.x
))
633 //broken at the moment
634 //begin_it = m_FoundIterator;
635 //m_FoundCursor = *cpos;
638 for(i
= begin_it
; i
!= end() && object
.y
<= cpos
->y
; )
640 width
= (**i
).CountPositions();
641 if(cpos
->y
== object
.y
) // a possible candidate
643 if((**i
).GetType() ==WXLO_TYPE_LINEBREAK
)
645 if(cpos
->x
== object
.x
)
647 if(offset
) *offset
= 0;
648 return m_FoundIterator
= i
;
650 if(offset
) *offset
=1;
652 return m_FoundIterator
= i
;
654 if(cpos
->x
>= object
.x
&& cpos
->x
<= object
.x
+width
) // overlap
656 if(offset
) *offset
= cpos
->x
-object
.x
;
657 //#ifdef WXLAYOUT_DEBUG
658 // wxLayoutDebug(" found object at (%d, %d), type: %s",
659 // object.x, object.y, TypeString((*i)->GetType()));
661 return m_FoundIterator
= i
;
664 // no overlap, increment coordinates
666 if((**i
).GetType() == WXLO_TYPE_LINEBREAK
)
676 //#ifdef WXLAYOUT_DEBUG
677 // wxLayoutDebug(" not found");
679 // return last object, coordinates of that one:
682 return m_FoundIterator
= i
;
683 if((**i
).GetType()==WXLO_TYPE_LINEBREAK
)
687 return m_FoundIterator
= i
;
689 cpos
->x
= object
.x
; // would be the coordinate of next object
691 cpos
->x
+= width
; // last object's width
692 if(*offset
) *offset
= cpos
->x
-object
.x
;
693 return m_FoundIterator
= i
; // not found
697 wxLayoutList::MoveCursor(int dx
, int dy
)
701 m_CursorMoved
= true;
703 enum { up
, down
} direction
;
705 wxPoint newPos
= wxPoint(m_CursorPos
.x
+ dx
,
709 //if(newPos.x < 0) newPos.x = 0;
710 if(newPos
.y
< 0) newPos
.y
= 0;
711 else if(newPos
.y
> m_MaxLine
) newPos
.y
= m_MaxLine
;
713 if(newPos
.y
> m_CursorPos
.y
||
714 newPos
.y
== m_CursorPos
.y
&&
715 newPos
.x
>= m_CursorPos
.x
)
720 wxASSERT(m_CursorObject
);
721 // now move cursor forwards until at the new position:
723 // first, go to the right line:
724 while(newPos
.y
!= m_CursorPos
.y
)
726 if(direction
== down
)
729 (**m_CursorObject
).CountPositions() - m_CursorOffset
;
730 if(m_CursorObject
== tail())
731 break; // can't go any further
732 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
733 && m_CursorOffset
== 0)
735 m_CursorPos
.y
++; m_CursorPos
.x
= 0;
737 m_CursorObject
++; m_CursorOffset
= 0;
741 if(m_CursorObject
== begin())
742 break; // can't go any further
744 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
&&
748 m_CursorPos
.x
= GetLineLength(m_CursorObject
);
750 m_CursorPos
.x
-= m_CursorOffset
;
751 m_CursorObject
--; m_CursorOffset
= (**m_CursorObject
).CountPositions();
754 if(newPos
.y
!= m_CursorPos
.y
) // reached begin/end of list,
755 newPos
.y
= m_CursorPos
.y
; // exited by break
757 // now line is right, go to right column:
758 direction
= newPos
.x
>= m_CursorPos
.x
? down
: up
;
759 while(newPos
.x
!= m_CursorPos
.x
)
761 if(direction
== down
)
763 diff
= newPos
.x
- m_CursorPos
.x
;
764 if(diff
> (**m_CursorObject
).CountPositions()-m_CursorOffset
)
767 (**m_CursorObject
).CountPositions()-m_CursorOffset
;
768 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
&&
770 m_CursorPos
= wxPoint(0, m_CursorPos
.y
+1);
771 if(m_CursorObject
== tail())
772 break; // cannot go further
773 m_CursorObject
++; m_CursorOffset
= 0;
777 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
)
779 newPos
.y
++; newPos
.x
-= m_CursorPos
.x
+1;
780 m_CursorPos
= wxPoint(0,m_CursorPos
.y
+1);
783 m_CursorPos
.x
+= diff
;
784 m_CursorOffset
+= diff
;
789 if(m_CursorPos
.x
== 0 && m_CursorOffset
== 1 &&
790 (**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
) // can we go further up?
795 m_CursorPos
.x
= GetLineLength(m_CursorObject
)-1;
796 newPos
.x
+= m_CursorPos
.x
+1;
799 diff
= m_CursorPos
.x
- newPos
.x
;
800 if(diff
>= m_CursorOffset
)
802 if(m_CursorObject
== begin())
806 break; // cannot go further
809 m_CursorPos
.x
-= m_CursorOffset
;
810 m_CursorOffset
= (**m_CursorObject
).CountPositions();
814 m_CursorPos
.x
-= diff
;
815 m_CursorOffset
-= diff
;
819 return true; // FIXME: when return what?
823 wxLayoutList::Delete(CoordType count
)
833 wxLayoutObjectList::iterator i
;
838 startover
: // ugly, but easiest way to do it
840 return; // we cannot delete anything more
842 /* Here we need to treat linebreaks differently.
843 If m_CursorOffset==0 we are before the linebreak, otherwise behind. */
844 if((*i
)->GetType() == WXLO_TYPE_LINEBREAK
)
846 if(m_CursorOffset
== 0)
850 m_CursorObject
= i
; // new i!
851 m_CursorOffset
= 0; // Pos unchanged
853 continue; // we're done
855 else // delete the object behind the linebreak
857 i
++; // we increment and continue as normal
862 else if((*i
)->GetType() == WXLO_TYPE_TEXT
)
864 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
865 CoordType len
= tobj
->CountPositions();
866 // If we find the end of a text object, this means that we
867 // have to delete from the object following it.
868 if(len
== m_CursorOffset
)
874 else if(len
<= count
) // delete this object
885 tobj
->GetText().erase(m_CursorOffset
,len
);
887 return; // we are done
890 else// all other objects: delete the object
891 // this only works as expected if the non-text object has 0/1
892 // as offset values. Not tested with "longer" objects.
894 CoordType len
= (*i
)->CountPositions();
897 count
= count
> len
? count
-= len
: 0;
898 erase(i
); // after this, i is the iterator for the
904 else // delete the following object
906 i
++; // we increment and continue as normal
912 while(count
&& i
!= end());
916 wxLayoutList::Insert(wxLayoutObjectBase
*obj
)
918 wxCHECK_RET( obj
, "no object to insert" );
922 wxLayoutObjectList::iterator i
= m_CursorObject
;
924 if(i
!= iterator(NULL
) && (*obj
).GetType() == WXLO_TYPE_LINEBREAK
)
926 m_CursorPos
.x
= 0; m_CursorPos
.y
++;
932 m_CursorObject
= tail();
934 else if(m_CursorOffset
== 0)
939 // do we have to split a text object?
940 else if((*i
)->GetType() == WXLO_TYPE_TEXT
&& m_CursorOffset
!= (*i
)->CountPositions())
942 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
943 String left
= tobj
->GetText().substr(0,m_CursorOffset
); // get part before cursor
944 tobj
->GetText() = tobj
->GetText().substr(m_CursorOffset
,(*i
)->CountPositions()-m_CursorOffset
); // keeps the right half
946 m_CursorObject
= i
; // == obj
947 insert(i
,new wxLayoutObjectText(left
)); // inserts before
951 // all other cases, append after object:
952 wxLayoutObjectList::iterator j
= i
; // we want to apend after this object
962 m_CursorObject
= tail();
966 if(obj
->GetType() != WXLO_TYPE_LINEBREAK
) // handled separately above
967 m_CursorPos
.x
+= obj
->CountPositions();
968 // applies also for linebreak:
969 m_CursorOffset
= obj
->CountPositions();
971 if(obj
->GetType() == WXLO_TYPE_LINEBREAK
)
973 m_CursorMoved
= true;
977 wxLayoutList::Insert(String
const &text
)
979 wxLayoutObjectText
*tobj
= NULL
;
980 wxLayoutObjectList::iterator j
;
982 // WXL_TRACE(Insert(text));
989 wxLayoutObjectList::iterator i
= m_CursorObject
;
993 Insert(new wxLayoutObjectText(text
));
997 switch((**i
).GetType())
1000 // insert into an existing text object:
1001 tobj
= (wxLayoutObjectText
*)*i
;
1003 tobj
->GetText().insert(m_CursorOffset
,text
);
1005 m_CursorOffset
= m_CursorOffset
+ text
.length();
1006 m_CursorPos
.x
+= text
.length();
1008 case WXLO_TYPE_LINEBREAK
:
1011 if(m_CursorOffset
== 0) // try to append to previous object
1014 if(j
!= end() && (**j
).GetType() == WXLO_TYPE_TEXT
)
1016 tobj
= (wxLayoutObjectText
*)*j
;
1017 tobj
->GetText()+=text
;
1019 m_CursorOffset
= (**j
).CountPositions();
1020 m_CursorPos
.x
+= text
.length();
1024 insert(i
,new wxLayoutObjectText(text
));
1026 m_CursorOffset
= (**i
).CountPositions();
1027 m_CursorPos
.x
+= m_CursorOffset
;
1030 else // offset == 1 : cursor after linebreak
1035 if(j
!= end() && (**j
).GetType() == WXLO_TYPE_TEXT
)
1037 tobj
= (wxLayoutObjectText
*)*j
;
1038 tobj
->GetText()=text
+tobj
->GetText();
1039 m_CursorOffset
= text
.length();
1040 m_CursorPos
.x
+= m_CursorOffset
;
1046 push_back(new wxLayoutObjectText(text
));
1047 m_CursorObject
= tail();
1048 m_CursorOffset
= (**m_CursorObject
).CountPositions();
1049 m_CursorPos
.x
+= text
.length();
1053 insert(j
,new wxLayoutObjectText(text
));
1055 m_CursorOffset
= (**j
).CountPositions();
1056 m_CursorPos
.x
+= text
.length();
1062 m_CursorMoved
= true;
1066 wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i
, CoordType offs
)
1073 if(offs
== 0 && (**i
).GetType() == WXLO_TYPE_LINEBREAK
)
1076 // search backwards for beginning of line:
1077 while(i
!= begin() && (*i
)->GetType() != WXLO_TYPE_LINEBREAK
)
1079 if((*i
)->GetType() == WXLO_TYPE_LINEBREAK
)
1081 // now we can start counting:
1082 while(i
!= end() && (*i
)->GetType() != WXLO_TYPE_LINEBREAK
)
1084 len
+= (*i
)->CountPositions();
1087 len
++; // one extra for the linebreak
1092 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1093 int underline
, char const *fg
, char const *bg
)
1096 m_CursorMoved
= true;
1097 m_dirty
= true; // force redraw/recalc
1098 wxLayoutObjectList::iterator i
= begin();
1101 m_CursorMemDC
.SelectObject(bm
);
1103 while(i
!= end()) // == while valid
1107 m_FontPtSize
= size
;
1108 m_FontUnderline
= false;
1109 m_FontFamily
= family
;
1110 m_FontStyle
= style
;
1111 m_FontWeight
= weight
;
1112 m_ColourFG
= wxTheColourDatabase
->FindColour(fg
);
1113 m_ColourBG
= wxTheColourDatabase
->FindColour(bg
);
1115 if(! m_ColourFG
) m_ColourFG
= wxBLACK
;
1116 if(! m_ColourBG
) m_ColourBG
= wxWHITE
;
1118 m_Position
= wxPoint(0,0);
1119 m_CursorPos
= wxPoint(0,0);
1120 m_CursorObject
= iterator(NULL
);
1122 m_CursorSize
= wxPoint(2,(BASELINESTRETCH
*m_FontPtSize
)/10);
1125 m_LineHeight
= (BASELINESTRETCH
*m_FontPtSize
)/10;
1126 m_MaxX
= 0; m_MaxY
= 0;
1129 m_FoundCursor
= wxPoint(0,0);
1130 m_FoundIterator
= begin();
1132 if(m_DefaultSetting
)
1133 delete m_DefaultSetting
;
1135 m_DefaultSetting
= new
1136 wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,
1137 m_FontWeight
,m_FontUnderline
,
1138 m_ColourFG
, m_ColourBG
);
1142 wxLayoutObjectBase
*
1143 wxLayoutList::Find(wxPoint coords
) const
1145 wxLayoutObjectList::iterator i
= begin();
1147 wxPoint topleft
, bottomright
;
1149 while(i
!= end()) // == while valid
1151 wxLayoutObjectBase
*object
= *i
;
1152 topleft
= object
->GetPosition();
1153 if(coords
.y
>= topleft
.y
&& coords
.x
>= topleft
.x
)
1155 bottomright
= topleft
;
1156 bottomright
.x
+= object
->GetSize().x
;
1157 bottomright
.y
+= object
->GetSize().y
;
1158 if(coords
.x
<= bottomright
.x
&& coords
.y
<= bottomright
.y
)
1168 wxLayoutList::SetWrapMargin(long n
= -1)
1174 wxLayoutList::WrapLine(void)
1176 wxASSERT(m_CursorObject
);
1178 iterator i
= m_CursorObject
;
1180 if(!DoWordWrap() || !i
) // empty list
1182 int cursorpos
= m_CursorPos
.x
, cpos
, offset
;
1184 if(cursorpos
< m_WrapMargin
)
1189 // find the right object to break:
1190 // is it the current one?
1193 cpos
= cursorpos
-m_CursorOffset
;
1194 while(i
!= begin() && cpos
>= m_WrapMargin
)
1197 cpos
-= (**i
).CountPositions();
1199 // now i is the object to break and cpos its position
1201 offset
= m_WrapMargin
- cpos
;
1202 wxASSERT(offset
<= (**i
).CountPositions());
1205 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1207 wxLayoutObjectText
&t
= *(wxLayoutObjectText
*)*i
;
1208 for(; offset
> 0; offset
--)
1209 if(t
.GetText().c_str()[offset
] == ' ' || t
.GetText().c_str()[offset
] == '\t')
1211 String left
= t
.GetText().substr(0,offset
-1); // get part before cursor
1212 t
.GetText() = t
.GetText().substr(offset
,t
.CountPositions()-offset
); // keeps the right halve
1213 insert(i
,new wxLayoutObjectLineBreak
);
1214 insert(i
,new wxLayoutObjectText(left
)); // inserts before
1219 // only insert a line break if there isn't already one
1220 iterator j
= i
; j
--;
1221 if(j
&& j
!= begin() && (**j
).GetType() != WXLO_TYPE_LINEBREAK
)
1222 insert(i
,new wxLayoutObjectLineBreak
);
1224 return; // do nothing
1228 insert(i
,new wxLayoutObjectLineBreak
);
1231 m_CursorPos
.x
-= offset
;
1232 m_CursorOffset
-= offset
;
1234 /******************** printing stuff ********************/
1236 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
&llist
,
1237 wxString
const & title
)
1244 bool wxLayoutPrintout::OnPrintPage(int page
)
1249 DrawHeader(*dc
,wxPoint(m_Margins
.left
,m_Margins
.top
/2),wxPoint(m_Margins
.right
,m_Margins
.top
),page
);
1251 top
= (page
- 1)*m_PrintoutHeight
;
1252 bottom
= top
+ m_PrintoutHeight
;
1253 // SetDeviceOrigin() doesn't work here, so we need to manually
1254 // translate all coordinates.
1255 wxPoint
translate(m_Margins
.left
,-top
+m_Margins
.top
);
1256 m_llist
->Draw(*dc
,top
,bottom
,wxLayoutObjectList::iterator(NULL
),translate
);
1263 bool wxLayoutPrintout::OnBeginDocument(int startPage
, int endPage
)
1265 if (!wxPrintout::OnBeginDocument(startPage
, endPage
))
1272 wxLayoutPrintout::OnPreparePrinting(void)
1278 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
1280 // ugly hack to get number of pages
1282 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
1284 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
1286 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
); // that's all we need it for
1288 // We do 5% margins on top and bottom, and a 5% high header line.
1289 m_Margins
.top
= m_PageHeight
/ 10 ; // 10%, half of it header
1290 m_Margins
.bottom
= m_PageHeight
- m_PageHeight
/ 20; // 95%
1291 // On the sides we reserve 10% each for the margins.
1292 m_Margins
.left
= m_PageWidth
/ 10;
1293 m_Margins
.right
= m_PageWidth
- m_PageWidth
/ 10;
1295 // This is the length of the printable area.
1296 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
1298 //FIXME this is wrong but not used at the moment
1299 m_PageWidth
= m_Margins
.right
- m_Margins
.left
;
1301 m_NumOfPages
= (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
) + 0.5);
1303 *maxPage
= m_NumOfPages
;
1306 *selPageTo
= m_NumOfPages
;
1307 wxRemoveFile(WXLLIST_TEMPFILE
);
1310 bool wxLayoutPrintout::HasPage(int pageNum
)
1312 return pageNum
<= m_NumOfPages
;
1317 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
1318 wxPoint topleft
, wxPoint bottomright
,
1321 // make backups of all essential parameters
1322 wxBrush
*brush
= dc
.GetBrush();
1323 wxPen
*pen
= dc
.GetPen();
1324 wxFont
*font
= dc
.GetFont(),
1327 dc
.SetBrush(*wxWHITE_BRUSH
);
1328 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
1329 dc
.DrawRoundedRectangle(topleft
.x
,
1330 topleft
.y
,bottomright
.x
-topleft
.x
,
1331 bottomright
.y
-topleft
.y
);
1332 dc
.SetBrush(*wxBLACK_BRUSH
);
1333 myfont
= new wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
1334 dc
.SetFont(*myfont
);
1337 page
= "9999/9999 "; // many pages...
1339 dc
.GetTextExtent(page
,&w
,&h
);
1340 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
1341 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
1342 dc
.GetTextExtent("XXXX", &w
,&h
);
1343 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
1347 dc
.SetBrush(*brush
);
1355 wxLayoutList::MakePrintout(wxString
const &name
)
1357 return new wxLayoutPrintout(*this,name
);