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"
19 # include "gui/wxllist.h"
25 # include "iostream.h"
28 # include <wx/print.h>
34 /// This should never really get created
35 #define WXLLIST_TEMPFILE "__wxllist.tmp"
39 # define TypewxString(t) g_aTypewxStrings[t]
40 # define WXLO_DEBUG(x) wxLogDebug x
42 static const char *g_aTypewxStrings
[] =
44 "invalid", "text", "cmd", "icon"
47 wxLayoutObject::Debug(void)
49 WXLO_DEBUG(("%s",g_aTypewxStrings
[GetType()]));
52 # define TypewxString(t) ""
53 # define WXLO_DEBUG(x)
57 /// Cursors smaller than this disappear in XOR drawing mode
58 #define WXLO_MINIMUM_CURSOR_WIDTH 4
60 /// Use this character to estimate a cursor size when none is available.
61 #define WXLO_CURSORCHAR "E"
63 /// Helper function, allows me to compare to wxPoints
64 bool operator ==(wxPoint
const &p1
, wxPoint
const &p2
)
66 return p1
.x
== p2
.x
&& p1
.y
== p2
.y
;
69 /// Helper function, allows me to compare to wxPoints
70 bool operator !=(wxPoint
const &p1
, wxPoint
const &p2
)
72 return p1
.x
!= p2
.x
|| p1
.y
!= p2
.y
;
75 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
79 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
81 wxLayoutObjectText::wxLayoutObjectText(const wxString
&txt
)
92 wxLayoutObjectText::GetSize(CoordType
*top
, CoordType
*bottom
) const
95 *top
= m_Top
; *bottom
= m_Bottom
;
96 return wxPoint(m_Width
, m_Height
);
100 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &coords
)
102 dc
.DrawText(m_Text
, coords
.x
, coords
.y
-m_Top
);
107 wxLayoutObjectText::Layout(wxDC
&dc
)
111 dc
.GetTextExtent(m_Text
,&m_Width
, &m_Height
, &descent
);
113 m_Top
= m_Height
- m_Bottom
;
116 #ifdef WXLAYOUT_DEBUG
118 wxLayoutObjectText::Debug(void)
120 wxLayoutObject::Debug();
121 WXLO_DEBUG((" `%s`", m_Text
.c_str()));
125 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
129 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
131 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
const &icon
)
133 m_Icon
= new wxBitmap(icon
);
136 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
*icon
)
142 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &coords
)
144 dc
.DrawBitmap(*m_Icon
, coords
.x
, coords
.y
-m_Icon
->GetHeight());
148 wxLayoutObjectIcon::Layout(wxDC
& /* dc */)
153 wxLayoutObjectIcon::GetSize(CoordType
*top
, CoordType
*bottom
) const
155 *top
= m_Icon
->GetHeight();
157 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
162 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
166 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
168 wxLayoutObjectCmd::wxLayoutObjectCmd(int size
, int family
, int style
, int
169 weight
, bool underline
,
170 wxColour
const *fg
, wxColour
const *bg
)
173 m_font
= new wxFont(size
,family
,style
,weight
,underline
);
178 wxLayoutObjectCmd::~wxLayoutObjectCmd()
184 wxLayoutObjectCmd::GetStyle(wxLayoutStyleInfo
*si
) const
186 si
->size
= m_font
->GetPointSize();
187 si
->family
= m_font
->GetFamily();
188 si
->style
= m_font
->GetStyle();
189 si
->underline
= m_font
->GetUnderlined();
190 si
->weight
= m_font
->GetWeight();
192 si
->fg_red
= m_ColourFG
->Red();
193 si
->fg_green
= m_ColourFG
->Green();
194 si
->fg_blue
= m_ColourFG
->Blue();
195 si
->bg_red
= m_ColourBG
->Red();
196 si
->bg_green
= m_ColourBG
->Green();
197 si
->bg_blue
= m_ColourBG
->Blue();
201 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */)
205 if(m_ColourFG
) dc
.SetTextForeground(*m_ColourFG
);
206 if(m_ColourBG
) dc
.SetTextBackground(*m_ColourBG
);
210 wxLayoutObjectCmd::Layout(wxDC
&dc
)
212 // this get called, so that recalculation uses right font sizes
213 Draw(dc
, wxPoint(0,0));
217 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
219 The wxLayoutLine object
221 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
223 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
)
231 RecalculatePosition();
234 m_LineNumber
= m_Previous
->GetLineNumber()+1;
235 m_Next
= m_Previous
->GetNextLine();
236 m_Previous
->m_Next
= this;
237 m_Height
= m_Previous
->GetHeight();
241 m_Next
->m_Previous
= this;
242 m_Next
->MoveLines(+1);
243 m_Next
->RecalculatePositions(1);
247 wxLayoutLine::~wxLayoutLine()
249 // kbList cleans itself
253 wxLayoutLine::RecalculatePosition(void)
256 m_Position
= m_Previous
->RecalculatePosition() +
257 wxPoint(0,m_Previous
->GetHeight());
259 m_Position
= wxPoint(0,0);
264 wxLayoutLine::RecalculatePositions(int recurse
)
266 wxPoint pos
= RecalculatePosition();
268 if(pos
!= m_Position
)
271 if(m_Next
) m_Next
->RecalculatePositions(--recurse
);
276 if(recurse
&& m_Next
)
277 m_Next
->RecalculatePositions(--recurse
);
282 wxLayoutObjectList::iterator
283 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
287 wxLayoutObjectList::iterator i
;
288 CoordType x
= 0, len
;
290 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
292 len
= (**i
).GetLength();
293 if( x
<= xpos
&& xpos
<= x
+ len
)
298 x
+= (**i
).GetLength();
304 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
307 wxASSERT(obj
!= NULL
);
309 wxLOiterator i
= FindObject(xpos
, &offset
);
312 if(xpos
== 0 ) // aha, empty line!
314 m_ObjectList
.push_back(obj
);
315 m_Length
+= obj
->GetLength();
322 CoordType len
= (**i
).GetLength();
323 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
324 { // insert before this object
325 m_ObjectList
.insert(i
,obj
);
326 m_Length
+= obj
->GetLength();
331 if( i
== m_ObjectList
.tail()) // last object?
333 m_ObjectList
.push_back(obj
);
334 m_Length
+= obj
->GetLength();
337 { // insert after current object
339 m_ObjectList
.insert(i
,obj
);
340 m_Length
+= obj
->GetLength();
344 /* Otherwise we need to split the current object.
345 Fortunately this can only be a text object. */
346 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
347 wxString left
, right
;
348 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
349 left
= tobj
->GetText().substr(0,offset
);
350 right
= tobj
->GetText().substr(offset
,len
-offset
);
351 // current text object gets set to right half
352 tobj
->GetText() = right
; // set new text
353 // before it we insert the new object
354 m_ObjectList
.insert(i
,obj
);
355 m_Length
+= obj
->GetLength();
356 // and before that we insert the left half
357 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
362 wxLayoutLine::Insert(CoordType xpos
, wxString text
)
366 wxLOiterator i
= FindObject(xpos
, &offset
);
367 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
369 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
370 tobj
->GetText().insert(offset
, text
);
371 m_Length
+= text
.Length();
376 return Insert(xpos
, new wxLayoutObjectText(text
));
380 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
386 wxLOiterator i
= FindObject(xpos
, &offset
);
389 if(i
== NULLIT
) return false; // FIXME
390 // now delete from that object:
391 if((**i
).GetType() != WXLO_TYPE_TEXT
)
393 if(offset
!= 0) // at end of line after a non-text object
396 m_Length
-= (**i
).GetLength();
398 m_ObjectList
.erase(i
);
402 // tidy up: remove empty text objects
403 if((**i
).GetLength() == 0)
405 m_ObjectList
.erase(i
);
409 CoordType max
= (**i
).GetLength() - offset
;
410 if(npos
< max
) max
= npos
;
413 if(xpos
== GetLength())
416 { // at the end of an object
417 // move to begin of next object:
419 continue; // start over
424 if(offset
== 0 && max
== (**i
).GetLength())
425 m_ObjectList
.erase(i
); // remove the whole object
427 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
434 wxLayoutLine::DeleteWord(CoordType xpos
)
439 wxLOiterator i
= FindObject(xpos
, &offset
);
443 if(i
== NULLIT
) return false;
444 if((**i
).GetType() != WXLO_TYPE_TEXT
)
446 // This should only happen when at end of line, behind a non-text
448 if(offset
== (**i
).GetLength()) return false;
449 m_Length
-= (**i
).GetLength(); // -1
450 m_ObjectList
.erase(i
);
451 return true; // we are done
455 if(offset
== (**i
).GetLength()) // at end of object
460 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
462 wxString str
= tobj
->GetText();
463 str
= str
.substr(offset
,str
.Length()-offset
);
464 // Find out how many positions we need to delete:
465 // 1. eat leading space
466 while(isspace(str
[count
])) count
++;
467 // 2. eat the word itself:
468 while(isalnum(str
[count
])) count
++;
470 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
471 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
476 wxASSERT(0); // we should never arrive here
480 wxLayoutLine::DeleteLine(bool update
)
482 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
483 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
486 m_Next
->MoveLines(-1);
487 m_Next
->RecalculatePositions(1);
489 wxLayoutLine
*next
= m_Next
;
495 wxLayoutLine::Draw(wxDC
&dc
, const wxPoint
& offset
) const
497 wxLayoutObjectList::iterator i
;
498 wxPoint pos
= offset
;
499 pos
= pos
+ GetPosition();
503 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
506 pos
.x
+= (**i
).GetWidth();
511 wxLayoutLine::Layout(wxDC
&dc
, wxPoint
*cursorPos
, wxPoint
515 wxLayoutObjectList::iterator i
;
518 oldHeight
= m_Height
;
520 topHeight
, bottomHeight
; // above and below baseline
523 objTopHeight
, objBottomHeight
;
526 m_Height
= 0; m_BaseLine
= 0;
528 topHeight
= 0; bottomHeight
= 0;
530 bool cursorFound
= false;
534 *cursorPos
= m_Position
;
537 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
540 size
= (**i
).GetSize(&objTopHeight
, &objBottomHeight
);
542 if(cursorPos
&& ! cursorFound
)
543 { // we need to check whether the text cursor is here
544 len
= (**i
).GetLength();
545 if(count
<= cx
&& count
+len
> cx
)
547 if((**i
).GetType() == WXLO_TYPE_TEXT
)
549 len
= cx
- count
; // pos in object
550 CoordType width
, height
, descent
;
551 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
552 &width
, &height
, &descent
);
553 cursorPos
->x
+= width
;
554 cursorPos
->y
= m_Position
.y
;
556 if(len
< (**i
).GetLength())
557 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
559 str
= WXLO_CURSORCHAR
;
560 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
561 wxASSERT(cursorSize
);
562 // Just in case some joker inserted an empty string object:
563 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
564 if(height
== 0) height
= objHeight
;
565 cursorSize
->x
= width
;
566 cursorSize
->y
= height
;
567 cursorFound
= true; // no more checks
570 { // on some other object
571 CoordType top
, bottom
; // unused
572 *cursorSize
= (**i
).GetSize(&top
,&bottom
);
573 cursorPos
->y
= m_Position
.y
;
574 cursorFound
= true; // no more checks
580 cursorPos
->x
+= (**i
).GetWidth();
585 if(objHeight
> m_Height
) m_Height
= objHeight
;
586 if(objTopHeight
> topHeight
) topHeight
= objTopHeight
;
587 if(objBottomHeight
> bottomHeight
) bottomHeight
= objBottomHeight
;
589 if(topHeight
+ bottomHeight
> m_Height
) m_Height
=
590 topHeight
+bottomHeight
;
591 m_BaseLine
= topHeight
;
595 if(GetPreviousLine()) // empty line
597 m_Height
= GetPreviousLine()->GetHeight();
598 m_BaseLine
= GetPreviousLine()->m_BaseLine
;
602 CoordType width
, height
, descent
;
603 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
605 m_BaseLine
= m_Height
- descent
;
610 // tell next line about coordinate change
611 if(m_Next
&& objHeight
!= oldHeight
)
612 m_Next
->RecalculatePositions();
616 // this might be the case if the cursor is at the end of the
617 // line or on a command object:
618 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
622 cursorSize
->y
= m_BaseLine
;
623 if(cursorSize
->x
< WXLO_MINIMUM_CURSOR_WIDTH
) cursorSize
->x
= WXLO_MINIMUM_CURSOR_WIDTH
;
627 CoordType width
, height
, descent
;
628 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
629 cursorSize
->x
= width
;
630 cursorSize
->y
= height
;
633 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
634 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
639 wxLayoutLine::FindObject(CoordType xpos
)
642 if(xpos
> GetWidth()) return NULL
;
645 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
647 x
+= (**i
).GetWidth();
648 if(x
> xpos
) // we just crossed it
655 wxLayoutLine::Break(CoordType xpos
)
660 { // insert an empty line before this one
661 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
);
662 if(m_Previous
== NULL
)
663 { // We were in first line, need to link in new empty line
667 m_Previous
->m_Height
= GetHeight(); // this is a wild guess
671 m_Next
->RecalculatePositions(1);
676 wxLOiterator i
= FindObject(xpos
, &offset
);
678 // must be at the end of the line then
679 return new wxLayoutLine(this);
682 wxLayoutLine
*newLine
= new wxLayoutLine(this);
683 // split object at i:
684 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
686 wxString left
, right
;
687 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
688 left
= tobj
->GetText().substr(0,offset
);
689 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
690 // current text object gets set to left half
691 tobj
->GetText() = left
; // set new text
692 newLine
->Append(new wxLayoutObjectText(right
));
693 m_Length
-= m_Length
- offset
;
694 i
++; // don't move this object to the new list
698 i
++; // move objects from here to new list
700 while(i
!= m_ObjectList
.end())
703 m_Length
-= (**i
).GetLength();
704 m_ObjectList
.remove(i
); // remove without deleting it
707 m_Next
->RecalculatePositions(2);
713 wxLayoutLine::MergeNextLine(void)
715 wxASSERT(GetNextLine());
716 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
719 for(i
= list
.begin(); i
!= list
.end();)
722 list
.remove(i
); // remove without deleting it
724 wxASSERT(list
.empty());
725 wxLayoutLine
*oldnext
= GetNextLine();
726 SetNext(GetNextLine()->GetNextLine());
728 RecalculatePositions(1);
733 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
735 The wxLayoutList object
737 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
739 wxLayoutList::wxLayoutList()
741 m_DefaultSetting
= NULL
;
746 wxLayoutList::~wxLayoutList()
752 wxLayoutList::InternalClear(void)
755 m_FirstLine
= m_FirstLine
->DeleteLine(false);
759 delete m_DefaultSetting
;
760 m_DefaultSetting
= NULL
;
763 m_CursorPos
= wxPoint(0,0);
764 m_CursorScreenPos
= wxPoint(0,0);
765 m_CursorSize
= wxPoint(0,0);
766 m_FirstLine
= new wxLayoutLine(NULL
); // empty first line
767 m_CursorLine
= m_FirstLine
;
771 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
772 int underline
, wxColour
const *fg
,
775 if(family
!= -1) m_FontFamily
= family
;
776 if(size
!= -1) m_FontPtSize
= size
;
777 if(style
!= -1) m_FontStyle
= style
;
778 if(weight
!= -1) m_FontWeight
= weight
;
779 if(underline
!= -1) m_FontUnderline
= underline
!= 0;
781 if(fg
!= NULL
) m_ColourFG
= fg
;
782 if(bg
!= NULL
) m_ColourBG
= bg
;
785 new wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,m_FontWeight
,m_FontUnderline
,
786 m_ColourFG
, m_ColourBG
));
790 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
791 int underline
, char const *fg
, char const *bg
)
799 cfg
= wxTheColourDatabase
->FindColour(fg
);
801 cbg
= wxTheColourDatabase
->FindColour(bg
);
803 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
807 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
808 int /* underline */, char const *fg
, char const *bg
)
814 m_FontUnderline
= false;
815 m_FontFamily
= family
;
817 m_FontWeight
= weight
;
818 m_ColourFG
= wxTheColourDatabase
->FindColour(fg
);
819 m_ColourBG
= wxTheColourDatabase
->FindColour(bg
);
821 if(! m_ColourFG
) m_ColourFG
= wxBLACK
;
822 if(! m_ColourBG
) m_ColourBG
= wxWHITE
;
825 delete m_DefaultSetting
;
827 m_DefaultSetting
= new
828 wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,
829 m_FontWeight
,m_FontUnderline
,
830 m_ColourFG
, m_ColourBG
);
836 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
838 wxLayoutLine
*line
= m_FirstLine
;
839 while(line
&& line
->GetLineNumber() != p
.y
)
841 if(line
&& line
->GetLineNumber() == p
.y
) // found it
845 CoordType len
= line
->GetLength();
861 wxLayoutList::MoveCursorVertically(int n
)
865 if(m_CursorLine
== m_FirstLine
) return false;
866 while(n
< 0 && m_CursorLine
)
868 m_CursorLine
= m_CursorLine
->GetPreviousLine();
874 m_CursorLine
= m_FirstLine
;
880 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
881 m_CursorPos
.x
= m_CursorLine
->GetLength();
887 wxLayoutLine
*last
= m_CursorLine
;
888 if(! m_CursorLine
->GetNextLine()) return false;
889 while(n
> 0 && m_CursorLine
)
893 m_CursorLine
= m_CursorLine
->GetNextLine();
903 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
904 m_CursorPos
.x
= m_CursorLine
->GetLength();
911 wxLayoutList::MoveCursorHorizontally(int n
)
916 if(m_CursorPos
.x
== 0) // at begin of line
918 if(! MoveCursorVertically(-1))
920 MoveCursorToEndOfLine();
925 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
926 m_CursorPos
.x
-= move
; n
+= move
;
931 int len
= m_CursorLine
->GetLength();
932 if(m_CursorPos
.x
== len
) // at end of line
934 if(! MoveCursorVertically(1))
936 MoveCursorToBeginOfLine();
941 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
942 m_CursorPos
.x
+= move
;
949 wxLayoutList::Insert(wxString
const &text
)
951 wxASSERT(m_CursorLine
);
952 m_CursorLine
->Insert(m_CursorPos
.x
, text
);
953 m_CursorPos
.x
+= text
.Length();
958 wxLayoutList::Insert(wxLayoutObject
*obj
)
960 wxASSERT(m_CursorLine
);
961 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
962 m_CursorPos
.x
+= obj
->GetLength();
967 wxLayoutList::LineBreak(void)
969 wxASSERT(m_CursorLine
);
971 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
972 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
);
973 if(setFirst
) // we were at beginning of first line
974 m_FirstLine
= m_CursorLine
->GetPreviousLine();
981 wxLayoutList::Delete(CoordType npos
)
983 wxASSERT(m_CursorLine
);
987 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
990 // More to delete, continue on next line.
991 // First, check if line is empty:
992 if(m_CursorLine
->GetLength() == 0)
993 { // in this case, updating could probably be optimised
994 m_CursorLine
= m_CursorLine
->DeleteLine(true);
999 // Need to join next line
1000 if(! m_CursorLine
->GetNextLine())
1004 m_CursorLine
->MergeNextLine();
1014 wxLayoutList::DeleteLines(int n
)
1016 wxASSERT(m_CursorLine
);
1020 if(!m_CursorLine
->GetNextLine())
1021 { // we cannot delete this line, but we can clear it
1022 MoveCursorToBeginOfLine();
1023 DeleteToEndOfLine();
1027 line
= m_CursorLine
;
1028 m_CursorLine
= m_CursorLine
->DeleteLine(true);
1030 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
1031 wxASSERT(m_FirstLine
);
1032 wxASSERT(m_CursorLine
);
1034 m_CursorLine
->RecalculatePositions(2);
1039 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
) const
1041 wxLayoutLine
*line
= m_FirstLine
;
1043 // first, make sure everything is calculated - this might not be
1044 // needed, optimise it later
1045 m_DefaultSetting
->Layout(dc
);
1048 if(line
== m_CursorLine
)
1049 line
->Layout(dc
, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1052 // little condition to speed up redrawing:
1053 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1054 line
= line
->GetNextLine();
1056 // can only be 0 if we are on the first line and have no next line
1057 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1058 m_CursorLine
->GetNextLine() == NULL
&&
1059 m_CursorLine
== m_FirstLine
));
1063 wxLayoutList::Draw(wxDC
&dc
, wxPoint
const &offset
,
1064 CoordType top
, CoordType bottom
) const
1066 wxLayoutLine
*line
= m_FirstLine
;
1069 m_DefaultSetting
->Draw(dc
, wxPoint(0,0));
1072 // only draw if between top and bottom:
1073 if((top
== -1 || line
->GetPosition().y
>= top
))
1074 line
->Draw(dc
, offset
);
1075 // little condition to speed up redrawing:
1076 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1077 line
= line
->GetNextLine();
1079 // can only be 0 if we are on the first line and have no next line
1080 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1081 m_CursorLine
->GetNextLine() == NULL
&&
1082 m_CursorLine
== m_FirstLine
));
1086 wxLayoutList::FindObject(wxPoint
const pos
)
1088 // First, find the right line:
1089 wxLayoutLine
*line
= m_FirstLine
;
1094 p
= line
->GetPosition();
1095 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
1097 line
= line
->GetNextLine();
1099 if(! line
) return NULL
; // not found
1100 // Now, find the object in the line:
1101 return line
->FindObject(pos
.x
);
1106 wxLayoutList::GetSize(void) const
1109 *line
= m_FirstLine
,
1112 return wxPoint(0,0);
1119 if(line
->GetWidth() > max
.x
) max
.x
= line
->GetWidth();
1121 line
= line
->GetNextLine();
1124 max
.y
= last
->GetPosition().y
+ last
->GetHeight();
1129 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
1132 coords
= m_CursorScreenPos
;
1133 coords
.x
+= translate
.x
;
1134 coords
.y
+= translate
.y
;
1136 #ifdef WXLAYOUT_DEBUG
1137 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
1138 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
1139 (long)coords
.x
, (long)coords
.y
,
1140 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
1141 (long)m_CursorLine
->GetLineNumber(),
1142 (long)m_CursorLine
->GetLength()));
1146 dc
.SetBrush(*wxBLACK_BRUSH
);
1147 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
1148 dc
.SetLogicalFunction(wxXOR
);
1149 dc
.DrawRectangle(coords
.x
, coords
.y
, m_CursorSize
.x
, m_CursorSize
.y
);
1150 dc
.SetLogicalFunction(wxCOPY
);
1151 dc
.SetBrush(wxNullBrush
);
1156 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1160 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1162 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
1163 wxString
const & title
)
1171 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
1173 // The following bit is taken from the printing sample, let's see
1174 // whether it works for us.
1176 /* You might use THIS code to set the printer DC to ROUGHLY reflect
1177 * the screen text size. This page also draws lines of actual length 5cm
1180 // Get the logical pixels per inch of screen and printer
1181 int ppiScreenX
, ppiScreenY
;
1182 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
1183 int ppiPrinterX
, ppiPrinterY
;
1184 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
1186 if(ppiScreenX
== 0) // not yet set, need to guess
1191 if(ppiPrinterX
== 0) // not yet set, need to guess
1197 // This scales the DC so that the printout roughly represents the
1198 // the screen scaling. The text point size _should_ be the right size
1199 // but in fact is too small for some reason. This is a detail that will
1200 // need to be addressed at some point but can be fudged for the
1202 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
1204 // Now we have to check in case our real page size is reduced
1205 // (e.g. because we're drawing to a print preview memory DC)
1206 int pageWidth
, pageHeight
;
1208 dc
->GetSize(&w
, &h
);
1209 GetPageSizePixels(&pageWidth
, &pageHeight
);
1210 if(pageWidth
!= 0) // doesn't work always
1212 // If printer pageWidth == current DC width, then this doesn't
1213 // change. But w might be the preview bitmap width, so scale down.
1214 scale
= scale
* (float)(w
/(float)pageWidth
);
1216 dc
->SetUserScale(scale
, scale
);
1220 bool wxLayoutPrintout::OnPrintPage(int page
)
1229 top
= (page
- 1)*m_PrintoutHeight
;
1230 bottom
= top
+ m_PrintoutHeight
;
1231 // SetDeviceOrigin() doesn't work here, so we need to manually
1232 // translate all coordinates.
1233 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
1234 m_llist
->Draw(*dc
, translate
, top
, bottom
);
1241 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
1243 /* We allocate a temporary wxDC for printing, so that we can
1244 determine the correct paper size and scaling. We don't actually
1245 print anything on it. */
1247 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
1249 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
1252 float scale
= ScaleDC(&psdc
);
1254 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
1255 // This sets a left/top origin of 10% and 20%:
1256 m_Offset
= wxPoint(m_PageWidth
/10, m_PageHeight
/20);
1258 // This is the length of the printable area.
1259 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.1);
1260 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
1263 m_NumOfPages
= (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
) + 0.5);
1265 // This is a crude hack to get it right for very small
1266 // printouts. No idea why this is required, I thought +0.5 would do
1268 if(m_NumOfPages
== 0 && m_llist
->GetSize().y
> 0)
1271 *maxPage
= m_NumOfPages
;
1274 *selPageTo
= m_NumOfPages
;
1275 wxRemoveFile(WXLLIST_TEMPFILE
);
1278 bool wxLayoutPrintout::HasPage(int pageNum
)
1280 return pageNum
<= m_NumOfPages
;
1284 Stupid wxWindows doesn't draw proper ellipses, so we comment this
1285 out. It's a waste of paper anyway.
1289 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
1290 wxPoint topleft
, wxPoint bottomright
,
1293 // make backups of all essential parameters
1294 const wxBrush
& brush
= dc
.GetBrush();
1295 const wxPen
& pen
= dc
.GetPen();
1296 const wxFont
& font
= dc
.GetFont();
1298 dc
.SetBrush(*wxWHITE_BRUSH
);
1299 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
1300 dc
.DrawRoundedRectangle(topleft
.x
,
1301 topleft
.y
,bottomright
.x
-topleft
.x
,
1302 bottomright
.y
-topleft
.y
);
1303 dc
.SetBrush(*wxBLACK_BRUSH
);
1304 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
1305 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
1309 page
= "9999/9999 "; // many pages...
1311 dc
.GetTextExtent(page
,&w
,&h
);
1312 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
1313 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
1314 dc
.GetTextExtent("XXXX", &w
,&h
);
1315 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);