]>
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 - new cursor movement calculations
29 - moving lines and moving across linebreaks still broken
33 - mouse click positions cursor
34 - selection (SetMark(), GetSelection())
35 - DND acceptance of text
37 - wxlwindow: formatting menu: problem with checked/unchecked consistency gtk bug?
40 #define USE_NEW_CURSORCODE 1
44 - MaxX()/MaxY() don't get set
49 #pragma implementation "wxllist.h"
54 # include "gui/wxllist.h"
60 # include "iostream.h"
62 # include <wx/postscrp.h>
63 # include <wx/print.h>
67 #define BASELINESTRETCH 12
69 // This should never really get created
70 #define WXLLIST_TEMPFILE "__wxllist.tmp"
73 static const char *g_aTypeStrings
[] =
75 "invalid", "text", "cmd", "icon", "linebreak"
78 # define wxLayoutDebug wxLogDebug
79 # define WXL_VAR(x) cerr << #x " = " << x << endl;
80 # define WXL_DBG_POINT(p) wxLayoutDebug(#p ": (%d, %d)", p.x, p.y)
81 # define WXL_TRACE(f) wxLayoutDebug(#f ": ")
82 # define TypeString(t) g_aTypeStrings[t]
85 wxLayoutObjectBase::Debug(void)
88 wxLayoutDebug("%s: size = %dx%d, pos=%d,%d, bl = %d",
89 TypeString(GetType()), GetSize(&bl
).x
,
91 GetPosition().x
, GetPosition().y
, bl
);
96 # define WXL_DBG_POINT(p)
98 # define ShowCurrentObject()
99 # define TypeString(t) ""
100 inline void wxLayoutDebug(const char *, ...) { }
104 //-------------------------- wxLayoutObjectText
106 wxLayoutObjectText::wxLayoutObjectText(const String
&txt
)
111 m_Position
= wxPoint(-1,-1);
116 wxLayoutObjectText::GetSize(CoordType
*baseLine
) const
118 if(baseLine
) *baseLine
= m_BaseLine
;
119 return wxPoint(m_Width
, m_Height
);
123 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &translate
)
125 dc
.DrawText(Str(m_Text
), m_Position
.x
+ translate
.x
, m_Position
.y
+translate
.y
);
131 wxLayoutObjectText::Layout(wxDC
&dc
, wxPoint position
, CoordType baseLine
)
135 if(m_Position
.x
!= position
.x
|| m_Position
.y
!= position
.y
)
138 m_Position
= position
;
139 dc
.GetTextExtent(Str(m_Text
),&m_Width
, &m_Height
, &descent
);
140 m_BaseLine
= m_Height
- descent
;
141 if(m_Position
.x
!= position
.x
|| m_Position
.y
!= position
.y
)
145 #ifdef WXLAYOUT_DEBUG
147 wxLayoutObjectText::Debug(void)
149 wxLayoutObjectBase::Debug();
150 wxLayoutDebug(" `%s`", m_Text
.c_str());
154 //-------------------------- wxLayoutObjectIcon
156 wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon
const &icon
)
158 m_Position
= wxPoint(-1,-1);
159 m_Icon
= new wxIcon(icon
);
162 wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon
*icon
)
168 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &translate
)
170 dc
.DrawIcon(m_Icon
,m_Position
.x
+translate
.x
, m_Position
.y
+translate
.y
);
174 wxLayoutObjectIcon::Layout(wxDC
&dc
, wxPoint position
, CoordType baseLine
)
176 if(m_Position
.x
!= position
.x
|| m_Position
.y
!= position
.y
)
178 m_Position
= position
;
182 wxLayoutObjectIcon::GetSize(CoordType
*baseLine
) const
184 if(baseLine
) *baseLine
= m_Icon
->GetHeight();
185 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
188 //-------------------------- wxLayoutObjectCmd
191 wxLayoutObjectCmd::wxLayoutObjectCmd(int size
, int family
, int style
, int
192 weight
, bool underline
,
193 wxColour
const *fg
, wxColour
const *bg
)
196 m_font
= new wxFont(size
,family
,style
,weight
,underline
);
201 wxLayoutObjectCmd::~wxLayoutObjectCmd()
207 wxLayoutObjectCmd::GetStyle(void) const
209 wxLayoutStyleInfo
*si
= new wxLayoutStyleInfo();
212 si
->size
= m_font
->GetPointSize();
213 si
->family
= m_font
->GetFamily();
214 si
->style
= m_font
->GetStyle();
215 si
->underline
= m_font
->GetUnderlined();
216 si
->weight
= m_font
->GetWeight();
218 si
->fg_red
= m_ColourFG
->Red();
219 si
->fg_green
= m_ColourFG
->Green();
220 si
->fg_blue
= m_ColourFG
->Blue();
221 si
->bg_red
= m_ColourBG
->Red();
222 si
->bg_green
= m_ColourBG
->Green();
223 si
->bg_blue
= m_ColourBG
->Blue();
229 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const &translate
)
234 dc
.SetTextForeground(*m_ColourFG
);
236 dc
.SetTextBackground(*m_ColourBG
);
239 wxLayoutObjectCmd::Layout(wxDC
&dc
, wxPoint p
, CoordType baseline
)
241 m_Position
= p
; // required so we can find the right object for cursor
242 // this get called, so that recalculation uses right font sizes
243 Draw(dc
,wxPoint(0,0));
246 //-------------------------- wxLayoutList
248 wxLayoutList::wxLayoutList()
250 m_DefaultSetting
= NULL
;
254 wxLayoutList::~wxLayoutList()
257 delete m_DefaultSetting
;
258 // no deletion of objects, they are owned by the list
262 wxLayoutList::LineBreak(void)
264 Insert(new wxLayoutObjectLineBreak
);
265 // m_CursorPos.x = 0; m_CursorPos.y++;
269 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
270 int underline
, wxColour
const *fg
,
273 if(family
!= -1) m_FontFamily
= family
;
274 if(size
!= -1) m_FontPtSize
= size
;
275 if(style
!= -1) m_FontStyle
= style
;
276 if(weight
!= -1) m_FontWeight
= weight
;
277 if(underline
!= -1) m_FontUnderline
= underline
!= 0;
279 if(fg
!= NULL
) m_ColourFG
= fg
;
280 if(bg
!= NULL
) m_ColourBG
= bg
;
283 new wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,m_FontWeight
,m_FontUnderline
,
284 m_ColourFG
, m_ColourBG
));
288 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
289 int underline
, char const *fg
, char const *bg
)
297 cfg
= wxTheColourDatabase
->FindColour(fg
);
299 cbg
= wxTheColourDatabase
->FindColour(bg
);
301 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
305 /// for access by wxLayoutWindow:
307 wxLayoutList::GetSize(CoordType
*max_x
, CoordType
*max_y
,
308 CoordType
*lineHeight
)
311 if(max_x
) *max_x
= m_MaxX
;
312 if(max_y
) *max_y
= m_MaxY
;
313 if(lineHeight
) *lineHeight
= m_LineHeight
;
317 wxLayoutList::ResetSettings(wxDC
&dc
)
319 // setting up the default:
320 dc
.SetTextForeground( *wxBLACK
);
321 dc
.SetTextBackground( *wxWHITE
);
322 dc
.SetBackgroundMode( wxSOLID
); // to enable setting of text background
323 dc
.SetFont( *wxNORMAL_FONT
);
325 m_DefaultSetting
->Draw(dc
,wxPoint(0,0));
329 wxLayoutList::Layout(wxDC
&dc
, wxLayoutMargins
*margins
)
333 // first object in current line
334 wxLayoutObjectList::iterator headOfLine
;
335 // where we draw next
336 wxPoint position
, position_HeadOfLine
;
337 // size of last object
339 CoordType baseLine
= m_FontPtSize
;
340 CoordType baseLineSkip
= (BASELINESTRETCH
* baseLine
)/10;
341 CoordType objBaseLine
= baseLine
;
342 wxLayoutObjectType type
;
344 // we need to count cursor positions
345 wxPoint cursorPos
= wxPoint(0,0);
349 position
.y
= margins
->top
;
350 position
.x
= margins
->left
;
362 position_HeadOfLine
= position
;
369 type
= (*i
)->GetType();
370 (*i
)->Layout(dc
, position
, baseLine
);
371 size
= (*i
)->GetSize(&objBaseLine
);
372 // calculate next object's position:
373 position
.x
+= size
.x
;
375 // do we need to increase the line's height?
376 if(size
.y
> baseLineSkip
)
378 baseLineSkip
= size
.y
;
379 i
= headOfLine
; position
= position_HeadOfLine
;
382 if(objBaseLine
> baseLine
)
384 baseLine
= objBaseLine
;
385 i
= headOfLine
; position
= position_HeadOfLine
;
389 // when we reach here, the coordinates are valid, this part of
390 // the loop gets run only once per object
391 if(position
.x
> m_MaxX
)
393 if(type
== WXLO_TYPE_LINEBREAK
)
395 cursorPos
.x
= 0; cursorPos
.y
++;
398 cursorPos
.x
+= (**i
).CountPositions();
400 // now check whether we have finished handling this line:
401 if(type
== WXLO_TYPE_LINEBREAK
&& i
!= tail())
403 position
.x
= margins
? margins
->left
: 0;
404 position
.y
+= baseLineSkip
;
405 baseLine
= m_FontPtSize
;
406 objBaseLine
= baseLine
; // not all objects set it
407 baseLineSkip
= (BASELINESTRETCH
* baseLine
)/10;
410 position_HeadOfLine
= position
;
412 #if defined( USE_NEW_CURSORCODE )
413 if(i
== m_CursorObject
)
416 if(cursorObject
== NULL
&& cursorPos
.y
== m_CursorPos
.y
) // look for cursor
418 if(cursorPos
.x
>= m_CursorPos
.x
&&
419 m_CursorPos
.x
-cursorPos
.x
+(**i
).CountPositions()) // cursor is in current object
429 m_MaxY
= position
.y
+ baseLineSkip
;
433 wxLayoutList::Draw(wxDC
&dc
,
434 CoordType fromLine
, CoordType toLine
,
436 wxPoint
const &translate
)
438 Layout(dc
); // FIXME just for now
442 wxLayoutObjectList::iterator i
;
444 if(start
== iterator(NULL
))
446 else // we need to restore font settings
448 for( i
= begin() ; i
!= start
; i
++)
449 if((**i
).GetType() == WXLO_TYPE_CMD
)
450 (**i
).Draw(dc
,translate
); // apply font settings
453 while( start
!= end() && (**start
).GetPosition().y
< fromLine
)
455 if((**start
).GetType() == WXLO_TYPE_CMD
)
456 (**start
).Draw(dc
,translate
); // apply font settings
460 i
!= end() && (toLine
== -1 || (**i
).GetPosition().y
< toLine
) ;
462 (*i
)->Draw(dc
,translate
);
465 /** Erase at least to end of line */
467 wxLayoutList::EraseAndDraw(wxDC
&dc
, iterator start
)
469 //look for begin of line
470 while(start
!= end() && start
!= begin() && (**start
).GetType() !=
473 if(start
== iterator(NULL
))
475 if(start
== iterator(NULL
))
478 wxPoint p
= (**start
).GetPosition();
480 //FIXME: wxGTK: MaxX()/MaxY() broken
481 //WXL_VAR(dc.MaxX()); WXL_VAR(dc.MaxY());
482 dc
.SetBrush(*wxWHITE_BRUSH
);
483 dc
.SetPen(wxPen(*wxWHITE
,0,wxTRANSPARENT
));
484 dc
.DrawRectangle(p
.x
,p
.y
,2000,2000); //dc.MaxX(),dc.MaxY());
485 Draw(dc
,-1,-1,start
,wxPoint(0,0));
486 //dc.DrawRectangle(p.x,p.y,2000,2000); //dc.MaxX(),dc.MaxY());
491 wxLayoutList::CalculateCursor(wxDC
&dc
)
493 CoordType width
, height
, descent
;
494 CoordType baseLineSkip
= 20; //FIXME
497 if( FindCurrentObject() == iterator(NULL
)) // empty list
499 DrawCursor(dc
,true); // erase it
500 m_CursorCoords
= wxPoint(0,0);
501 m_CursorSize
= wxPoint(2,baseLineSkip
);
502 m_CursorMoved
= false; // coords are valid
505 wxLayoutObjectBase
&obj
= **FindCurrentObject(&offset
);
507 DrawCursor(dc
,true); // erase it
509 m_CursorCoords
= obj
.GetPosition();
510 if(obj
.GetType() == WXLO_TYPE_TEXT
)
512 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)&obj
;
513 String
& str
= tobj
->GetText();
514 String sstr
= str
.substr(0,offset
);
515 dc
.GetTextExtent(sstr
,&width
,&height
,&descent
);
516 m_CursorCoords
= wxPoint(m_CursorCoords
.x
+width
,
518 m_CursorSize
= wxPoint(2,height
);
520 else if(obj
.GetType() == WXLO_TYPE_LINEBREAK
)
522 if(m_CursorOffset
== 1) // behind linebreak
523 m_CursorCoords
= wxPoint(0, m_CursorCoords
.y
+ baseLineSkip
);
524 //m_CursorCoords = wxPoint(0, m_CursorCoords.y);
525 m_CursorSize
= wxPoint(2,baseLineSkip
);
529 // this is not necessarily the most "beautiful" solution:
530 //cursorPosition = wxPoint(position.x, position.y);
531 //cursorSize = wxPoint(size.x > 0 ? size.x : 1,size.y > 0 ? size.y : baseLineSkip);
532 m_CursorCoords
= wxPoint(m_CursorCoords
.x
+obj
.GetSize().x
, m_CursorCoords
.y
);
533 m_CursorSize
= wxPoint(2, obj
.GetSize().y
);
534 if(m_CursorSize
.y
< 1) m_CursorSize
.y
= baseLineSkip
;
536 m_CursorMoved
= false; // coords are valid
540 wxLayoutList::DrawCursor(wxDC
&dc
, bool erase
)
547 //dc.SetBrush(*wxWHITE_BRUSH);
548 //dc.SetPen(wxPen(*wxWHITE,1,wxSOLID));
549 //dc.DrawRectangle(m_CursorCoords.x, m_CursorCoords.y, m_CursorSize.x, m_CursorSize.y);
550 dc
.Blit(m_CursorCoords
.x
, m_CursorCoords
.y
, m_CursorSize
.x
,
551 m_CursorSize
.y
, &m_CursorMemDC
,
556 if(IsDirty() || CursorMoved())
562 wxBitmap
bm(m_CursorSize
.x
+1,m_CursorSize
.y
+1);
563 m_CursorMemDC
.SelectObject(bm
);
564 m_CursorMemDC
.Blit(0, 0, m_CursorSize
.x
, m_CursorSize
.y
,
565 &dc
, m_CursorCoords
.x
,
566 m_CursorCoords
.y
, 0, 0);
567 dc
.SetBrush(*wxBLACK_BRUSH
);
568 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
569 dc
.DrawRectangle(m_CursorCoords
.x
, m_CursorCoords
.y
,
570 m_CursorSize
.x
, m_CursorSize
.y
);
580 #ifdef WXLAYOUT_DEBUG
582 wxLayoutList::Debug(void)
584 wxLayoutObjectList::iterator i
;
586 wxLayoutDebug("------------------------ debug start ------------------------");
587 for(i
= begin(); i
!= end(); i
++)
589 wxLayoutDebug("-------------------------- list end -------------------------");
591 // show current object:
593 wxLayoutDebug("------------------------- debug end -------------------------");
597 wxLayoutList::ShowCurrentObject()
600 wxLayoutObjectList::iterator i
= FindCurrentObject(&offs
);
602 wxLayoutDebug("CursorPos (%d, %d)", (int) m_CursorPos
.x
, (int) m_CursorPos
.y
);
603 wxLayoutDebug("CursorOffset = %d", (int) m_CursorOffset
);
604 wxLayoutDebug("CursorObject = %p", m_CursorObject
);
605 wxLayoutDebug("Line length: %d", GetLineLength(i
));
607 if(i
== iterator(NULL
))
608 wxLayoutDebug("<<no object found>>");
611 if((*i
)->GetType() == WXLO_TYPE_TEXT
)
612 wxLayoutDebug(" \"%s\", offs: %d", ((wxLayoutObjectText
*)(*i
))->GetText().c_str(), offs
);
614 wxLayoutDebug(" %s", TypeString((*i
)->GetType()));
620 /******************** editing stuff ********************/
622 // don't change this, I know how to optimise this and will do it real
627 * Finds the object belonging to a given cursor position cpos and
628 * returns an iterator to that object and stores the relative cursor
629 * position in offset.
631 * For linebreaks, the offset can be 0=before or 1=after.
633 * If the cpos coordinates don't exist, they are modified.
636 wxLayoutObjectList::iterator
637 wxLayoutList::FindObjectCursor(wxPoint
*cpos
, CoordType
*offset
)
639 wxPoint object
= wxPoint(0,0); // runs along the objects
641 wxLayoutObjectList::iterator i
, begin_it
;
644 //#ifdef WXLAYOUT_DEBUG
645 // wxLayoutDebug("Looking for object at (%d, %d)", cpos->x, cpos->y);
648 // optimisation: compare to last looked at object:
649 if(cpos
->y
> m_FoundCursor
.y
|| (cpos
->y
== m_FoundCursor
.y
&&
650 cpos
->x
>= m_FoundCursor
.x
))
655 //broken at the moment
656 //begin_it = m_FoundIterator;
657 //m_FoundCursor = *cpos;
660 for(i
= begin_it
; i
!= end() && object
.y
<= cpos
->y
; )
662 width
= (**i
).CountPositions();
663 if(cpos
->y
== object
.y
) // a possible candidate
665 if((**i
).GetType() ==WXLO_TYPE_LINEBREAK
)
667 if(cpos
->x
== object
.x
)
669 if(offset
) *offset
= 0;
670 return m_FoundIterator
= i
;
672 if(offset
) *offset
=1;
674 return m_FoundIterator
= i
;
676 if(cpos
->x
>= object
.x
&& cpos
->x
<= object
.x
+width
) // overlap
678 if(offset
) *offset
= cpos
->x
-object
.x
;
679 //#ifdef WXLAYOUT_DEBUG
680 // wxLayoutDebug(" found object at (%d, %d), type: %s",
681 // object.x, object.y, TypeString((*i)->GetType()));
683 return m_FoundIterator
= i
;
686 // no overlap, increment coordinates
688 if((**i
).GetType() == WXLO_TYPE_LINEBREAK
)
698 //#ifdef WXLAYOUT_DEBUG
699 // wxLayoutDebug(" not found");
701 // return last object, coordinates of that one:
704 return m_FoundIterator
= i
;
705 if((**i
).GetType()==WXLO_TYPE_LINEBREAK
)
709 return m_FoundIterator
= i
;
711 cpos
->x
= object
.x
; // would be the coordinate of next object
713 cpos
->x
+= width
; // last object's width
714 if(*offset
) *offset
= cpos
->x
-object
.x
;
715 return m_FoundIterator
= i
; // not found
718 wxLayoutObjectList::iterator
719 wxLayoutList::FindCurrentObject(CoordType
*offset
)
722 *offset
= m_CursorOffset
;
723 return m_CursorObject
;
727 wxLayoutList::MoveCursor(int dx
, int dy
)
731 m_CursorMoved
= true;
733 enum { up
, down
} direction
;
735 wxPoint newPos
= wxPoint(m_CursorPos
.x
+ dx
,
739 //if(newPos.x < 0) newPos.x = 0;
740 if(newPos
.y
< 0) newPos
.y
= 0;
741 else if(newPos
.y
> m_MaxLine
) newPos
.y
= m_MaxLine
;
743 if(newPos
.y
> m_CursorPos
.y
||
744 newPos
.y
== m_CursorPos
.y
&&
745 newPos
.x
>= m_CursorPos
.x
)
750 // now move cursor forwards until at the new position:
752 // first, go to the right line:
753 while(newPos
.y
!= m_CursorPos
.y
)
755 if(direction
== down
)
758 (**m_CursorObject
).CountPositions() - m_CursorOffset
;
759 if(m_CursorObject
== tail())
760 break; // can't go any further
761 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
762 && m_CursorOffset
== 0)
764 m_CursorPos
.y
++; m_CursorPos
.x
= 0;
766 m_CursorObject
++; m_CursorOffset
= 0;
770 if(m_CursorObject
== begin())
771 break; // can't go any further
773 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
&&
777 m_CursorPos
.x
= GetLineLength(m_CursorObject
);
779 m_CursorPos
.x
-= m_CursorOffset
;
780 m_CursorObject
--; m_CursorOffset
= (**m_CursorObject
).CountPositions();
783 if(newPos
.y
!= m_CursorPos
.y
) // reached begin/end of list,
784 newPos
.y
= m_CursorPos
.y
; // exited by break
786 // now line is right, go to right column:
787 direction
= newPos
.x
>= m_CursorPos
.x
? down
: up
;
788 while(newPos
.x
!= m_CursorPos
.x
)
790 if(direction
== down
)
792 diff
= newPos
.x
- m_CursorPos
.x
;
793 if(diff
> (**m_CursorObject
).CountPositions()-m_CursorOffset
)
796 (**m_CursorObject
).CountPositions()-m_CursorOffset
;
797 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
&&
799 m_CursorPos
= wxPoint(0, m_CursorPos
.y
+1);
800 if(m_CursorObject
== tail())
801 break; // cannot go further
802 m_CursorObject
++; m_CursorOffset
= 0;
806 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
)
808 newPos
.y
++; newPos
.x
-= m_CursorPos
.x
+1;
809 m_CursorPos
= wxPoint(0,m_CursorPos
.y
+1);
812 m_CursorPos
.x
+= diff
;
813 m_CursorOffset
+= diff
;
818 if(m_CursorPos
.x
== 0 && m_CursorOffset
== 1 &&
819 (**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
) // can we go further up?
824 m_CursorPos
.x
= GetLineLength(m_CursorObject
)-1;
825 newPos
.x
+= m_CursorPos
.x
+1;
828 diff
= m_CursorPos
.x
- newPos
.x
;
829 if(diff
>= m_CursorOffset
)
831 if(m_CursorObject
== begin())
835 break; // cannot go further
838 m_CursorPos
.x
-= m_CursorOffset
;
839 m_CursorOffset
= (**m_CursorObject
).CountPositions();
843 m_CursorPos
.x
-= diff
;
844 m_CursorOffset
-= diff
;
848 return true; // FIXME: when return what?
852 wxLayoutList::Delete(CoordType count
)
862 wxLayoutObjectList::iterator i
;
866 i
= FindCurrentObject(&offs
);
867 startover
: // ugly, but easiest way to do it
869 return; // we cannot delete anything more
871 /* Here we need to treat linebreaks differently.
872 If offs==0 we are before the linebreak, otherwise behind. */
873 if((*i
)->GetType() == WXLO_TYPE_LINEBREAK
)
879 m_CursorObject
= i
; // new i!
880 m_CursorOffset
= 0; // Pos unchanged
882 continue; // we're done
884 else // delete the object behind the linebreak
886 i
++; // we increment and continue as normal
891 else if((*i
)->GetType() == WXLO_TYPE_TEXT
)
893 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
894 CoordType len
= tobj
->CountPositions();
895 // If we find the end of a text object, this means that we
896 // have to delete from the object following it.
903 else if(len
<= count
) // delete this object
914 tobj
->GetText().erase(offs
,len
);
916 return; // we are done
919 else// all other objects: delete the object
920 // this only works as expected if the non-text object has 0/1
921 // as offset values. Not tested with "longer" objects.
923 CoordType len
= (*i
)->CountPositions();
926 count
= count
> len
? count
-= len
: 0;
927 erase(i
); // after this, i is the iterator for the
933 else // delete the following object
935 i
++; // we increment and continue as normal
941 while(count
&& i
!= end());
945 wxLayoutList::Insert(wxLayoutObjectBase
*obj
)
947 wxCHECK_RET( obj
, "no object to insert" );
952 wxLayoutObjectList::iterator i
= FindCurrentObject(&offs
);
954 // if(i != iterator(NULL) && (*obj).GetType() == WXLO_TYPE_LINEBREAK)
956 // m_CursorPos.x = 0; m_CursorPos.y ++;
962 m_CursorObject
= tail();
969 // do we have to split a text object?
970 else if((*i
)->GetType() == WXLO_TYPE_TEXT
&& offs
!= (*i
)->CountPositions())
972 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
973 String left
= tobj
->GetText().substr(0,offs
); // get part before cursor
974 tobj
->GetText() = tobj
->GetText().substr(offs
,(*i
)->CountPositions()-offs
); // keeps the right half
976 insert(i
,new wxLayoutObjectText(left
)); // inserts before
980 // all other cases, append after object:
981 wxLayoutObjectList::iterator j
= i
; // we want to apend after this object
991 m_CursorObject
= tail();
995 if(obj
->GetType() != WXLO_TYPE_LINEBREAK
) // handled separately above
996 m_CursorPos
.x
+= obj
->CountPositions();
997 // applies also for linebreak:
998 m_CursorOffset
= obj
->CountPositions();
1000 if(obj
->GetType() == WXLO_TYPE_LINEBREAK
)
1002 m_CursorMoved
= true;
1006 wxLayoutList::Insert(String
const &text
)
1008 wxLayoutObjectText
*tobj
= NULL
;
1009 wxLayoutObjectList::iterator j
;
1011 // WXL_TRACE(Insert(text));
1019 wxLayoutObjectList::iterator i
= FindCurrentObject(&offs
);
1023 Insert(new wxLayoutObjectText(text
));
1027 if(i
!= iterator(NULL
) && (**i
).GetType() == WXLO_TYPE_LINEBREAK
)
1029 m_CursorPos
.x
= 0; m_CursorPos
.y
++;
1032 switch((**i
).GetType())
1034 case WXLO_TYPE_TEXT
:
1035 // insert into an existing text object:
1036 tobj
= (wxLayoutObjectText
*)*i
;
1038 tobj
->GetText().insert(offs
,text
);
1040 m_CursorOffset
= offs
+ text
.length();
1041 m_CursorPos
.x
+= text
.length();
1043 case WXLO_TYPE_LINEBREAK
:
1046 if(offs
== 0) // try to append to previous object
1049 if(j
!= end() && (**j
).GetType() == WXLO_TYPE_TEXT
)
1051 tobj
= (wxLayoutObjectText
*)*j
;
1052 tobj
->GetText()+=text
;
1054 m_CursorOffset
= (**j
).CountPositions();
1055 m_CursorPos
.x
+= text
.length();
1059 insert(i
,new wxLayoutObjectText(text
));
1061 m_CursorOffset
= (**i
).CountPositions();
1062 m_CursorPos
.x
+= m_CursorOffset
;
1065 else // offset == 1 : cursor after linebreak
1070 if(j
!= end() && (**j
).GetType() == WXLO_TYPE_TEXT
)
1072 tobj
= (wxLayoutObjectText
*)*j
;
1073 tobj
->GetText()=text
+tobj
->GetText();
1074 m_CursorOffset
= text
.length();
1075 m_CursorPos
.x
+= m_CursorOffset
;
1081 push_back(new wxLayoutObjectText(text
));
1082 m_CursorObject
= tail();
1083 m_CursorOffset
= (**m_CursorObject
).CountPositions();
1084 m_CursorPos
.x
+= text
.length();
1088 insert(j
,new wxLayoutObjectText(text
));
1090 m_CursorOffset
= (**j
).CountPositions();
1091 m_CursorPos
.x
+= text
.length();
1097 m_CursorMoved
= true;
1101 wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i
, CoordType offs
)
1108 if(offs
== 0 && (**i
).GetType() == WXLO_TYPE_LINEBREAK
)
1111 // search backwards for beginning of line:
1112 while(i
!= begin() && (*i
)->GetType() != WXLO_TYPE_LINEBREAK
)
1114 if((*i
)->GetType() == WXLO_TYPE_LINEBREAK
)
1116 // now we can start counting:
1117 while(i
!= end() && (*i
)->GetType() != WXLO_TYPE_LINEBREAK
)
1119 len
+= (*i
)->CountPositions();
1122 len
++; // one extra for the linebreak
1127 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1128 int underline
, char const *fg
, char const *bg
)
1131 m_CursorMoved
= true;
1132 m_dirty
= true; // force redraw/recalc
1133 wxLayoutObjectList::iterator i
= begin();
1136 m_CursorMemDC
.SelectObject(bm
);
1138 while(i
!= end()) // == while valid
1142 m_FontPtSize
= size
;
1143 m_FontUnderline
= false;
1144 m_FontFamily
= family
;
1145 m_FontStyle
= style
;
1146 m_FontWeight
= weight
;
1147 m_ColourFG
= wxTheColourDatabase
->FindColour(fg
);
1148 m_ColourBG
= wxTheColourDatabase
->FindColour(bg
);
1150 if(! m_ColourFG
) m_ColourFG
= wxBLACK
;
1151 if(! m_ColourBG
) m_ColourBG
= wxWHITE
;
1153 m_Position
= wxPoint(0,0);
1154 m_CursorPos
= wxPoint(0,0);
1155 m_CursorObject
= iterator(NULL
);
1157 m_CursorSize
= wxPoint(2,(BASELINESTRETCH
*m_FontPtSize
)/10);
1160 m_LineHeight
= (BASELINESTRETCH
*m_FontPtSize
)/10;
1161 m_MaxX
= 0; m_MaxY
= 0;
1164 m_FoundCursor
= wxPoint(0,0);
1165 m_FoundIterator
= begin();
1167 if(m_DefaultSetting
)
1168 delete m_DefaultSetting
;
1170 m_DefaultSetting
= new
1171 wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,
1172 m_FontWeight
,m_FontUnderline
,
1173 m_ColourFG
, m_ColourBG
);
1177 wxLayoutObjectBase
*
1178 wxLayoutList::Find(wxPoint coords
) const
1180 wxLayoutObjectList::iterator i
= begin();
1182 wxPoint topleft
, bottomright
;
1184 while(i
!= end()) // == while valid
1186 wxLayoutObjectBase
*object
= *i
;
1187 topleft
= object
->GetPosition();
1188 if(coords
.y
>= topleft
.y
&& coords
.x
>= topleft
.x
)
1190 bottomright
= topleft
;
1191 bottomright
.x
+= object
->GetSize().x
;
1192 bottomright
.y
+= object
->GetSize().y
;
1193 if(coords
.x
<= bottomright
.x
&& coords
.y
<= bottomright
.y
)
1202 /******************** printing stuff ********************/
1204 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
&llist
,
1205 wxString
const & title
)
1212 bool wxLayoutPrintout::OnPrintPage(int page
)
1217 DrawHeader(*dc
,wxPoint(m_Margins
.left
,m_Margins
.top
/2),wxPoint(m_Margins
.right
,m_Margins
.top
),page
);
1219 top
= (page
- 1)*m_PrintoutHeight
;
1220 bottom
= top
+ m_PrintoutHeight
;
1221 // SetDeviceOrigin() doesn't work here, so we need to manually
1222 // translate all coordinates.
1223 wxPoint
translate(m_Margins
.left
,-top
+m_Margins
.top
);
1224 m_llist
->Draw(*dc
,top
,bottom
,wxLayoutObjectList::iterator(NULL
),translate
);
1231 bool wxLayoutPrintout::OnBeginDocument(int startPage
, int endPage
)
1233 if (!wxPrintout::OnBeginDocument(startPage
, endPage
))
1240 wxLayoutPrintout::OnPreparePrinting(void)
1246 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
1248 // ugly hack to get number of pages
1250 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
1252 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
1254 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
); // that's all we need it for
1256 // We do 5% margins on top and bottom, and a 5% high header line.
1257 m_Margins
.top
= m_PageHeight
/ 10 ; // 10%, half of it header
1258 m_Margins
.bottom
= m_PageHeight
- m_PageHeight
/ 20; // 95%
1259 // On the sides we reserve 10% each for the margins.
1260 m_Margins
.left
= m_PageWidth
/ 10;
1261 m_Margins
.right
= m_PageWidth
- m_PageWidth
/ 10;
1263 // This is the length of the printable area.
1264 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
1266 //FIXME this is wrong but not used at the moment
1267 m_PageWidth
= m_Margins
.right
- m_Margins
.left
;
1269 m_NumOfPages
= (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
) + 0.5);
1271 *maxPage
= m_NumOfPages
;
1274 *selPageTo
= m_NumOfPages
;
1275 wxRemoveFile(WXLLIST_TEMPFILE
);
1278 bool wxLayoutPrintout::HasPage(int pageNum
)
1280 return pageNum
< m_NumOfPages
;
1285 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
1286 wxPoint topleft
, wxPoint bottomright
,
1289 // make backups of all essential parameters
1290 wxBrush
*brush
= dc
.GetBrush();
1291 wxPen
*pen
= dc
.GetPen();
1292 wxFont
*font
= dc
.GetFont(),
1295 dc
.SetBrush(*wxWHITE_BRUSH
);
1296 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
1297 dc
.DrawRoundedRectangle(topleft
.x
,
1298 topleft
.y
,bottomright
.x
-topleft
.x
,
1299 bottomright
.y
-topleft
.y
);
1300 dc
.SetBrush(*wxBLACK_BRUSH
);
1301 myfont
= new wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
1302 dc
.SetFont(*myfont
);
1305 page
= "9999/9999 "; // many pages...
1307 dc
.GetTextExtent(page
,&w
,&h
);
1308 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
1309 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
1310 dc
.GetTextExtent("XXXX", &w
,&h
);
1311 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
1315 dc
.SetBrush(*brush
);
1323 wxLayoutList::MakePrintout(wxString
const &name
)
1325 return new wxLayoutPrintout(*this,name
);