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 # define SHOW_SELECTIONS 1
30 # define SHOW_SELECTIONS 1
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
)
109 /// returns true if the point is in the rectangle
111 bool Contains(const wxRect
&r
, const wxPoint
&p
)
113 return r
.x
<= p
.x
&& r
.y
<= p
.y
&& (r
.x
+r
.width
) >= p
.x
&& (r
.y
+ r
.height
) >= p
.y
;
120 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
124 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
126 wxLayoutObjectText::wxLayoutObjectText(const wxString
&txt
)
136 wxLayoutObjectText::Copy(void)
138 wxLayoutObjectText
*obj
= new wxLayoutObjectText(m_Text
);
139 obj
->m_Width
= m_Width
;
140 obj
->m_Height
= m_Height
;
142 obj
->m_Bottom
= m_Bottom
;
143 obj
->SetUserData(m_UserData
);
148 wxLayoutObjectText::GetSize(CoordType
*top
, CoordType
*bottom
) const
151 *top
= m_Top
; *bottom
= m_Bottom
;
152 return wxPoint(m_Width
, m_Height
);
156 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &coords
,
157 wxLayoutList
*wxllist
,
158 CoordType begin
, CoordType end
)
161 dc
.DrawText(m_Text
, coords
.x
, coords
.y
-m_Top
);
164 // highlight the bit between begin and len
168 ypos
= coords
.y
-m_Top
;
169 long width
, height
, descent
;
171 str
= m_Text
.Mid(0, begin
);
172 dc
.DrawText(str
, xpos
, ypos
);
173 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
175 wxllist
->StartHighlighting(dc
);
176 str
= m_Text
.Mid(begin
, end
-begin
);
177 dc
.DrawText(str
, xpos
, ypos
);
178 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
180 wxllist
->EndHighlighting(dc
);
181 str
= m_Text
.Mid(end
, m_Text
.Length()-end
);
182 dc
.DrawText(str
, xpos
, ypos
);
187 wxLayoutObjectText::GetOffsetScreen(wxDC
&dc
, CoordType xpos
) const
191 maxlen
= m_Text
.Length();
194 height
, descent
= 0l;
196 if(xpos
== 0) return 0; // easy
198 while(width
< xpos
&& offs
< maxlen
)
200 dc
.GetTextExtent(m_Text
.substr(0,offs
),
201 &width
, &height
, &descent
);
204 /* We have to substract 1 to compensate for the offs++, and another
205 one because we don't want to position the cursor behind the
206 object what we clicked on, but before - otherwise it looks
208 return (xpos
> 2) ? offs
-2 : 0;
212 wxLayoutObjectText::Layout(wxDC
&dc
)
216 dc
.GetTextExtent(m_Text
,&m_Width
, &m_Height
, &descent
);
218 m_Top
= m_Height
- m_Bottom
;
221 #ifdef WXLAYOUT_DEBUG
223 wxLayoutObjectText::Debug(void)
225 wxLayoutObject::Debug();
226 WXLO_DEBUG((" `%s`", m_Text
.c_str()));
230 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
234 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
236 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
const &icon
)
238 m_Icon
= new wxBitmap(icon
);
242 wxLayoutObjectIcon::Copy(void)
244 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon(new
246 obj
->SetUserData(m_UserData
);
250 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
*icon
)
256 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &coords
,
257 wxLayoutList
*wxllist
,
258 CoordType begin
, CoordType
/* len */)
260 dc
.DrawBitmap(*m_Icon
, coords
.x
, coords
.y
-m_Icon
->GetHeight(),
261 (m_Icon
->GetMask() == NULL
) ? FALSE
: TRUE
);
265 wxLayoutObjectIcon::Layout(wxDC
& /* dc */)
270 wxLayoutObjectIcon::GetSize(CoordType
*top
, CoordType
*bottom
) const
272 *top
= m_Icon
->GetHeight();
274 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
279 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
283 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
285 wxLayoutObjectCmd::wxLayoutObjectCmd(int size
, int family
, int style
, int
286 weight
, bool underline
,
287 wxColour
&fg
, wxColour
&bg
)
290 m_font
= new wxFont(size
,family
,style
,weight
,underline
);
296 wxLayoutObjectCmd::Copy(void)
298 wxLayoutStyleInfo si
;
301 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
302 si
.size
, si
.family
, si
.style
, si
.weight
, si
.underline
,
303 m_ColourFG
, m_ColourBG
);
304 obj
->SetUserData(m_UserData
);
309 wxLayoutObjectCmd::~wxLayoutObjectCmd()
315 wxLayoutObjectCmd::GetStyle(wxLayoutStyleInfo
*si
) const
317 si
->size
= m_font
->GetPointSize();
318 si
->family
= m_font
->GetFamily();
319 si
->style
= m_font
->GetStyle();
320 si
->underline
= m_font
->GetUnderlined();
321 si
->weight
= m_font
->GetWeight();
323 si
->fg_red
= m_ColourFG
.Red();
324 si
->fg_green
= m_ColourFG
.Green();
325 si
->fg_blue
= m_ColourFG
.Blue();
326 si
->bg_red
= m_ColourBG
.Red();
327 si
->bg_green
= m_ColourBG
.Green();
328 si
->bg_blue
= m_ColourBG
.Blue();
332 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
333 wxLayoutList
*wxllist
,
334 CoordType begin
, CoordType
/* len */)
338 dc
.SetTextForeground(m_ColourFG
);
339 dc
.SetTextBackground(m_ColourBG
);
341 wxllist
->SetColour_Internal(&m_ColourFG
,& m_ColourBG
);
345 wxLayoutObjectCmd::Layout(wxDC
&dc
)
347 // this get called, so that recalculation uses right font sizes
348 Draw(dc
, wxPoint(0,0), NULL
);
352 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
354 The wxLayoutLine object
356 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
358 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
361 m_Width
= m_Height
= 0;
366 RecalculatePosition(llist
);
369 m_LineNumber
= m_Previous
->GetLineNumber()+1;
370 m_Next
= m_Previous
->GetNextLine();
371 m_Previous
->m_Next
= this;
372 m_Height
= m_Previous
->GetHeight();
376 m_Next
->m_Previous
= this;
377 m_Next
->MoveLines(+1);
378 m_Next
->RecalculatePositions(1,llist
);
382 wxLayoutLine::~wxLayoutLine()
384 // kbList cleans itself
388 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
391 m_Position
= m_Previous
->GetPosition() +
392 wxPoint(0,m_Previous
->GetHeight());
394 m_Position
= wxPoint(0,0);
395 llist
->SetUpdateRect(m_Position
);
400 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
402 wxASSERT(recurse
>= 0);
403 wxPoint pos
= m_Position
;
404 CoordType height
= m_Height
;
406 // WXLO_TRACE("RecalculatePositions()");
407 RecalculatePosition(llist
);
411 m_Next
->RecalculatePositions(--recurse
, llist
);
412 else if(pos
!= m_Position
|| m_Height
!= height
)
413 m_Next
->RecalculatePositions(0, llist
);
417 wxLayoutObjectList::iterator
418 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
422 wxLayoutObjectList::iterator
425 CoordType x
= 0, len
;
427 /* We search through the objects. As we don't like returning the
428 object that the cursor is behind, we just remember such an
429 object in "found" so we can return it if there is really no
430 further object following it. */
431 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
433 len
= (**i
).GetLength();
434 if( x
<= xpos
&& xpos
<= x
+ len
)
437 if(xpos
== x
+ len
) // is there another object behind?
439 else // we are really inside this object
442 x
+= (**i
).GetLength();
444 return found
; // ==NULL if really none found
447 wxLayoutObjectList::iterator
448 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
449 CoordType xpos
, CoordType
*cxpos
,
454 wxLayoutObjectList::iterator i
;
455 CoordType x
= 0, cx
= 0, width
;
457 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
460 width
= (**i
).GetWidth();
461 if( x
<= xpos
&& xpos
<= x
+ width
)
463 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
464 WXLO_DEBUG(("wxLayoutLine::FindObjectScreen: cursor xpos = %ld", *cxpos
));
465 if(found
) *found
= true;
468 x
+= (**i
).GetWidth();
469 cx
+= (**i
).GetLength();
471 // behind last object:
473 if(found
) *found
= false;
474 return m_ObjectList
.tail();
478 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
481 wxASSERT(obj
!= NULL
);
483 wxLOiterator i
= FindObject(xpos
, &offset
);
486 if(xpos
== 0 ) // aha, empty line!
488 m_ObjectList
.push_back(obj
);
489 m_Length
+= obj
->GetLength();
496 CoordType len
= (**i
).GetLength();
497 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
498 { // insert before this object
499 m_ObjectList
.insert(i
,obj
);
500 m_Length
+= obj
->GetLength();
505 if( i
== m_ObjectList
.tail()) // last object?
506 m_ObjectList
.push_back(obj
);
508 { // insert after current object
510 m_ObjectList
.insert(i
,obj
);
512 m_Length
+= obj
->GetLength();
515 /* Otherwise we need to split the current object.
516 Fortunately this can only be a text object. */
517 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
518 wxString left
, right
;
519 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
520 left
= tobj
->GetText().substr(0,offset
);
521 right
= tobj
->GetText().substr(offset
,len
-offset
);
522 // current text object gets set to right half
523 tobj
->GetText() = right
; // set new text
524 // before it we insert the new object
525 m_ObjectList
.insert(i
,obj
);
526 m_Length
+= obj
->GetLength();
527 // and before that we insert the left half
528 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
533 wxLayoutLine::Insert(CoordType xpos
, wxString text
)
537 wxLOiterator i
= FindObject(xpos
, &offset
);
538 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
540 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
541 tobj
->GetText().insert(offset
, text
);
542 m_Length
+= text
.Length();
547 return Insert(xpos
, new wxLayoutObjectText(text
));
551 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
553 CoordType offset
, len
;
557 wxLOiterator i
= FindObject(xpos
, &offset
);
560 if(i
== NULLIT
) return npos
;
561 // now delete from that object:
562 if((**i
).GetType() != WXLO_TYPE_TEXT
)
564 if(offset
!= 0) // at end of line after a non-text object
567 len
= (**i
).GetLength();
570 m_ObjectList
.erase(i
);
574 // tidy up: remove empty text objects
575 if((**i
).GetLength() == 0)
577 m_ObjectList
.erase(i
);
581 CoordType max
= (**i
).GetLength() - offset
;
582 if(npos
< max
) max
= npos
;
585 if(xpos
== GetLength())
588 { // at the end of an object
589 // move to begin of next object:
591 continue; // start over
596 if(offset
== 0 && max
== (**i
).GetLength())
597 m_ObjectList
.erase(i
); // remove the whole object
599 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
606 wxLayoutLine::DeleteWord(CoordType xpos
)
611 wxLOiterator i
= FindObject(xpos
, &offset
);
615 if(i
== NULLIT
) return false;
616 if((**i
).GetType() != WXLO_TYPE_TEXT
)
618 // This should only happen when at end of line, behind a non-text
620 if(offset
== (**i
).GetLength()) return false;
621 m_Length
-= (**i
).GetLength(); // -1
622 m_ObjectList
.erase(i
);
623 return true; // we are done
627 if(offset
== (**i
).GetLength()) // at end of object
632 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
634 wxString str
= tobj
->GetText();
635 str
= str
.substr(offset
,str
.Length()-offset
);
636 // Find out how many positions we need to delete:
637 // 1. eat leading space
638 while(isspace(str
.c_str()[count
])) count
++;
639 // 2. eat the word itself:
640 while(isalnum(str
.c_str()[count
])) count
++;
642 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
643 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
648 wxASSERT(0); // we should never arrive here
652 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
654 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
655 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
658 m_Next
->MoveLines(-1);
659 m_Next
->RecalculatePositions(1, llist
);
661 wxLayoutLine
*next
= m_Next
;
667 wxLayoutLine::Draw(wxDC
&dc
,
669 const wxPoint
& offset
) const
671 wxLayoutObjectList::iterator i
;
672 wxPoint pos
= offset
;
673 pos
= pos
+ GetPosition();
677 CoordType xpos
= 0; // cursorpos, lenght of line
679 CoordType from
, to
, tempto
;
680 int highlight
= llist
->IsSelected(this, &from
, &to
);
681 if(highlight
== 1) // we need to draw the whole line inverted!
682 llist
->StartHighlighting(dc
);
684 llist
->EndHighlighting(dc
);
686 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
688 if(highlight
== -1) // partially highlight line
690 // parts of the line need highlighting
691 tempto
= xpos
+(**i
).GetLength();
692 if(tempto
>= from
&& xpos
<= to
)
695 if(tempto
> (**i
).GetLength())
696 tempto
= (**i
).GetLength();
697 CoordType tmp
= from
-xpos
;
699 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, tempto
);
703 llist
->EndHighlighting(dc
); // FIXME! inefficient
704 (**i
).Draw(dc
, pos
, llist
);
708 (**i
).Draw(dc
, pos
, llist
);
709 pos
.x
+= (**i
).GetWidth();
710 xpos
+= (**i
).GetLength();
715 wxLayoutLine::Layout(wxDC
&dc
,
721 wxLayoutObjectList::iterator i
;
724 oldHeight
= m_Height
;
726 topHeight
, bottomHeight
; // above and below baseline
729 objTopHeight
, objBottomHeight
;
732 m_Height
= 0; m_BaseLine
= 0;
734 topHeight
= 0; bottomHeight
= 0;
736 bool cursorFound
= false;
740 *cursorPos
= m_Position
;
741 if(cursorSize
) *cursorSize
= wxPoint(0,0);
744 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
747 size
= (**i
).GetSize(&objTopHeight
, &objBottomHeight
);
749 if(cursorPos
&& ! cursorFound
)
750 { // we need to check whether the text cursor is here
751 len
= (**i
).GetLength();
752 if(count
<= cx
&& count
+len
> cx
)
754 if((**i
).GetType() == WXLO_TYPE_TEXT
)
756 len
= cx
- count
; // pos in object
757 CoordType width
, height
, descent
;
758 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
759 &width
, &height
, &descent
);
760 cursorPos
->x
+= width
;
761 cursorPos
->y
= m_Position
.y
;
763 if(len
< (**i
).GetLength())
764 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
766 str
= WXLO_CURSORCHAR
;
767 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
768 wxASSERT(cursorSize
);
769 // Just in case some joker inserted an empty string object:
770 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
771 if(height
== 0) height
= objHeight
;
772 cursorSize
->x
= width
;
773 cursorSize
->y
= height
;
774 cursorFound
= true; // no more checks
777 { // on some other object
778 CoordType top
, bottom
; // unused
779 *cursorSize
= (**i
).GetSize(&top
,&bottom
);
780 cursorPos
->y
= m_Position
.y
;
781 cursorFound
= true; // no more checks
787 cursorPos
->x
+= (**i
).GetWidth();
792 if(objHeight
> m_Height
) m_Height
= objHeight
;
793 if(objTopHeight
> topHeight
) topHeight
= objTopHeight
;
794 if(objBottomHeight
> bottomHeight
) bottomHeight
= objBottomHeight
;
796 if(topHeight
+ bottomHeight
> m_Height
) m_Height
=
797 topHeight
+bottomHeight
;
798 m_BaseLine
= topHeight
;
802 if(GetPreviousLine()) // empty line
804 m_Height
= GetPreviousLine()->GetHeight();
805 m_BaseLine
= GetPreviousLine()->m_BaseLine
;
809 CoordType width
, height
, descent
;
810 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
812 m_BaseLine
= m_Height
- descent
;
817 // tell next line about coordinate change
818 if(m_Next
&& objHeight
!= oldHeight
)
819 m_Next
->RecalculatePositions(0, llist
);
821 // We need to check whether we found a valid cursor size:
824 // this might be the case if the cursor is at the end of the
825 // line or on a command object:
826 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
828 CoordType width
, height
, descent
;
829 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
830 cursorSize
->x
= width
;
831 cursorSize
->y
= height
;
833 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
834 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
840 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
845 { // insert an empty line before this one
846 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
847 if(m_Previous
== NULL
)
848 { // We were in first line, need to link in new empty line
852 m_Previous
->m_Height
= GetHeight(); // this is a wild guess
856 m_Next
->RecalculatePositions(1, llist
);
861 wxLOiterator i
= FindObject(xpos
, &offset
);
863 // must be at the end of the line then
864 return new wxLayoutLine(this, llist
);
867 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
868 // split object at i:
869 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
871 wxString left
, right
;
872 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
873 left
= tobj
->GetText().substr(0,offset
);
874 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
875 // current text object gets set to left half
876 tobj
->GetText() = left
; // set new text
877 newLine
->Append(new wxLayoutObjectText(right
));
878 m_Length
-= right
.Length();
879 i
++; // don't move this object to the new list
883 i
++; // move objects from here to new list
885 while(i
!= m_ObjectList
.end())
888 m_Length
-= (**i
).GetLength();
889 m_ObjectList
.remove(i
); // remove without deleting it
892 m_Next
->RecalculatePositions(2, llist
);
898 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
900 wxASSERT(GetNextLine());
901 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
904 for(i
= list
.begin(); i
!= list
.end();)
907 list
.remove(i
); // remove without deleting it
909 wxASSERT(list
.empty());
910 wxLayoutLine
*oldnext
= GetNextLine();
911 SetNext(GetNextLine()->GetNextLine());
913 RecalculatePositions(1, llist
);
917 wxLayoutLine::GetWrapPosition(CoordType column
)
920 wxLOiterator i
= FindObject(column
, &offset
);
921 if(i
== NULLIT
) return -1; // cannot wrap
923 // go backwards through the list and look for space in text objects
926 if((**i
).GetType() == WXLO_TYPE_TEXT
)
930 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
937 }while(offset
!= -1);
938 i
--; // move on to previous object
942 column
-= (**i
).GetLength();
946 offset
= (**i
).GetLength();
948 /* If we reached the begin of the list and have more than one
949 object, that one is longer than the margin, so break behind
952 i
= m_ObjectList
.begin();
953 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
955 pos
+= (**i
).GetLength();
958 if(i
== NULLIT
) return -1; //why should this happen?
959 pos
+= (**i
).GetLength();
961 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
963 pos
+= (**i
).GetLength();
966 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
967 // now we are at the second text object:
968 pos
-= (**i
).GetLength();
969 return pos
; // in front of it
973 #ifdef WXLAYOUT_DEBUG
975 wxLayoutLine::Debug(void)
978 wxPoint pos
= GetPosition();
979 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld",
980 (long int) GetLineNumber(),
981 (long int) pos
.x
, (long int) pos
.y
,
982 (long int) GetHeight()));
987 wxLayoutLine::Copy(wxLayoutList
*llist
,
991 CoordType firstOffset
, lastOffset
;
993 if(to
== -1) to
= GetLength();
995 wxLOiterator first
= FindObject(from
, &firstOffset
);
996 wxLOiterator last
= FindObject(to
, &lastOffset
);
998 // Common special case: only one object
999 if( *first
== *last
)
1001 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1003 llist
->Insert(new wxLayoutObjectText(
1004 ((wxLayoutObjectText
1005 *)*first
)->GetText().substr(firstOffset
,
1006 lastOffset
-firstOffset
))
1010 else // what can we do?
1012 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1013 llist
->Insert( (**first
).Copy() );
1018 // If we reach here, we can safely copy the whole first object from
1019 // the firstOffset position on:
1020 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1022 llist
->Insert(new wxLayoutObjectText(
1023 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1026 else if(firstOffset
== 0)
1027 llist
->Insert( (**first
).Copy() );
1028 // else nothing to copy :-(
1030 // Now we copy all objects before the last one:
1031 wxLOiterator i
= first
; i
++;
1032 for( ; i
!= last
; i
++)
1033 llist
->Insert( (**i
).Copy() );
1035 // And now the last object:
1038 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1040 llist
->Insert(new wxLayoutObjectText(
1041 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1045 llist
->Insert( (**last
).Copy() );
1049 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1051 The wxLayoutList object
1053 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1055 wxLayoutList::wxLayoutList()
1057 m_DefaultSetting
= NULL
;
1059 m_ColourFG
= *wxBLACK
;
1060 m_ColourBG
= *wxWHITE
;
1061 InvalidateUpdateRect();
1065 wxLayoutList::~wxLayoutList()
1068 m_FirstLine
->DeleteLine(false, this);
1072 wxLayoutList::Empty(void)
1075 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1077 m_CursorPos
= wxPoint(0,0);
1078 m_CursorScreenPos
= wxPoint(0,0);
1079 m_CursorSize
= wxPoint(0,0);
1080 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1081 m_CursorLine
= m_FirstLine
;
1082 InvalidateUpdateRect();
1087 wxLayoutList::InternalClear(void)
1090 if(m_DefaultSetting
)
1092 delete m_DefaultSetting
;
1093 m_DefaultSetting
= NULL
;
1098 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1099 int underline
, wxColour
*fg
,
1102 if(family
!= -1) m_FontFamily
= family
;
1103 if(size
!= -1) m_FontPtSize
= size
;
1104 if(style
!= -1) m_FontStyle
= style
;
1105 if(weight
!= -1) m_FontWeight
= weight
;
1106 if(underline
!= -1) m_FontUnderline
= underline
!= 0;
1108 if(fg
!= NULL
) m_ColourFG
= *fg
;
1109 if(bg
!= NULL
) m_ColourBG
= *bg
;
1112 new wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,m_FontWeight
,m_FontUnderline
,
1113 m_ColourFG
, m_ColourBG
));
1117 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1118 int underline
, char const *fg
, char const *bg
)
1126 cfg
= wxTheColourDatabase
->FindColour(fg
);
1128 cbg
= wxTheColourDatabase
->FindColour(bg
);
1130 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1134 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1135 int /* underline */, wxColour
*fg
, wxColour
*bg
)
1140 m_FontPtSize
= size
;
1141 m_FontUnderline
= false;
1142 m_FontFamily
= family
;
1143 m_FontStyle
= style
;
1144 m_FontWeight
= weight
;
1148 m_ColourFG
= *wxBLACK
;
1152 m_ColourBG
= *wxWHITE
;
1154 if(m_DefaultSetting
)
1155 delete m_DefaultSetting
;
1157 m_DefaultSetting
= new
1158 wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,
1159 m_FontWeight
,m_FontUnderline
,
1160 m_ColourFG
, m_ColourBG
);
1166 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1168 SetUpdateRect(m_CursorScreenPos
);
1169 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1170 wxLayoutLine
*line
= m_FirstLine
;
1171 while(line
&& line
->GetLineNumber() != p
.y
)
1172 line
= line
->GetNextLine();
1173 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1175 m_CursorPos
.y
= p
.y
;
1176 m_CursorLine
= line
;
1177 CoordType len
= line
->GetLength();
1180 m_CursorPos
.x
= p
.x
;
1185 m_CursorPos
.x
= len
;
1193 wxLayoutList::MoveCursorVertically(int n
)
1195 SetUpdateRect(m_CursorScreenPos
);
1196 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1198 if(n
< 0) // move up
1200 if(m_CursorLine
== m_FirstLine
) return false;
1201 while(n
< 0 && m_CursorLine
)
1203 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1209 m_CursorLine
= m_FirstLine
;
1215 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1216 m_CursorPos
.x
= m_CursorLine
->GetLength();
1222 wxLayoutLine
*last
= m_CursorLine
;
1223 if(! m_CursorLine
->GetNextLine()) return false;
1224 while(n
> 0 && m_CursorLine
)
1228 m_CursorLine
= m_CursorLine
->GetNextLine();
1232 m_CursorLine
= last
;
1238 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1239 m_CursorPos
.x
= m_CursorLine
->GetLength();
1247 wxLayoutList::MoveCursorHorizontally(int n
)
1249 SetUpdateRect(m_CursorScreenPos
);
1250 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1254 if(m_CursorPos
.x
== 0) // at begin of line
1256 if(! MoveCursorVertically(-1))
1258 MoveCursorToEndOfLine();
1263 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1264 m_CursorPos
.x
-= move
; n
+= move
;
1269 int len
= m_CursorLine
->GetLength();
1270 if(m_CursorPos
.x
== len
) // at end of line
1272 if(! MoveCursorVertically(1))
1274 MoveCursorToBeginOfLine();
1279 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1280 m_CursorPos
.x
+= move
;
1287 wxLayoutList::Insert(wxString
const &text
)
1289 wxASSERT(m_CursorLine
);
1290 SetUpdateRect(m_CursorScreenPos
);
1291 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1292 m_CursorLine
->Insert(m_CursorPos
.x
, text
);
1293 m_CursorPos
.x
+= text
.Length();
1298 wxLayoutList::Insert(wxLayoutObject
*obj
)
1300 wxASSERT(m_CursorLine
);
1301 SetUpdateRect(m_CursorScreenPos
);
1302 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1303 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1304 m_CursorPos
.x
+= obj
->GetLength();
1309 wxLayoutList::LineBreak(void)
1311 wxASSERT(m_CursorLine
);
1312 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1313 SetUpdateRect(m_CursorScreenPos
);
1314 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1315 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1316 if(setFirst
) // we were at beginning of first line
1317 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1324 wxLayoutList::WrapLine(CoordType column
)
1326 if(m_CursorPos
.x
<= column
|| column
< 1)
1327 return false; // do nothing yet
1330 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1332 return false; // cannot break line
1334 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1335 m_CursorPos
.x
= xpos
;
1336 SetUpdateRect(m_CursorScreenPos
);
1337 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1339 Delete(1); // delete the space
1340 m_CursorPos
.x
= newpos
;
1346 wxLayoutList::Delete(CoordType npos
)
1348 wxASSERT(m_CursorLine
);
1349 SetUpdateRect(m_CursorScreenPos
);
1350 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1354 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1357 // More to delete, continue on next line.
1358 // First, check if line is empty:
1359 if(m_CursorLine
->GetLength() == 0)
1360 { // in this case, updating could probably be optimised
1362 wxASSERT(DeleteLines(1) == 0);
1371 // Need to join next line
1372 if(! m_CursorLine
->GetNextLine())
1376 m_CursorLine
->MergeNextLine(this);
1386 wxLayoutList::DeleteLines(int n
)
1388 wxASSERT(m_CursorLine
);
1390 SetUpdateRect(m_CursorScreenPos
);
1391 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1394 if(!m_CursorLine
->GetNextLine())
1395 { // we cannot delete this line, but we can clear it
1396 MoveCursorToBeginOfLine();
1397 DeleteToEndOfLine();
1401 line
= m_CursorLine
;
1402 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
1404 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
1405 wxASSERT(m_FirstLine
);
1406 wxASSERT(m_CursorLine
);
1408 m_CursorLine
->RecalculatePositions(2, this);
1413 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
1415 wxLayoutLine
*line
= m_FirstLine
;
1417 // first, make sure everything is calculated - this might not be
1418 // needed, optimise it later
1419 m_DefaultSetting
->Layout(dc
);
1422 line
->RecalculatePosition(this); // so we don't need to do it all the time
1423 // little condition to speed up redrawing:
1424 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1425 line
= line
->GetNextLine();
1430 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
)
1432 wxASSERT(m_CursorLine
);
1433 m_CursorLine
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1437 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
1439 UpdateCursorScreenPos(dc
);
1440 return m_CursorScreenPos
;
1444 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
)
1446 wxLayoutLine
*line
= m_FirstLine
;
1448 // first, make sure everything is calculated - this might not be
1449 // needed, optimise it later
1450 m_DefaultSetting
->Layout(dc
);
1453 if(line
== m_CursorLine
)
1454 line
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1456 line
->Layout(dc
, this);
1457 // little condition to speed up redrawing:
1458 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1459 line
= line
->GetNextLine();
1462 ///FIXME: disabled for now
1464 // can only be 0 if we are on the first line and have no next line
1465 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1466 m_CursorLine
->GetNextLine() == NULL
&&
1467 m_CursorLine
== m_FirstLine
));
1469 SetUpdateRect(m_CursorScreenPos
);
1470 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1474 wxLayoutList::Draw(wxDC
&dc
,
1475 wxPoint
const &offset
,
1479 wxLayoutLine
*line
= m_FirstLine
;
1482 m_DefaultSetting
->Draw(dc
, wxPoint(0,0), this);
1483 wxBrush
brush(m_ColourBG
, wxSOLID
);
1488 // only draw if between top and bottom:
1489 if((top
== -1 || line
->GetPosition().y
+ line
->GetHeight() >= top
))
1490 line
->Draw(dc
, this, offset
);
1491 // little condition to speed up redrawing:
1492 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1493 line
= line
->GetNextLine();
1495 // can only be 0 if we are on the first line and have no next line
1496 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1497 m_CursorLine
->GetNextLine() == NULL
&&
1498 m_CursorLine
== m_FirstLine
));
1499 InvalidateUpdateRect();
1501 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
1502 m_Selection
.m_valid
? "valid" : "invalid",
1503 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
1504 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
1508 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
1512 // First, find the right line:
1513 wxLayoutLine
*line
= m_FirstLine
;
1516 // we need to run a layout here to get font sizes right :-(
1517 m_DefaultSetting
->Layout(dc
);
1520 p
= line
->GetPosition();
1521 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
1523 line
->Layout(dc
, this);
1524 line
= line
->GetNextLine();
1528 if(found
) *found
= false;
1529 return NULL
; // not found
1531 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
1532 // Now, find the object in the line:
1533 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
1534 cursorPos
? & cursorPos
->x
: NULL
,
1536 return (i
== NULLIT
) ? NULL
: *i
;
1541 wxLayoutList::GetSize(void) const
1544 *line
= m_FirstLine
,
1547 return wxPoint(0,0);
1549 wxPoint
maxPoint(0,0);
1554 if(line
->GetWidth() > maxPoint
.x
)
1555 maxPoint
.x
= line
->GetWidth();
1557 line
= line
->GetNextLine();
1560 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
1565 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
1568 coords
= m_CursorScreenPos
;
1569 coords
.x
+= translate
.x
;
1570 coords
.y
+= translate
.y
;
1572 #ifdef WXLAYOUT_DEBUG
1573 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
1574 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
1575 (long)coords
.x
, (long)coords
.y
,
1576 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
1577 (long)m_CursorLine
->GetLineNumber(),
1578 (long)m_CursorLine
->GetLength()));
1581 dc
.SetBrush(*wxBLACK_BRUSH
);
1582 dc
.SetLogicalFunction(wxXOR
);
1583 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
1586 dc
.DrawRectangle(coords
.x
, coords
.y
,
1587 m_CursorSize
.x
, m_CursorSize
.y
);
1588 SetUpdateRect(coords
.x
, coords
.y
);
1589 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
1593 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
1594 coords
.x
, coords
.y
);
1595 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
1596 SetUpdateRect(coords
.x
, coords
.y
);
1598 dc
.SetLogicalFunction(wxCOPY
);
1599 //dc.SetBrush(wxNullBrush);
1603 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
1605 if(m_UpdateRectValid
)
1606 GrowRect(m_UpdateRect
, x
, y
);
1611 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
1612 m_UpdateRect
.height
= 4;// wxGTK :-)
1613 m_UpdateRectValid
= true;
1618 wxLayoutList::StartSelection(void)
1620 WXLO_DEBUG(("Starting selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1621 m_Selection
.m_CursorA
= m_CursorPos
;
1622 m_Selection
.m_CursorB
= m_CursorPos
;
1623 m_Selection
.m_selecting
= true;
1624 m_Selection
.m_valid
= false;
1628 wxLayoutList::ContinueSelection(void)
1630 wxASSERT(m_Selection
.m_selecting
== true);
1631 wxASSERT(m_Selection
.m_valid
== false);
1632 WXLO_DEBUG(("Continuing selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1633 m_Selection
.m_CursorB
= m_CursorPos
;
1634 // We always want m_CursorA <= m_CursorB!
1635 if(! (m_Selection
.m_CursorA
<= m_Selection
.m_CursorB
))
1637 wxPoint help
= m_Selection
.m_CursorB
;
1638 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
1639 m_Selection
.m_CursorA
= help
;
1644 wxLayoutList::EndSelection(void)
1646 ContinueSelection();
1647 WXLO_DEBUG(("Ending selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1648 m_Selection
.m_selecting
= false;
1649 m_Selection
.m_valid
= true;
1654 wxLayoutList::IsSelecting(void)
1656 return m_Selection
.m_selecting
;
1660 wxLayoutList::IsSelected(const wxPoint
&cursor
)
1662 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1664 return m_Selection
.m_CursorA
<= cursor
1665 && cursor
<= m_Selection
.m_CursorB
;
1669 /** Tests whether this layout line is selected and needs
1671 @param line to test for
1672 @return 0 = not selected, 1 = fully selected, -1 = partially
1676 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
1679 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
1681 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1684 CoordType y
= line
->GetLineNumber();
1685 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
1687 else if(m_Selection
.m_CursorA
.y
== y
)
1689 *from
= m_Selection
.m_CursorA
.x
;
1690 if(m_Selection
.m_CursorB
.y
== y
)
1691 *to
= m_Selection
.m_CursorB
.x
;
1693 *to
= line
->GetLength();
1696 else if(m_Selection
.m_CursorB
.y
== y
)
1698 *to
= m_Selection
.m_CursorB
.x
;
1699 if(m_Selection
.m_CursorA
.y
== y
)
1700 *from
= m_Selection
.m_CursorA
.x
;
1710 /// Starts highlighting the selection
1712 wxLayoutList::StartHighlighting(wxDC
&dc
)
1715 dc
.SetTextForeground(m_ColourBG
);
1716 dc
.SetTextBackground(m_ColourFG
);
1720 /// Ends highlighting the selection
1722 wxLayoutList::EndHighlighting(wxDC
&dc
)
1725 dc
.SetTextForeground(m_ColourFG
);
1726 dc
.SetTextBackground(m_ColourBG
);
1732 wxLayoutList::Copy(const wxPoint
&from
,
1739 for(firstLine
= m_FirstLine
;
1740 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
1741 firstLine
=firstLine
->GetNextLine())
1743 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
1746 for(lastLine
= m_FirstLine
;
1747 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
1748 lastLine
=lastLine
->GetNextLine())
1750 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
1755 wxLayoutLine
*tmp
= firstLine
;
1756 firstLine
= lastLine
;
1760 wxLayoutList
*llist
= new wxLayoutList();
1762 if(firstLine
== lastLine
)
1764 firstLine
->Copy(llist
, from
.x
, to
.x
);
1768 // Extract objects from first line
1769 firstLine
->Copy(llist
, from
.x
);
1770 // Extract all lines between
1771 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
1773 line
= line
->GetNextLine())
1775 // Extract objects from last line
1776 lastLine
->Copy(llist
, 0, to
.x
);
1782 wxLayoutList::GetSelection(void)
1784 if(! m_Selection
.m_valid
)
1787 return Copy( m_Selection
.m_CursorA
, m_Selection
.m_CursorB
);
1790 #ifdef WXLAYOUT_DEBUG
1793 wxLayoutList::Debug(void)
1798 for(line
= m_FirstLine
;
1800 line
= line
->GetNextLine())
1807 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1811 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1813 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
1814 wxString
const & title
)
1821 wxLayoutPrintout::~wxLayoutPrintout()
1826 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
1828 // The following bit is taken from the printing sample, let's see
1829 // whether it works for us.
1831 /* You might use THIS code to set the printer DC to ROUGHLY reflect
1832 * the screen text size. This page also draws lines of actual length 5cm
1835 // Get the logical pixels per inch of screen and printer
1836 int ppiScreenX
, ppiScreenY
;
1837 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
1838 int ppiPrinterX
, ppiPrinterY
;
1839 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
1841 if(ppiScreenX
== 0) // not yet set, need to guess
1846 if(ppiPrinterX
== 0) // not yet set, need to guess
1852 // This scales the DC so that the printout roughly represents the
1853 // the screen scaling. The text point size _should_ be the right size
1854 // but in fact is too small for some reason. This is a detail that will
1855 // need to be addressed at some point but can be fudged for the
1857 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
1859 // Now we have to check in case our real page size is reduced
1860 // (e.g. because we're drawing to a print preview memory DC)
1861 int pageWidth
, pageHeight
;
1863 dc
->GetSize(&w
, &h
);
1864 GetPageSizePixels(&pageWidth
, &pageHeight
);
1865 if(pageWidth
!= 0) // doesn't work always
1867 // If printer pageWidth == current DC width, then this doesn't
1868 // change. But w might be the preview bitmap width, so scale down.
1869 scale
= scale
* (float)(w
/(float)pageWidth
);
1871 dc
->SetUserScale(scale
, scale
);
1875 bool wxLayoutPrintout::OnPrintPage(int page
)
1884 top
= (page
- 1)*m_PrintoutHeight
;
1885 bottom
= top
+ m_PrintoutHeight
;
1886 // SetDeviceOrigin() doesn't work here, so we need to manually
1887 // translate all coordinates.
1888 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
1889 m_llist
->Draw(*dc
, translate
, top
, bottom
);
1896 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
1898 /* We allocate a temporary wxDC for printing, so that we can
1899 determine the correct paper size and scaling. We don't actually
1900 print anything on it. */
1902 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
1904 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
1907 float scale
= ScaleDC(&psdc
);
1909 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
1910 // This sets a left/top origin of 15% and 20%:
1911 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
1913 // This is the length of the printable area.
1914 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
1915 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
1919 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
1922 *maxPage
= m_NumOfPages
;
1925 *selPageTo
= m_NumOfPages
;
1926 wxRemoveFile(WXLLIST_TEMPFILE
);
1929 bool wxLayoutPrintout::HasPage(int pageNum
)
1931 return pageNum
<= m_NumOfPages
;
1935 Stupid wxWindows doesn't draw proper ellipses, so we comment this
1936 out. It's a waste of paper anyway.
1940 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
1941 wxPoint topleft
, wxPoint bottomright
,
1944 // make backups of all essential parameters
1945 const wxBrush
& brush
= dc
.GetBrush();
1946 const wxPen
& pen
= dc
.GetPen();
1947 const wxFont
& font
= dc
.GetFont();
1949 dc
.SetBrush(*wxWHITE_BRUSH
);
1950 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
1951 dc
.DrawRoundedRectangle(topleft
.x
,
1952 topleft
.y
,bottomright
.x
-topleft
.x
,
1953 bottomright
.y
-topleft
.y
);
1954 dc
.SetBrush(*wxBLACK_BRUSH
);
1955 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
1956 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
1960 page
= "9999/9999 "; // many pages...
1962 dc
.GetTextExtent(page
,&w
,&h
);
1963 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
1964 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
1965 dc
.GetTextExtent("XXXX", &w
,&h
);
1966 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);