1 /*-*- c++ -*-********************************************************
2 * wxllist: wxLayoutList, a layout engine for text and graphics *
4 * (C) 1998-1999 by Karsten Ballüder (Ballueder@usa.net) *
7 *******************************************************************/
14 #pragma implementation "wxllist.h"
20 #include "wx/wxprec.h"
26 # include "gui/wxllist.h"
27 # undef SHOW_SELECTIONS
30 # define SHOW_SELECTIONS
34 # include "iostream.h"
37 # include <wx/print.h>
43 /// This should never really get created
44 #define WXLLIST_TEMPFILE "__wxllist.tmp"
48 # define TypewxString(t) g_aTypewxStrings[t]
49 # define WXLO_DEBUG(x) wxLogDebug x
51 static const char *g_aTypewxStrings
[] =
53 "invalid", "text", "cmd", "icon"
56 wxLayoutObject::Debug(void)
58 WXLO_DEBUG(("%s",g_aTypewxStrings
[GetType()]));
61 # define TypewxString(t) ""
62 # define WXLO_DEBUG(x)
66 /// Cursors smaller than this disappear in XOR drawing mode
67 #define WXLO_MINIMUM_CURSOR_WIDTH 4
69 /// Use this character to estimate a cursor size when none is available.
70 #define WXLO_CURSORCHAR "E"
71 /** @name Helper functions */
73 /// allows me to compare to wxPoints
74 bool operator ==(wxPoint
const &p1
, wxPoint
const &p2
)
76 return p1
.x
== p2
.x
&& p1
.y
== p2
.y
;
79 /// allows me to compare to wxPoints
80 bool operator !=(wxPoint
const &p1
, wxPoint
const &p2
)
82 return p1
.x
!= p2
.x
|| p1
.y
!= p2
.y
;
85 /// allows me to compare to wxPoints
86 bool operator <=(wxPoint
const &p1
, wxPoint
const &p2
)
88 return p1
.y
< p2
.y
|| (p1
.y
== p2
.y
&& p1
.x
<= p2
.x
);
91 /// grows a wxRect so that it includes the given point
94 void GrowRect(wxRect
&r
, CoordType x
, CoordType y
)
98 else if(r
.x
+ r
.width
< x
)
103 else if(r
.y
+ r
.height
< y
)
107 /// returns true if the point is in the rectangle
109 bool Contains(const wxRect
&r
, const wxPoint
&p
)
111 return r
.x
<= p
.x
&& r
.y
<= p
.y
&& (r
.x
+r
.width
) >= p
.x
&& (r
.y
+ r
.height
) >= p
.y
;
117 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
121 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
123 wxLayoutObjectText::wxLayoutObjectText(const wxString
&txt
)
133 wxLayoutObjectText::Copy(void)
135 wxLayoutObjectText
*obj
= new wxLayoutObjectText(m_Text
);
136 obj
->m_Width
= m_Width
;
137 obj
->m_Height
= m_Height
;
139 obj
->m_Bottom
= m_Bottom
;
140 obj
->SetUserData(m_UserData
);
145 wxLayoutObjectText::GetSize(CoordType
*top
, CoordType
*bottom
) const
148 *top
= m_Top
; *bottom
= m_Bottom
;
149 return wxPoint(m_Width
, m_Height
);
153 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &coords
,
154 wxLayoutList
*wxllist
,
155 CoordType begin
, CoordType end
)
158 dc
.DrawText(m_Text
, coords
.x
, coords
.y
-m_Top
);
161 // highlight the bit between begin and len
165 ypos
= coords
.y
-m_Top
;
166 long width
, height
, descent
;
168 str
= m_Text
.Mid(0, begin
);
169 dc
.DrawText(str
, xpos
, ypos
);
170 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
172 wxllist
->StartHighlighting(dc
);
173 str
= m_Text
.Mid(begin
, end
-begin
);
174 dc
.DrawText(str
, xpos
, ypos
);
175 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
177 wxllist
->EndHighlighting(dc
);
178 str
= m_Text
.Mid(end
, m_Text
.Length()-end
);
179 dc
.DrawText(str
, xpos
, ypos
);
184 wxLayoutObjectText::GetOffsetScreen(wxDC
&dc
, CoordType xpos
) const
188 maxlen
= m_Text
.Length();
191 height
, descent
= 0l;
193 if(xpos
== 0) return 0; // easy
195 while(width
< xpos
&& offs
< maxlen
)
197 dc
.GetTextExtent(m_Text
.substr(0,offs
),
198 &width
, &height
, &descent
);
201 /* We have to substract 1 to compensate for the offs++, and another
202 one because we don't want to position the cursor behind the
203 object what we clicked on, but before - otherwise it looks
205 return (xpos
> 2) ? offs
-2 : 0;
209 wxLayoutObjectText::Layout(wxDC
&dc
)
213 dc
.GetTextExtent(m_Text
,&m_Width
, &m_Height
, &descent
);
215 m_Top
= m_Height
- m_Bottom
;
218 #ifdef WXLAYOUT_DEBUG
220 wxLayoutObjectText::Debug(void)
222 wxLayoutObject::Debug();
223 WXLO_DEBUG((" `%s`", m_Text
.c_str()));
227 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
231 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
233 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
const &icon
)
235 m_Icon
= new wxBitmap(icon
);
239 wxLayoutObjectIcon::Copy(void)
241 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon(new
243 obj
->SetUserData(m_UserData
);
247 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
*icon
)
253 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &coords
,
254 wxLayoutList
*wxllist
,
255 CoordType begin
, CoordType
/* len */)
257 dc
.DrawBitmap(*m_Icon
, coords
.x
, coords
.y
-m_Icon
->GetHeight(),
258 (m_Icon
->GetMask() == NULL
) ? FALSE
: TRUE
);
262 wxLayoutObjectIcon::Layout(wxDC
& /* dc */)
267 wxLayoutObjectIcon::GetSize(CoordType
*top
, CoordType
*bottom
) const
269 *top
= m_Icon
->GetHeight();
271 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
276 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
280 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
282 wxLayoutObjectCmd::wxLayoutObjectCmd(int size
, int family
, int style
, int
283 weight
, bool underline
,
284 wxColour
&fg
, wxColour
&bg
)
287 m_font
= new wxFont(size
,family
,style
,weight
,underline
);
293 wxLayoutObjectCmd::Copy(void)
295 wxLayoutStyleInfo si
;
298 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
299 si
.size
, si
.family
, si
.style
, si
.weight
, si
.underline
,
300 m_ColourFG
, m_ColourBG
);
301 obj
->SetUserData(m_UserData
);
306 wxLayoutObjectCmd::~wxLayoutObjectCmd()
312 wxLayoutObjectCmd::GetStyle(wxLayoutStyleInfo
*si
) const
314 si
->size
= m_font
->GetPointSize();
315 si
->family
= m_font
->GetFamily();
316 si
->style
= m_font
->GetStyle();
317 si
->underline
= m_font
->GetUnderlined();
318 si
->weight
= m_font
->GetWeight();
320 si
->fg_red
= m_ColourFG
.Red();
321 si
->fg_green
= m_ColourFG
.Green();
322 si
->fg_blue
= m_ColourFG
.Blue();
323 si
->bg_red
= m_ColourBG
.Red();
324 si
->bg_green
= m_ColourBG
.Green();
325 si
->bg_blue
= m_ColourBG
.Blue();
329 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
330 wxLayoutList
*wxllist
,
331 CoordType begin
, CoordType
/* len */)
335 dc
.SetTextForeground(m_ColourFG
);
336 dc
.SetTextBackground(m_ColourBG
);
340 wxLayoutObjectCmd::Layout(wxDC
&dc
)
342 // this get called, so that recalculation uses right font sizes
343 Draw(dc
, wxPoint(0,0), NULL
);
347 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
349 The wxLayoutLine object
351 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
353 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
356 m_Width
= m_Height
= 0;
361 RecalculatePosition(llist
);
364 m_LineNumber
= m_Previous
->GetLineNumber()+1;
365 m_Next
= m_Previous
->GetNextLine();
366 m_Previous
->m_Next
= this;
367 m_Height
= m_Previous
->GetHeight();
371 m_Next
->m_Previous
= this;
372 m_Next
->MoveLines(+1);
373 m_Next
->RecalculatePositions(1,llist
);
377 wxLayoutLine::~wxLayoutLine()
379 // kbList cleans itself
383 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
386 m_Position
= m_Previous
->GetPosition() +
387 wxPoint(0,m_Previous
->GetHeight());
389 m_Position
= wxPoint(0,0);
390 llist
->SetUpdateRect(m_Position
);
395 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
397 wxASSERT(recurse
>= 0);
398 wxPoint pos
= m_Position
;
399 CoordType height
= m_Height
;
401 // WXLO_TRACE("RecalculatePositions()");
402 RecalculatePosition(llist
);
406 m_Next
->RecalculatePositions(--recurse
, llist
);
407 else if(pos
!= m_Position
|| m_Height
!= height
)
408 m_Next
->RecalculatePositions(0, llist
);
412 wxLayoutObjectList::iterator
413 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
417 wxLayoutObjectList::iterator
420 CoordType x
= 0, len
;
422 /* We search through the objects. As we don't like returning the
423 object that the cursor is behind, we just remember such an
424 object in "found" so we can return it if there is really no
425 further object following it. */
426 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
428 len
= (**i
).GetLength();
429 if( x
<= xpos
&& xpos
<= x
+ len
)
432 if(xpos
== x
+ len
) // is there another object behind?
434 else // we are really inside this object
437 x
+= (**i
).GetLength();
439 return found
; // ==NULL if really none found
442 wxLayoutObjectList::iterator
443 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
444 CoordType xpos
, CoordType
*cxpos
,
449 wxLayoutObjectList::iterator i
;
450 CoordType x
= 0, cx
= 0, width
;
452 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
455 width
= (**i
).GetWidth();
456 if( x
<= xpos
&& xpos
<= x
+ width
)
458 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
459 wxLogDebug("wxLayoutLine::FindObjectScreen: cursor xpos = %ld", *cxpos
);
460 if(found
) *found
= true;
463 x
+= (**i
).GetWidth();
464 cx
+= (**i
).GetLength();
466 // behind last object:
468 if(found
) *found
= false;
469 return m_ObjectList
.tail();
473 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
476 wxASSERT(obj
!= NULL
);
478 wxLOiterator i
= FindObject(xpos
, &offset
);
481 if(xpos
== 0 ) // aha, empty line!
483 m_ObjectList
.push_back(obj
);
484 m_Length
+= obj
->GetLength();
491 CoordType len
= (**i
).GetLength();
492 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
493 { // insert before this object
494 m_ObjectList
.insert(i
,obj
);
495 m_Length
+= obj
->GetLength();
500 if( i
== m_ObjectList
.tail()) // last object?
501 m_ObjectList
.push_back(obj
);
503 { // insert after current object
505 m_ObjectList
.insert(i
,obj
);
507 m_Length
+= obj
->GetLength();
510 /* Otherwise we need to split the current object.
511 Fortunately this can only be a text object. */
512 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
513 wxString left
, right
;
514 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
515 left
= tobj
->GetText().substr(0,offset
);
516 right
= tobj
->GetText().substr(offset
,len
-offset
);
517 // current text object gets set to right half
518 tobj
->GetText() = right
; // set new text
519 // before it we insert the new object
520 m_ObjectList
.insert(i
,obj
);
521 m_Length
+= obj
->GetLength();
522 // and before that we insert the left half
523 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
528 wxLayoutLine::Insert(CoordType xpos
, wxString text
)
532 wxLOiterator i
= FindObject(xpos
, &offset
);
533 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
535 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
536 tobj
->GetText().insert(offset
, text
);
537 m_Length
+= text
.Length();
542 return Insert(xpos
, new wxLayoutObjectText(text
));
546 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
548 CoordType offset
, len
;
552 wxLOiterator i
= FindObject(xpos
, &offset
);
555 if(i
== NULLIT
) return npos
;
556 // now delete from that object:
557 if((**i
).GetType() != WXLO_TYPE_TEXT
)
559 if(offset
!= 0) // at end of line after a non-text object
562 len
= (**i
).GetLength();
565 m_ObjectList
.erase(i
);
569 // tidy up: remove empty text objects
570 if((**i
).GetLength() == 0)
572 m_ObjectList
.erase(i
);
576 CoordType max
= (**i
).GetLength() - offset
;
577 if(npos
< max
) max
= npos
;
580 if(xpos
== GetLength())
583 { // at the end of an object
584 // move to begin of next object:
586 continue; // start over
591 if(offset
== 0 && max
== (**i
).GetLength())
592 m_ObjectList
.erase(i
); // remove the whole object
594 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
601 wxLayoutLine::DeleteWord(CoordType xpos
)
606 wxLOiterator i
= FindObject(xpos
, &offset
);
610 if(i
== NULLIT
) return false;
611 if((**i
).GetType() != WXLO_TYPE_TEXT
)
613 // This should only happen when at end of line, behind a non-text
615 if(offset
== (**i
).GetLength()) return false;
616 m_Length
-= (**i
).GetLength(); // -1
617 m_ObjectList
.erase(i
);
618 return true; // we are done
622 if(offset
== (**i
).GetLength()) // at end of object
627 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
629 wxString str
= tobj
->GetText();
630 str
= str
.substr(offset
,str
.Length()-offset
);
631 // Find out how many positions we need to delete:
632 // 1. eat leading space
633 while(isspace(str
.c_str()[count
])) count
++;
634 // 2. eat the word itself:
635 while(isalnum(str
.c_str()[count
])) count
++;
637 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
638 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
643 wxASSERT(0); // we should never arrive here
647 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
649 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
650 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
653 m_Next
->MoveLines(-1);
654 m_Next
->RecalculatePositions(1, llist
);
656 wxLayoutLine
*next
= m_Next
;
662 wxLayoutLine::Draw(wxDC
&dc
,
664 const wxPoint
& offset
) const
666 wxLayoutObjectList::iterator i
;
667 wxPoint pos
= offset
;
668 pos
= pos
+ GetPosition();
672 CoordType xpos
= 0; // cursorpos, lenght of line
674 CoordType from
, to
, tempto
;
675 int highlight
= llist
->IsSelected(this, &from
, &to
);
676 if(highlight
== 1) // we need to draw the whole line inverted!
677 llist
->StartHighlighting(dc
);
679 llist
->EndHighlighting(dc
);
681 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
683 if(highlight
== -1) // partially highlight line
685 // parts of the line need highlighting
686 tempto
= xpos
+(**i
).GetLength();
687 if(tempto
>= from
&& xpos
<= to
)
690 if(tempto
> (**i
).GetLength())
691 tempto
= (**i
).GetLength();
692 CoordType tmp
= from
-xpos
;
694 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, to
);
698 llist
->EndHighlighting(dc
); // FIXME! inefficient
699 (**i
).Draw(dc
, pos
, llist
);
703 (**i
).Draw(dc
, pos
, llist
);
704 pos
.x
+= (**i
).GetWidth();
705 xpos
+= (**i
).GetLength();
710 wxLayoutLine::Layout(wxDC
&dc
,
716 wxLayoutObjectList::iterator i
;
719 oldHeight
= m_Height
;
721 topHeight
, bottomHeight
; // above and below baseline
724 objTopHeight
, objBottomHeight
;
727 m_Height
= 0; m_BaseLine
= 0;
729 topHeight
= 0; bottomHeight
= 0;
731 bool cursorFound
= false;
735 *cursorPos
= m_Position
;
736 if(cursorSize
) *cursorSize
= wxPoint(0,0);
739 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
742 size
= (**i
).GetSize(&objTopHeight
, &objBottomHeight
);
744 if(cursorPos
&& ! cursorFound
)
745 { // we need to check whether the text cursor is here
746 len
= (**i
).GetLength();
747 if(count
<= cx
&& count
+len
> cx
)
749 if((**i
).GetType() == WXLO_TYPE_TEXT
)
751 len
= cx
- count
; // pos in object
752 CoordType width
, height
, descent
;
753 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
754 &width
, &height
, &descent
);
755 cursorPos
->x
+= width
;
756 cursorPos
->y
= m_Position
.y
;
758 if(len
< (**i
).GetLength())
759 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
761 str
= WXLO_CURSORCHAR
;
762 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
763 wxASSERT(cursorSize
);
764 // Just in case some joker inserted an empty string object:
765 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
766 if(height
== 0) height
= objHeight
;
767 cursorSize
->x
= width
;
768 cursorSize
->y
= height
;
769 cursorFound
= true; // no more checks
772 { // on some other object
773 CoordType top
, bottom
; // unused
774 *cursorSize
= (**i
).GetSize(&top
,&bottom
);
775 cursorPos
->y
= m_Position
.y
;
776 cursorFound
= true; // no more checks
782 cursorPos
->x
+= (**i
).GetWidth();
787 if(objHeight
> m_Height
) m_Height
= objHeight
;
788 if(objTopHeight
> topHeight
) topHeight
= objTopHeight
;
789 if(objBottomHeight
> bottomHeight
) bottomHeight
= objBottomHeight
;
791 if(topHeight
+ bottomHeight
> m_Height
) m_Height
=
792 topHeight
+bottomHeight
;
793 m_BaseLine
= topHeight
;
797 if(GetPreviousLine()) // empty line
799 m_Height
= GetPreviousLine()->GetHeight();
800 m_BaseLine
= GetPreviousLine()->m_BaseLine
;
804 CoordType width
, height
, descent
;
805 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
807 m_BaseLine
= m_Height
- descent
;
812 // tell next line about coordinate change
813 if(m_Next
&& objHeight
!= oldHeight
)
814 m_Next
->RecalculatePositions(0, llist
);
816 // We need to check whether we found a valid cursor size:
819 // this might be the case if the cursor is at the end of the
820 // line or on a command object:
821 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
823 CoordType width
, height
, descent
;
824 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
825 cursorSize
->x
= width
;
826 cursorSize
->y
= height
;
828 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
829 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
835 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
840 { // insert an empty line before this one
841 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
842 if(m_Previous
== NULL
)
843 { // We were in first line, need to link in new empty line
847 m_Previous
->m_Height
= GetHeight(); // this is a wild guess
851 m_Next
->RecalculatePositions(1, llist
);
856 wxLOiterator i
= FindObject(xpos
, &offset
);
858 // must be at the end of the line then
859 return new wxLayoutLine(this, llist
);
862 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
863 // split object at i:
864 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
866 wxString left
, right
;
867 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
868 left
= tobj
->GetText().substr(0,offset
);
869 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
870 // current text object gets set to left half
871 tobj
->GetText() = left
; // set new text
872 newLine
->Append(new wxLayoutObjectText(right
));
873 m_Length
-= right
.Length();
874 i
++; // don't move this object to the new list
878 i
++; // move objects from here to new list
880 while(i
!= m_ObjectList
.end())
883 m_Length
-= (**i
).GetLength();
884 m_ObjectList
.remove(i
); // remove without deleting it
887 m_Next
->RecalculatePositions(2, llist
);
893 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
895 wxASSERT(GetNextLine());
896 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
899 for(i
= list
.begin(); i
!= list
.end();)
902 list
.remove(i
); // remove without deleting it
904 wxASSERT(list
.empty());
905 wxLayoutLine
*oldnext
= GetNextLine();
906 SetNext(GetNextLine()->GetNextLine());
908 RecalculatePositions(1, llist
);
912 wxLayoutLine::GetWrapPosition(CoordType column
)
915 wxLOiterator i
= FindObject(column
, &offset
);
916 if(i
== NULLIT
) return -1; // cannot wrap
918 // go backwards through the list and look for space in text objects
921 if((**i
).GetType() == WXLO_TYPE_TEXT
)
925 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
932 }while(offset
!= -1);
933 i
--; // move on to previous object
937 column
-= (**i
).GetLength();
941 offset
= (**i
).GetLength();
943 /* If we reached the begin of the list and have more than one
944 object, that one is longer than the margin, so break behind
947 i
= m_ObjectList
.begin();
948 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
950 pos
+= (**i
).GetLength();
953 if(i
== NULLIT
) return -1; //why should this happen?
954 pos
+= (**i
).GetLength();
956 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
958 pos
+= (**i
).GetLength();
961 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
962 // now we are at the second text object:
963 pos
-= (**i
).GetLength();
964 return pos
; // in front of it
968 #ifdef WXLAYOUT_DEBUG
970 wxLayoutLine::Debug(void)
973 wxPoint pos
= GetPosition();
974 tmp
.Printf("Line %ld, Pos (%ld,%ld), Height %ld",
975 (long int) GetLineNumber(),
976 (long int) pos
.x
, (long int) pos
.y
,
977 (long int) GetHeight());
983 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
985 The wxLayoutList object
987 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
989 wxLayoutList::wxLayoutList()
991 m_DefaultSetting
= NULL
;
993 m_ColourFG
= *wxBLACK
;
994 m_ColourBG
= *wxWHITE
;
995 InvalidateUpdateRect();
999 wxLayoutList::~wxLayoutList()
1002 m_FirstLine
->DeleteLine(false, this);
1006 wxLayoutList::Empty(void)
1009 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1011 m_CursorPos
= wxPoint(0,0);
1012 m_CursorScreenPos
= wxPoint(0,0);
1013 m_CursorSize
= wxPoint(0,0);
1014 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1015 m_CursorLine
= m_FirstLine
;
1016 InvalidateUpdateRect();
1021 wxLayoutList::InternalClear(void)
1024 if(m_DefaultSetting
)
1026 delete m_DefaultSetting
;
1027 m_DefaultSetting
= NULL
;
1032 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1033 int underline
, wxColour
*fg
,
1036 if(family
!= -1) m_FontFamily
= family
;
1037 if(size
!= -1) m_FontPtSize
= size
;
1038 if(style
!= -1) m_FontStyle
= style
;
1039 if(weight
!= -1) m_FontWeight
= weight
;
1040 if(underline
!= -1) m_FontUnderline
= underline
!= 0;
1042 if(fg
!= NULL
) m_ColourFG
= *fg
;
1043 if(bg
!= NULL
) m_ColourBG
= *bg
;
1046 new wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,m_FontWeight
,m_FontUnderline
,
1047 m_ColourFG
, m_ColourBG
));
1051 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1052 int underline
, char const *fg
, char const *bg
)
1060 cfg
= wxTheColourDatabase
->FindColour(fg
);
1062 cbg
= wxTheColourDatabase
->FindColour(bg
);
1064 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1068 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1069 int /* underline */, wxColour
*fg
, wxColour
*bg
)
1074 m_FontPtSize
= size
;
1075 m_FontUnderline
= false;
1076 m_FontFamily
= family
;
1077 m_FontStyle
= style
;
1078 m_FontWeight
= weight
;
1079 if(fg
) m_ColourFG
= *fg
;
1080 if(bg
) m_ColourBG
= *bg
;
1082 m_ColourFG
= *wxBLACK
;
1083 m_ColourBG
= *wxWHITE
;
1085 if(m_DefaultSetting
)
1086 delete m_DefaultSetting
;
1088 m_DefaultSetting
= new
1089 wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,
1090 m_FontWeight
,m_FontUnderline
,
1091 m_ColourFG
, m_ColourBG
);
1097 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1099 SetUpdateRect(m_CursorScreenPos
);
1100 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1101 wxLayoutLine
*line
= m_FirstLine
;
1102 while(line
&& line
->GetLineNumber() != p
.y
)
1103 line
= line
->GetNextLine();
1104 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1106 m_CursorPos
.y
= p
.y
;
1107 m_CursorLine
= line
;
1108 CoordType len
= line
->GetLength();
1111 m_CursorPos
.x
= p
.x
;
1116 m_CursorPos
.x
= len
;
1124 wxLayoutList::MoveCursorVertically(int n
)
1126 SetUpdateRect(m_CursorScreenPos
);
1127 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1129 if(n
< 0) // move up
1131 if(m_CursorLine
== m_FirstLine
) return false;
1132 while(n
< 0 && m_CursorLine
)
1134 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1140 m_CursorLine
= m_FirstLine
;
1146 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1147 m_CursorPos
.x
= m_CursorLine
->GetLength();
1153 wxLayoutLine
*last
= m_CursorLine
;
1154 if(! m_CursorLine
->GetNextLine()) return false;
1155 while(n
> 0 && m_CursorLine
)
1159 m_CursorLine
= m_CursorLine
->GetNextLine();
1163 m_CursorLine
= last
;
1169 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1170 m_CursorPos
.x
= m_CursorLine
->GetLength();
1178 wxLayoutList::MoveCursorHorizontally(int n
)
1180 SetUpdateRect(m_CursorScreenPos
);
1181 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1185 if(m_CursorPos
.x
== 0) // at begin of line
1187 if(! MoveCursorVertically(-1))
1189 MoveCursorToEndOfLine();
1194 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1195 m_CursorPos
.x
-= move
; n
+= move
;
1200 int len
= m_CursorLine
->GetLength();
1201 if(m_CursorPos
.x
== len
) // at end of line
1203 if(! MoveCursorVertically(1))
1205 MoveCursorToBeginOfLine();
1210 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1211 m_CursorPos
.x
+= move
;
1218 wxLayoutList::Insert(wxString
const &text
)
1220 wxASSERT(m_CursorLine
);
1221 SetUpdateRect(m_CursorScreenPos
);
1222 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1223 m_CursorLine
->Insert(m_CursorPos
.x
, text
);
1224 m_CursorPos
.x
+= text
.Length();
1229 wxLayoutList::Insert(wxLayoutObject
*obj
)
1231 wxASSERT(m_CursorLine
);
1232 SetUpdateRect(m_CursorScreenPos
);
1233 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1234 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1235 m_CursorPos
.x
+= obj
->GetLength();
1240 wxLayoutList::LineBreak(void)
1242 wxASSERT(m_CursorLine
);
1243 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1244 SetUpdateRect(m_CursorScreenPos
);
1245 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1246 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1247 if(setFirst
) // we were at beginning of first line
1248 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1255 wxLayoutList::WrapLine(CoordType column
)
1257 if(m_CursorPos
.x
<= column
|| column
< 1)
1258 return false; // do nothing yet
1261 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1263 return false; // cannot break line
1265 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1266 m_CursorPos
.x
= xpos
;
1267 SetUpdateRect(m_CursorScreenPos
);
1268 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1270 Delete(1); // delete the space
1271 m_CursorPos
.x
= newpos
;
1277 wxLayoutList::Delete(CoordType npos
)
1279 wxASSERT(m_CursorLine
);
1280 SetUpdateRect(m_CursorScreenPos
);
1281 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1285 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1288 // More to delete, continue on next line.
1289 // First, check if line is empty:
1290 if(m_CursorLine
->GetLength() == 0)
1291 { // in this case, updating could probably be optimised
1293 wxASSERT(DeleteLines(1) == 0);
1302 // Need to join next line
1303 if(! m_CursorLine
->GetNextLine())
1307 m_CursorLine
->MergeNextLine(this);
1317 wxLayoutList::DeleteLines(int n
)
1319 wxASSERT(m_CursorLine
);
1321 SetUpdateRect(m_CursorScreenPos
);
1322 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1325 if(!m_CursorLine
->GetNextLine())
1326 { // we cannot delete this line, but we can clear it
1327 MoveCursorToBeginOfLine();
1328 DeleteToEndOfLine();
1332 line
= m_CursorLine
;
1333 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
1335 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
1336 wxASSERT(m_FirstLine
);
1337 wxASSERT(m_CursorLine
);
1339 m_CursorLine
->RecalculatePositions(2, this);
1344 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
1346 wxLayoutLine
*line
= m_FirstLine
;
1348 // first, make sure everything is calculated - this might not be
1349 // needed, optimise it later
1350 m_DefaultSetting
->Layout(dc
);
1353 line
->RecalculatePosition(this); // so we don't need to do it all the time
1354 // little condition to speed up redrawing:
1355 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1356 line
= line
->GetNextLine();
1361 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
)
1363 wxASSERT(m_CursorLine
);
1364 m_CursorLine
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1368 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
1370 UpdateCursorScreenPos(dc
);
1371 return m_CursorScreenPos
;
1375 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
)
1377 wxLayoutLine
*line
= m_FirstLine
;
1379 // first, make sure everything is calculated - this might not be
1380 // needed, optimise it later
1381 m_DefaultSetting
->Layout(dc
);
1384 if(line
== m_CursorLine
)
1385 line
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1387 line
->Layout(dc
, this);
1388 // little condition to speed up redrawing:
1389 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1390 line
= line
->GetNextLine();
1393 ///FIXME: disabled for now
1395 // can only be 0 if we are on the first line and have no next line
1396 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1397 m_CursorLine
->GetNextLine() == NULL
&&
1398 m_CursorLine
== m_FirstLine
));
1400 SetUpdateRect(m_CursorScreenPos
);
1401 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1405 wxLayoutList::Draw(wxDC
&dc
,
1406 wxPoint
const &offset
,
1410 wxLayoutLine
*line
= m_FirstLine
;
1413 m_DefaultSetting
->Draw(dc
, wxPoint(0,0), this);
1414 wxBrush
brush(m_ColourBG
, wxSOLID
);
1419 // only draw if between top and bottom:
1420 if((top
== -1 || line
->GetPosition().y
+ line
->GetHeight() >= top
))
1421 line
->Draw(dc
, this, offset
);
1422 // little condition to speed up redrawing:
1423 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1424 line
= line
->GetNextLine();
1426 // can only be 0 if we are on the first line and have no next line
1427 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1428 m_CursorLine
->GetNextLine() == NULL
&&
1429 m_CursorLine
== m_FirstLine
));
1430 InvalidateUpdateRect();
1432 wxLogDebug("Selection is %s : l%d,%ld/%ld,%ld",
1433 m_Selection
.m_valid
? "valid" : "invalid",
1434 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
1435 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
);
1439 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
1443 // First, find the right line:
1444 wxLayoutLine
*line
= m_FirstLine
;
1447 // we need to run a layout here to get font sizes right :-(
1448 m_DefaultSetting
->Layout(dc
);
1451 p
= line
->GetPosition();
1452 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
1454 line
->Layout(dc
, this);
1455 line
= line
->GetNextLine();
1459 if(found
) *found
= false;
1460 return NULL
; // not found
1462 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
1463 // Now, find the object in the line:
1464 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
1465 cursorPos
? & cursorPos
->x
: NULL
,
1467 return (i
== NULLIT
) ? NULL
: *i
;
1472 wxLayoutList::GetSize(void) const
1475 *line
= m_FirstLine
,
1478 return wxPoint(0,0);
1480 wxPoint
maxPoint(0,0);
1485 if(line
->GetWidth() > maxPoint
.x
)
1486 maxPoint
.x
= line
->GetWidth();
1488 line
= line
->GetNextLine();
1491 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
1496 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
1499 coords
= m_CursorScreenPos
;
1500 coords
.x
+= translate
.x
;
1501 coords
.y
+= translate
.y
;
1503 #ifdef WXLAYOUT_DEBUG
1504 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
1505 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
1506 (long)coords
.x
, (long)coords
.y
,
1507 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
1508 (long)m_CursorLine
->GetLineNumber(),
1509 (long)m_CursorLine
->GetLength()));
1512 dc
.SetBrush(*wxBLACK_BRUSH
);
1513 dc
.SetLogicalFunction(wxXOR
);
1514 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
1516 dc
.DrawRectangle(coords
.x
, coords
.y
, m_CursorSize
.x
,
1519 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
1520 coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
-1);
1521 dc
.SetLogicalFunction(wxCOPY
);
1522 //dc.SetBrush(wxNullBrush);
1526 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
1528 if(m_UpdateRectValid
)
1529 GrowRect(m_UpdateRect
, x
, y
);
1534 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
1535 m_UpdateRect
.height
= 4;// wxGTK :-)
1536 m_UpdateRectValid
= true;
1541 wxLayoutList::StartSelection(void)
1543 wxLogDebug("Starting selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
);
1544 m_Selection
.m_CursorA
= m_CursorPos
;
1545 m_Selection
.m_selecting
= true;
1546 m_Selection
.m_valid
= false;
1550 wxLayoutList::ContinueSelection(void)
1552 wxASSERT(m_Selection
.m_selecting
== true);
1553 wxASSERT(m_Selection
.m_valid
== false);
1554 wxLogDebug("Continuing selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
);
1555 m_Selection
.m_CursorB
= m_CursorPos
;
1556 // We always want m_CursorA <= m_CursorB!
1557 if(! (m_Selection
.m_CursorA
<= m_Selection
.m_CursorB
))
1559 wxPoint help
= m_Selection
.m_CursorB
;
1560 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
1561 m_Selection
.m_CursorA
= help
;
1566 wxLayoutList::EndSelection(void)
1568 ContinueSelection();
1569 wxLogDebug("Ending selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
);
1570 m_Selection
.m_selecting
= false;
1571 m_Selection
.m_valid
= true;
1576 wxLayoutList::IsSelecting(void)
1578 return m_Selection
.m_selecting
;
1582 wxLayoutList::IsSelected(const wxPoint
&cursor
)
1584 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1586 return m_Selection
.m_CursorA
<= cursor
1587 && cursor
<= m_Selection
.m_CursorB
;
1591 /** Tests whether this layout line is selected and needs
1593 @param line to test for
1594 @return 0 = not selected, 1 = fully selected, -1 = partially
1598 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
1601 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
1603 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1606 CoordType y
= line
->GetLineNumber();
1607 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
1609 else if(m_Selection
.m_CursorA
.y
== y
)
1611 *from
= m_Selection
.m_CursorA
.x
;
1612 if(m_Selection
.m_CursorB
.y
== y
)
1613 *to
= m_Selection
.m_CursorB
.x
;
1615 *to
= line
->GetLength();
1618 else if(m_Selection
.m_CursorB
.y
== y
)
1620 *to
= m_Selection
.m_CursorB
.x
;
1621 if(m_Selection
.m_CursorA
.y
== y
)
1622 *from
= m_Selection
.m_CursorA
.x
;
1632 /// Starts highlighting the selection
1634 wxLayoutList::StartHighlighting(wxDC
&dc
)
1636 #ifdef SHOW_SELECTIONS
1637 dc
.SetTextForeground(m_ColourBG
);
1638 dc
.SetTextBackground(m_ColourFG
);
1642 /// Ends highlighting the selection
1644 wxLayoutList::EndHighlighting(wxDC
&dc
)
1646 #ifdef SHOW_SELECTIONS
1647 dc
.SetTextForeground(m_ColourFG
);
1648 dc
.SetTextBackground(m_ColourBG
);
1653 #ifdef WXLAYOUT_DEBUG
1656 wxLayoutList::Debug(void)
1661 for(line
= m_FirstLine
;
1663 line
= line
->GetNextLine())
1670 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1674 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1676 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
1677 wxString
const & title
)
1684 wxLayoutPrintout::~wxLayoutPrintout()
1689 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
1691 // The following bit is taken from the printing sample, let's see
1692 // whether it works for us.
1694 /* You might use THIS code to set the printer DC to ROUGHLY reflect
1695 * the screen text size. This page also draws lines of actual length 5cm
1698 // Get the logical pixels per inch of screen and printer
1699 int ppiScreenX
, ppiScreenY
;
1700 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
1701 int ppiPrinterX
, ppiPrinterY
;
1702 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
1704 if(ppiScreenX
== 0) // not yet set, need to guess
1709 if(ppiPrinterX
== 0) // not yet set, need to guess
1715 // This scales the DC so that the printout roughly represents the
1716 // the screen scaling. The text point size _should_ be the right size
1717 // but in fact is too small for some reason. This is a detail that will
1718 // need to be addressed at some point but can be fudged for the
1720 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
1722 // Now we have to check in case our real page size is reduced
1723 // (e.g. because we're drawing to a print preview memory DC)
1724 int pageWidth
, pageHeight
;
1726 dc
->GetSize(&w
, &h
);
1727 GetPageSizePixels(&pageWidth
, &pageHeight
);
1728 if(pageWidth
!= 0) // doesn't work always
1730 // If printer pageWidth == current DC width, then this doesn't
1731 // change. But w might be the preview bitmap width, so scale down.
1732 scale
= scale
* (float)(w
/(float)pageWidth
);
1734 dc
->SetUserScale(scale
, scale
);
1738 bool wxLayoutPrintout::OnPrintPage(int page
)
1747 top
= (page
- 1)*m_PrintoutHeight
;
1748 bottom
= top
+ m_PrintoutHeight
;
1749 // SetDeviceOrigin() doesn't work here, so we need to manually
1750 // translate all coordinates.
1751 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
1752 m_llist
->Draw(*dc
, translate
, top
, bottom
);
1759 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
1761 /* We allocate a temporary wxDC for printing, so that we can
1762 determine the correct paper size and scaling. We don't actually
1763 print anything on it. */
1765 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
1767 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
1770 float scale
= ScaleDC(&psdc
);
1772 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
1773 // This sets a left/top origin of 15% and 20%:
1774 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
1776 // This is the length of the printable area.
1777 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
1778 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
1782 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
1785 *maxPage
= m_NumOfPages
;
1788 *selPageTo
= m_NumOfPages
;
1789 wxRemoveFile(WXLLIST_TEMPFILE
);
1792 bool wxLayoutPrintout::HasPage(int pageNum
)
1794 return pageNum
<= m_NumOfPages
;
1798 Stupid wxWindows doesn't draw proper ellipses, so we comment this
1799 out. It's a waste of paper anyway.
1803 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
1804 wxPoint topleft
, wxPoint bottomright
,
1807 // make backups of all essential parameters
1808 const wxBrush
& brush
= dc
.GetBrush();
1809 const wxPen
& pen
= dc
.GetPen();
1810 const wxFont
& font
= dc
.GetFont();
1812 dc
.SetBrush(*wxWHITE_BRUSH
);
1813 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
1814 dc
.DrawRoundedRectangle(topleft
.x
,
1815 topleft
.y
,bottomright
.x
-topleft
.x
,
1816 bottomright
.y
-topleft
.y
);
1817 dc
.SetBrush(*wxBLACK_BRUSH
);
1818 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
1819 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
1823 page
= "9999/9999 "; // many pages...
1825 dc
.GetTextExtent(page
,&w
,&h
);
1826 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
1827 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
1828 dc
.GetTextExtent("XXXX", &w
,&h
);
1829 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);