1 /*-*- c++ -*-********************************************************
2 * wxllist: wxLayoutList, a layout engine for text and graphics *
4 * (C) 1998-1999 by Karsten Ballüder (Ballueder@usa.net) *
7 *******************************************************************/
13 Layout() recalculates the objects, sizes, etc.
14 Draw() just draws them with the current settings, without
15 re-layout()ing them again
17 Each line has its own wxLayoutStyleInfo structure which gets updated
18 from within Layout(). Thanks to this, we don't need to re-layout all
19 lines if we want to draw one, but can just use its styleinfo to set
25 # pragma implementation "wxllist.h"
28 #include <wx/wxprec.h>
37 # include "gui/wxllist.h"
38 # include "gui/wxlparser.h"
39 # define SHOW_SELECTIONS 1
42 # include "wxlparser.h"
43 # define SHOW_SELECTIONS 1
47 # include <iostream.h>
51 # include <wx/print.h>
53 # include <wx/filefn.h>
56 #ifdef WXLAYOUT_USE_CARET
57 # include <wx/caret.h>
58 #endif // WXLAYOUT_USE_CARET
62 /// This should never really get created
63 #define WXLLIST_TEMPFILE "__wxllist.tmp"
67 # define TypeString(t) g_aTypeStrings[t]
68 # define WXLO_DEBUG(x) wxLogDebug x
70 static const char *g_aTypeStrings
[] =
72 "invalid", "text", "cmd", "icon"
75 wxLayoutObject::Debug(void)
77 WXLO_DEBUG(("%s",g_aTypeStrings
[GetType()]));
80 # define TypeString(t) ""
81 # define WXLO_DEBUG(x)
84 // FIXME under MSW, this constant is needed to make the thing properly redraw
85 // itself - I don't know where the size calculation error is and I can't
86 // waste time looking for it right now. Search for occurences of
87 // MSW_CORRECTION to find all the places where I did it.
89 static const int MSW_CORRECTION
= 10;
91 static const int MSW_CORRECTION
= 0;
94 /// Cursors smaller than this disappear in XOR drawing mode
95 #define WXLO_MINIMUM_CURSOR_WIDTH 4
97 /// Use this character to estimate a cursor size when none is available.
98 #define WXLO_CURSORCHAR "E"
99 /** @name Helper functions */
101 /// allows me to compare to wxPoints
102 bool operator <=(wxPoint
const &p1
, wxPoint
const &p2
)
104 return p1
.y
< p2
.y
|| (p1
.y
== p2
.y
&& p1
.x
<= p2
.x
);
108 The following STAY HERE until we have a working wxGTK again!!!
110 #ifndef wxWANTS_CHARS
111 /// allows me to compare to wxPoints
112 bool operator ==(wxPoint
const &p1
, wxPoint
const &p2
)
114 return p1
.x
== p2
.x
&& p1
.y
== p2
.y
;
117 /// allows me to compare to wxPoints
118 bool operator !=(wxPoint
const &p1
, wxPoint
const &p2
)
120 return p1
.x
!= p2
.x
|| p1
.y
!= p2
.y
;
123 wxPoint
& operator += (wxPoint
&p1
, wxPoint
const &p2
)
131 /// allows me to compare to wxPoints
132 bool operator>(wxPoint
const &p1
, wxPoint
const &p2
)
137 /// grows a wxRect so that it includes the given point
140 void GrowRect(wxRect
&r
, CoordType x
, CoordType y
)
144 else if(r
.x
+ r
.width
< x
)
149 else if(r
.y
+ r
.height
< y
)
155 /// returns true if the point is in the rectangle
157 bool Contains(const wxRect
&r
, const wxPoint
&p
)
159 return r
.x
<= p
.x
&& r
.y
<= p
.y
&& (r
.x
+r
.width
) >= p
.x
&& (r
.y
+ r
.height
) >= p
.y
;
167 void ReadString(wxString
&to
, wxString
&from
)
170 const char *cptr
= from
.c_str();
171 while(*cptr
&& *cptr
!= '\n')
177 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
181 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
185 wxLayoutObject::Read(wxString
&istr
)
188 ReadString(tmp
, istr
);
190 sscanf(tmp
.c_str(),"%d", &type
);
195 return wxLayoutObjectText::Read(istr
);
197 return wxLayoutObjectCmd::Read(istr
);
199 return wxLayoutObjectIcon::Read(istr
);
205 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
209 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
211 wxLayoutObjectText::wxLayoutObjectText(const wxString
&txt
)
221 wxLayoutObjectText::Copy(void)
223 wxLayoutObjectText
*obj
= new wxLayoutObjectText(m_Text
);
224 obj
->m_Width
= m_Width
;
225 obj
->m_Height
= m_Height
;
227 obj
->m_Bottom
= m_Bottom
;
228 obj
->SetUserData(m_UserData
);
234 wxLayoutObjectText::Write(wxString
&ostr
)
236 ostr
<< (int) WXLO_TYPE_TEXT
<< '\n'
241 wxLayoutObjectText::Read(wxString
&istr
)
244 ReadString(text
, istr
);
246 return new wxLayoutObjectText(text
);
250 wxLayoutObjectText::GetSize(CoordType
*top
, CoordType
*bottom
) const
253 *top
= m_Top
; *bottom
= m_Bottom
;
254 return wxPoint(m_Width
, m_Height
);
258 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &coords
,
259 wxLayoutList
*wxllist
,
260 CoordType begin
, CoordType end
)
264 // draw the whole object normally
265 dc
.DrawText(m_Text
, coords
.x
, coords
.y
-m_Top
);
269 // highlight the bit between begin and len
272 ypos
= coords
.y
-m_Top
;
273 long width
, height
, descent
;
275 if(begin
< 0) begin
= 0;
276 if( end
> (signed)m_Text
.Length() )
277 end
= m_Text
.Length();
279 wxString str
= m_Text
.Mid(0, begin
);
280 dc
.DrawText(str
, xpos
, ypos
);
281 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
283 wxllist
->StartHighlighting(dc
);
284 str
= m_Text
.Mid(begin
, end
-begin
);
285 dc
.DrawText(str
, xpos
, ypos
);
286 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
288 wxllist
->EndHighlighting(dc
);
289 str
= m_Text
.Mid(end
, m_Text
.Length()-end
);
290 dc
.DrawText(str
, xpos
, ypos
);
295 wxLayoutObjectText::GetOffsetScreen(wxDC
&dc
, CoordType xpos
) const
299 maxlen
= m_Text
.Length();
302 height
, descent
= 0l;
304 if(xpos
== 0) return 0; // easy
306 while(width
< xpos
&& offs
< maxlen
)
308 dc
.GetTextExtent(m_Text
.substr(0,offs
),
309 &width
, &height
, &descent
);
312 /* We have to substract 1 to compensate for the offs++, and another
313 one because we don't want to position the cursor behind the
314 object what we clicked on, but before - otherwise it looks
316 return (xpos
> 2) ? offs
-2 : 0;
320 wxLayoutObjectText::Layout(wxDC
&dc
, class wxLayoutList
*llist
)
324 // now this is done in wxLayoutLine::Layout(), but this code might be
325 // reenabled later - in principle, it's more efficient
327 CoordType widthOld
= m_Width
,
328 heightOld
= m_Height
;
331 dc
.GetTextExtent(m_Text
, &m_Width
, &m_Height
, &descent
);
334 if ( widthOld
!= m_Width
|| heightOld
!= m_Height
)
336 // as the text length changed, it must be refreshed
337 wxLayoutLine
*line
= GetLine();
339 wxCHECK_RET( line
, "wxLayoutObjectText can't refresh itself" );
341 // as our size changed, we need to repaint the part which was appended
342 wxPoint
position(line
->GetPosition());
344 // this is not the most efficient way (we repaint the whole line), but
345 // it's not too slow and is *simple*
346 if ( widthOld
< m_Width
)
348 if ( heightOld
< m_Height
)
349 heightOld
= m_Height
;
351 llist
->SetUpdateRect(position
.x
+ widthOld
+ MSW_CORRECTION
,
352 position
.y
+ heightOld
+ MSW_CORRECTION
);
357 m_Top
= m_Height
- m_Bottom
;
361 #ifdef WXLAYOUT_DEBUG
363 wxLayoutObjectText::Debug(void)
365 wxLayoutObject::Debug();
366 WXLO_DEBUG((" `%s`", m_Text
.c_str()));
370 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
374 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
376 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
const &icon
)
378 m_Icon
= new wxBitmap(icon
);
383 wxLayoutObjectIcon::Write(wxString
&ostr
)
385 /* Exports icon through a temporary file. */
387 wxString file
= wxGetTempFileName("wxloexport");
389 ostr
<< WXLO_TYPE_ICON
<< '\n'
391 m_Icon
->SaveFile(file
, WXLO_BITMAP_FORMAT
);
395 wxLayoutObjectIcon::Read(wxString
&istr
)
398 ReadString(file
, istr
);
400 if(! wxFileExists(file
))
402 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon
;
404 if(!obj
->m_Icon
->LoadFile(file
, WXLO_BITMAP_FORMAT
))
414 wxLayoutObjectIcon::Copy(void)
416 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon(new
418 obj
->SetUserData(m_UserData
);
422 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
*icon
)
428 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &coords
,
429 wxLayoutList
*wxllist
,
430 CoordType begin
, CoordType
/* len */)
432 dc
.DrawBitmap(*m_Icon
, coords
.x
, coords
.y
-m_Icon
->GetHeight(),
433 (m_Icon
->GetMask() == NULL
) ? FALSE
: TRUE
);
437 wxLayoutObjectIcon::Layout(wxDC
& /* dc */, class wxLayoutList
* )
442 wxLayoutObjectIcon::GetSize(CoordType
*top
, CoordType
*bottom
) const
444 *top
= m_Icon
->GetHeight();
446 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
451 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
455 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
458 wxLayoutStyleInfo::wxLayoutStyleInfo(int ifamily
,
466 family
= ifamily
; size
= isize
;
467 style
= istyle
; weight
= iweight
;
468 underline
= iul
!= 0;
485 #define COPY_SI_(what) if(right.what != -1) what = right.what;
488 wxLayoutStyleInfo::operator=(const wxLayoutStyleInfo
&right
)
495 if(right
.m_fg_valid
) m_fg
= right
.m_fg
;
496 if(right
.m_bg_valid
) m_bg
= right
.m_bg
;
500 wxLayoutObjectCmd::wxLayoutObjectCmd(int family
, int size
, int style
, int
501 weight
, int underline
,
502 wxColour
*fg
, wxColour
*bg
)
505 m_StyleInfo
= new wxLayoutStyleInfo(family
, size
,style
,weight
,underline
,fg
,bg
);
509 wxLayoutObjectCmd::Copy(void)
511 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
516 m_StyleInfo
->underline
,
517 m_StyleInfo
->m_fg_valid
?
518 &m_StyleInfo
->m_fg
: NULL
,
519 m_StyleInfo
->m_bg_valid
?
520 &m_StyleInfo
->m_bg
: NULL
);
521 obj
->SetUserData(m_UserData
);
526 wxLayoutObjectCmd::Write(wxString
&ostr
)
528 ostr
<< WXLO_TYPE_CMD
<< '\n'
529 << m_StyleInfo
->size
<< '\n'
530 << m_StyleInfo
->family
<< '\n'
531 << m_StyleInfo
->style
<< '\n'
532 << m_StyleInfo
->weight
<< '\n'
533 << m_StyleInfo
->underline
<< '\n'
534 << m_StyleInfo
->m_fg_valid
<< '\n'
535 << m_StyleInfo
->m_bg_valid
<< '\n';
536 if(m_StyleInfo
->m_fg_valid
)
538 ostr
<< m_StyleInfo
->m_fg
.Red() << '\n'
539 << m_StyleInfo
->m_fg
.Green() << '\n'
540 << m_StyleInfo
->m_fg
.Blue() << '\n';
542 if(m_StyleInfo
->m_bg_valid
)
544 ostr
<< m_StyleInfo
->m_bg
.Red() << '\n'
545 << m_StyleInfo
->m_bg
.Green() << '\n'
546 << m_StyleInfo
->m_bg
.Blue() << '\n';
551 wxLayoutObjectCmd::Read(wxString
&istr
)
553 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd
;
556 ReadString(tmp
, istr
);
557 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->size
);
558 ReadString(tmp
, istr
);
559 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->family
);
560 ReadString(tmp
, istr
);
561 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->style
);
562 ReadString(tmp
, istr
);
563 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->weight
);
564 ReadString(tmp
, istr
);
565 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->underline
);
566 ReadString(tmp
, istr
);
567 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_fg_valid
);
568 ReadString(tmp
, istr
);
569 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_bg_valid
);
570 if(obj
->m_StyleInfo
->m_fg_valid
)
572 int red
, green
, blue
;
573 ReadString(tmp
, istr
);
574 sscanf(tmp
.c_str(),"%d", &red
);
575 ReadString(tmp
, istr
);
576 sscanf(tmp
.c_str(),"%d", &green
);
577 ReadString(tmp
, istr
);
578 sscanf(tmp
.c_str(),"%d", &blue
);
579 obj
->m_StyleInfo
->m_fg
= wxColour(red
, green
, blue
);
581 if(obj
->m_StyleInfo
->m_bg_valid
)
583 int red
, green
, blue
;
584 ReadString(tmp
, istr
);
585 sscanf(tmp
.c_str(),"%d", &red
);
586 ReadString(tmp
, istr
);
587 sscanf(tmp
.c_str(),"%d", &green
);
588 ReadString(tmp
, istr
);
589 sscanf(tmp
.c_str(),"%d", &blue
);
590 obj
->m_StyleInfo
->m_bg
= wxColour(red
, green
, blue
);
596 wxLayoutObjectCmd::~wxLayoutObjectCmd()
602 wxLayoutObjectCmd::GetStyle(void) const
608 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
609 wxLayoutList
*wxllist
,
610 CoordType begin
, CoordType
/* len */)
612 wxASSERT(m_StyleInfo
);
613 wxllist
->ApplyStyle(*m_StyleInfo
, dc
);
617 wxLayoutObjectCmd::Layout(wxDC
&dc
, class wxLayoutList
* llist
)
619 // this get called, so that recalculation uses right font sizes
620 Draw(dc
, wxPoint(0,0), llist
);
624 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
626 The wxLayoutLine object
628 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
630 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
633 m_Width
= m_Height
= 0;
638 RecalculatePosition(llist
);
641 m_LineNumber
= m_Previous
->GetLineNumber()+1;
642 m_Next
= m_Previous
->GetNextLine();
643 m_Previous
->m_Next
= this;
647 m_Next
->m_Previous
= this;
648 m_Next
->MoveLines(+1);
649 m_Next
->RecalculatePositions(1,llist
);
653 wxLayoutLine::~wxLayoutLine()
655 // kbList cleans itself
659 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
661 wxASSERT(m_Previous
|| GetLineNumber() == 0);
663 wxPoint
posOld(m_Position
);
667 m_Position
= m_Previous
->GetPosition();
668 m_Position
.y
+= m_Previous
->GetHeight();
671 m_Position
= wxPoint(0,0);
673 if ( m_Position
!= posOld
)
675 // the whole line moved and must be repainted
676 llist
->SetUpdateRect(m_Position
);
677 llist
->SetUpdateRect(m_Position
.x
+ GetWidth() + MSW_CORRECTION
,
678 m_Position
.y
+ GetHeight() + MSW_CORRECTION
);
679 llist
->SetUpdateRect(posOld
);
680 llist
->SetUpdateRect(posOld
.x
+ GetWidth() + MSW_CORRECTION
,
681 posOld
.y
+ GetHeight() + MSW_CORRECTION
);
688 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
690 //FIXME: is this really needed? We run Layout() anyway.
691 // Recursing here, drives computation time up exponentially, as
692 // each line will cause all following lines to be recalculated.
693 // Yes, or linenumbers go wrong.
695 wxASSERT(recurse
>= 0);
696 wxPoint pos
= m_Position
;
697 CoordType height
= m_Height
;
699 // WXLO_TRACE("RecalculatePositions()");
700 RecalculatePosition(llist
);
704 m_Next
->RecalculatePositions(--recurse
, llist
);
705 else if(pos
!= m_Position
|| m_Height
!= height
)
706 m_Next
->RecalculatePositions(0, llist
);
710 wxLayoutObjectList::iterator
711 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
715 wxLayoutObjectList::iterator
718 CoordType x
= 0, len
;
720 /* We search through the objects. As we don't like returning the
721 object that the cursor is behind, we just remember such an
722 object in "found" so we can return it if there is really no
723 further object following it. */
724 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
726 len
= (**i
).GetLength();
727 if( x
<= xpos
&& xpos
<= x
+ len
)
730 if(xpos
== x
+ len
) // is there another object behind?
732 else // we are really inside this object
735 x
+= (**i
).GetLength();
737 return found
; // ==NULL if really none found
740 wxLayoutObjectList::iterator
741 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
742 CoordType xpos
, CoordType
*cxpos
,
747 wxLayoutObjectList::iterator i
;
748 CoordType x
= 0, cx
= 0, width
;
750 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
752 width
= (**i
).GetWidth();
753 if( x
<= xpos
&& xpos
<= x
+ width
)
755 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
756 if(found
) *found
= true;
759 x
+= (**i
).GetWidth();
760 cx
+= (**i
).GetLength();
762 // behind last object:
764 if(found
) *found
= false;
765 return m_ObjectList
.tail();
768 /** Finds text in this line.
769 @param needle the text to find
770 @param xpos the position where to start the search
771 @return the cursoor coord where it was found or -1
774 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
) const
779 wxString
const *text
;
781 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
783 if(cpos
>= xpos
) // search from here!
785 if((**i
).GetType() == WXLO_TYPE_TEXT
)
787 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
788 relpos
= text
->Find(needle
);
789 if(relpos
>= cpos
-xpos
) // -1 if not found
794 cpos
+= (**i
).GetLength();
797 return -1; // not found
801 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
804 wxASSERT(obj
!= NULL
);
808 // If we insert a command object, we need to recalculate all lines
809 // to update their styleinfo structure.
810 if(obj
->GetType() == WXLO_TYPE_CMD
)
814 wxLOiterator i
= FindObject(xpos
, &offset
);
817 if(xpos
== 0 ) // aha, empty line!
819 m_ObjectList
.push_back(obj
);
820 m_Length
+= obj
->GetLength();
827 CoordType len
= (**i
).GetLength();
828 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
829 { // insert before this object
830 m_ObjectList
.insert(i
,obj
);
831 m_Length
+= obj
->GetLength();
836 if( i
== m_ObjectList
.tail()) // last object?
837 m_ObjectList
.push_back(obj
);
839 { // insert after current object
841 m_ObjectList
.insert(i
,obj
);
843 m_Length
+= obj
->GetLength();
846 /* Otherwise we need to split the current object.
847 Fortunately this can only be a text object. */
848 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
849 wxString left
, right
;
850 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
851 left
= tobj
->GetText().substr(0,offset
);
852 right
= tobj
->GetText().substr(offset
,len
-offset
);
853 // current text object gets set to right half
854 tobj
->GetText() = right
; // set new text
855 // before it we insert the new object
856 m_ObjectList
.insert(i
,obj
);
857 m_Length
+= obj
->GetLength();
858 // and before that we insert the left half
859 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
864 wxLayoutLine::Insert(CoordType xpos
, const wxString
& text
)
871 wxLOiterator i
= FindObject(xpos
, &offset
);
872 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
874 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
875 tobj
->GetText().insert(offset
, text
);
876 m_Length
+= text
.Length();
880 if ( !Insert(xpos
, new wxLayoutObjectText(text
)) )
888 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
890 CoordType offset
, len
;
895 wxLOiterator i
= FindObject(xpos
, &offset
);
898 if(i
== NULLIT
) return npos
;
899 // now delete from that object:
900 if((**i
).GetType() != WXLO_TYPE_TEXT
)
902 if(offset
!= 0) // at end of line after a non-text object
905 len
= (**i
).GetLength();
908 // If we delete a command object, we need to recalculate all lines
909 // to update their styleinfo structure.
910 if((**i
).GetType() == WXLO_TYPE_CMD
)
912 m_ObjectList
.erase(i
);
916 // tidy up: remove empty text objects
917 if((**i
).GetLength() == 0)
919 m_ObjectList
.erase(i
);
923 CoordType max
= (**i
).GetLength() - offset
;
924 if(npos
< max
) max
= npos
;
927 if(xpos
== GetLength())
930 { // at the end of an object
931 // move to begin of next object:
933 continue; // start over
938 if(offset
== 0 && max
== (**i
).GetLength())
939 m_ObjectList
.erase(i
); // remove the whole object
941 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
949 wxLayoutLine::MarkNextDirty(int recurse
)
951 wxLayoutLine
*line
= GetNextLine();
952 while(line
&& (recurse
== -1 || recurse
>= 0))
955 line
= line
->GetNextLine();
956 if(recurse
> 0) recurse
--;
961 wxLayoutLine::DeleteWord(CoordType xpos
)
967 wxLOiterator i
= FindObject(xpos
, &offset
);
971 if(i
== NULLIT
) return false;
972 if((**i
).GetType() != WXLO_TYPE_TEXT
)
974 // This should only happen when at end of line, behind a non-text
976 if(offset
== (**i
).GetLength()) return false;
977 m_Length
-= (**i
).GetLength(); // -1
978 m_ObjectList
.erase(i
);
979 return true; // we are done
983 if(offset
== (**i
).GetLength()) // at end of object
988 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
990 wxString str
= tobj
->GetText();
991 str
= str
.substr(offset
,str
.Length()-offset
);
992 // Find out how many positions we need to delete:
993 // 1. eat leading space
994 while(isspace(str
.c_str()[count
])) count
++;
995 // 2. eat the word itself:
996 while(isalnum(str
.c_str()[count
])) count
++;
998 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
999 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
1005 wxFAIL_MSG("unreachable");
1009 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
1011 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
1012 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
1015 m_Next
->MoveLines(-1);
1016 m_Next
->RecalculatePositions(1, llist
);
1017 /* We assume that if we have more than one object in the list,
1018 this means that we have a command object, so we need to
1019 update the following lines. */
1020 if(m_ObjectList
.size() > 1 ||
1021 ( m_ObjectList
.begin() != NULLIT
&&
1022 (**m_ObjectList
.begin()).GetType() == WXLO_TYPE_CMD
)
1026 wxLayoutLine
*next
= m_Next
;
1032 wxLayoutLine::Draw(wxDC
&dc
,
1033 wxLayoutList
*llist
,
1034 const wxPoint
& offset
) const
1036 wxLayoutObjectList::iterator i
;
1037 wxPoint pos
= offset
;
1038 pos
= pos
+ GetPosition();
1040 pos
.y
+= m_BaseLine
;
1042 CoordType xpos
= 0; // cursorpos, lenght of line
1044 CoordType from
, to
, tempto
;
1046 int highlight
= llist
->IsSelected(this, &from
, &to
);
1047 // WXLO_DEBUG(("highlight=%d", highlight ));
1048 if(highlight
== 1) // we need to draw the whole line inverted!
1049 llist
->StartHighlighting(dc
);
1051 llist
->EndHighlighting(dc
);
1053 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1055 if(highlight
== -1) // partially highlight line
1057 // parts of the line need highlighting
1058 tempto
= xpos
+(**i
).GetLength();
1059 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, to
-xpos
);
1062 (**i
).Draw(dc
, pos
, llist
);
1063 pos
.x
+= (**i
).GetWidth();
1064 xpos
+= (**i
).GetLength();
1069 This function does all the recalculation, that is, it should only be
1070 called from within wxLayoutList::Layout(), as it uses the current
1071 list's styleinfo and updates it.
1074 wxLayoutLine::Layout(wxDC
&dc
,
1075 wxLayoutList
*llist
,
1077 wxPoint
*cursorSize
,
1079 bool suppressSIupdate
)
1081 wxLayoutObjectList::iterator i
;
1083 // when a line becomes dirty, we redraw it from the place where it was
1084 // changed till the end of line (because the following wxLayoutObjects are
1085 // moved when the preceding one changes) - calculate the update rectangle.
1086 CoordType updateTop
= m_Position
.y
,
1088 updateWidth
= m_Width
,
1089 updateHeight
= m_Height
;
1093 bottomHeight
= 0; // above and below baseline
1095 objTopHeight
, objBottomHeight
; // above and below baseline
1099 CoordType heightOld
= m_Height
;
1105 bool cursorFound
= false;
1109 *cursorPos
= m_Position
;
1110 if(cursorSize
) *cursorSize
= wxPoint(0,0);
1113 m_StyleInfo
= llist
->GetStyleInfo(); // save current style
1114 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1116 wxLayoutObject
*obj
= *i
;
1117 obj
->Layout(dc
, llist
);
1118 wxPoint sizeObj
= obj
->GetSize(&objTopHeight
, &objBottomHeight
);
1120 if(cursorPos
&& ! cursorFound
)
1122 // we need to check whether the text cursor is here
1123 len
= obj
->GetLength();
1124 if(count
<= cx
&& count
+len
> cx
)
1126 if(obj
->GetType() == WXLO_TYPE_TEXT
)
1128 len
= cx
- count
; // pos in object
1129 CoordType width
, height
, descent
;
1130 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
1131 &width
, &height
, &descent
);
1132 cursorPos
->x
+= width
;
1133 cursorPos
->y
= m_Position
.y
;
1135 if(len
< obj
->GetLength())
1136 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
1138 str
= WXLO_CURSORCHAR
;
1139 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
1140 wxASSERT(cursorSize
);
1141 // Just in case some joker inserted an empty string object:
1142 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
1143 if(height
== 0) height
= sizeObj
.y
;
1144 cursorSize
->x
= width
;
1145 cursorSize
->y
= height
;
1146 cursorFound
= true; // no more checks
1150 // on some other object
1151 CoordType top
, bottom
; // unused
1152 *cursorSize
= obj
->GetSize(&top
,&bottom
);
1153 cursorPos
->y
= m_Position
.y
;
1154 cursorFound
= true; // no more checks
1160 cursorPos
->x
+= obj
->GetWidth();
1164 m_Width
+= sizeObj
.x
;
1165 if(sizeObj
.y
> m_Height
)
1167 m_Height
= sizeObj
.y
;
1170 if(objTopHeight
> topHeight
)
1171 topHeight
= objTopHeight
;
1172 if(objBottomHeight
> bottomHeight
)
1173 bottomHeight
= objBottomHeight
;
1178 if ( updateHeight
< m_Height
)
1179 updateHeight
= m_Height
;
1180 if ( updateWidth
< m_Width
)
1181 updateWidth
= m_Width
;
1183 // update all line if we don't know where to start from
1184 if ( updateLeft
== -1 )
1187 llist
->SetUpdateRect(updateLeft
, updateTop
);
1188 llist
->SetUpdateRect(updateLeft
+ updateWidth
+ MSW_CORRECTION
,
1189 updateTop
+ updateHeight
+ MSW_CORRECTION
);
1192 if(topHeight
+ bottomHeight
> m_Height
)
1194 m_Height
= topHeight
+bottomHeight
;
1197 m_BaseLine
= topHeight
;
1201 CoordType width
, height
, descent
;
1202 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1204 m_BaseLine
= m_Height
- descent
;
1207 // tell next line about coordinate change
1208 if(m_Next
&& m_Height
!= heightOld
)
1210 // FIXME isn't this done in RecalculatePositions() below anyhow?
1211 m_Next
->RecalculatePositions(0, llist
);
1214 // We need to check whether we found a valid cursor size:
1217 // this might be the case if the cursor is at the end of the
1218 // line or on a command object:
1219 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
1221 CoordType width
, height
, descent
;
1222 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1223 cursorSize
->x
= width
;
1224 cursorSize
->y
= height
;
1226 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
1227 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
1229 RecalculatePositions(1, llist
);
1235 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
1237 wxASSERT(xpos
>= 0);
1241 /* If we are at the begin of a line, we want to move all other
1242 lines down and stay with the cursor where we are. However, if we
1243 are in an empty line, we want to move down with it. */
1244 if(xpos
== 0 && GetLength() > 0)
1245 { // insert an empty line before this one
1246 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
1247 if(m_Previous
== NULL
)
1248 { // We were in first line, need to link in new empty line
1250 prev
->m_Next
= this;
1252 m_Previous
->m_Height
= 0; // this is a wild guess
1255 m_Next
->RecalculatePositions(1, llist
);
1260 wxLOiterator i
= FindObject(xpos
, &offset
);
1262 // must be at the end of the line then
1263 return new wxLayoutLine(this, llist
);
1266 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
1267 // split object at i:
1268 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
1270 wxString left
, right
;
1271 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
1272 left
= tobj
->GetText().substr(0,offset
);
1273 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
1274 // current text object gets set to left half
1275 tobj
->GetText() = left
; // set new text
1276 newLine
->Append(new wxLayoutObjectText(right
));
1277 m_Length
-= right
.Length();
1278 i
++; // don't move this object to the new list
1283 i
++; // move objects from here to new list
1286 while(i
!= m_ObjectList
.end())
1288 wxLayoutObject
*obj
= *i
;
1289 newLine
->Append(obj
);
1290 m_Length
-= obj
->GetLength();
1292 m_ObjectList
.remove(i
); // remove without deleting it
1295 m_Next
->RecalculatePositions(2, llist
);
1301 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
1303 wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
1304 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
1307 MarkDirty(GetWidth());
1309 wxLayoutObject
*last
= NULL
;
1310 for(i
= list
.begin(); i
!= list
.end();)
1312 wxLayoutObject
*current
= *i
;
1314 // merge text objects together for efficiency
1315 if ( last
&& last
->GetType() == WXLO_TYPE_TEXT
&&
1316 current
->GetType() == WXLO_TYPE_TEXT
)
1318 wxLayoutObjectText
*textObj
= (wxLayoutObjectText
*)last
;
1319 wxString
text(textObj
->GetText());
1320 text
+= ((wxLayoutObjectText
*)current
)->GetText();
1321 textObj
->SetText(text
);
1323 list
.erase(i
); // remove and delete it
1327 // just append the object "as was"
1330 list
.remove(i
); // remove without deleting it
1333 wxASSERT(list
.empty());
1335 wxLayoutLine
*oldnext
= GetNextLine();
1336 wxLayoutLine
*nextLine
= oldnext
->GetNextLine();
1340 nextLine
->MoveLines(-1);
1344 // this is now done in Delete(), but if this function is ever called
1345 // from elsewhere, we might have to move refresh code back here (in
1346 // order not to duplicate it)
1348 wxPoint
pos(oldnext
->GetPosition());
1349 llist
->SetUpdateRect(pos
);
1350 llist
->SetUpdateRect(pos
.x
+ oldnext
->GetWidth() + MSW_CORRECTION
,
1351 pos
.y
+ oldnext
->GetHeight() + MSW_CORRECTION
);
1359 wxLayoutLine::GetWrapPosition(CoordType column
)
1362 wxLOiterator i
= FindObject(column
, &offset
);
1363 if(i
== NULLIT
) return -1; // cannot wrap
1365 // go backwards through the list and look for space in text objects
1368 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1372 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1379 }while(offset
!= -1);
1380 i
--; // move on to previous object
1384 column
-= (**i
).GetLength();
1388 offset
= (**i
).GetLength();
1389 }while(i
!= NULLIT
);
1390 /* If we reached the begin of the list and have more than one
1391 object, that one is longer than the margin, so break behind
1394 i
= m_ObjectList
.begin();
1395 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1397 pos
+= (**i
).GetLength();
1400 if(i
== NULLIT
) return -1; //why should this happen?
1401 pos
+= (**i
).GetLength();
1403 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1405 pos
+= (**i
).GetLength();
1408 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1409 // now we are at the second text object:
1410 pos
-= (**i
).GetLength();
1411 return pos
; // in front of it
1415 #ifdef WXLAYOUT_DEBUG
1417 wxLayoutLine::Debug(void)
1420 wxPoint pos
= GetPosition();
1421 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d",
1422 (long int) GetLineNumber(),
1423 (long int) pos
.x
, (long int) pos
.y
,
1424 (long int) GetHeight(),
1425 (long int) m_BaseLine
,
1426 (int) m_StyleInfo
.family
));
1427 if(m_ObjectList
.begin() != NULLIT
)
1428 (**m_ObjectList
.begin()).Debug();
1434 wxLayoutLine::Copy(wxLayoutList
*llist
,
1438 CoordType firstOffset
, lastOffset
;
1440 if(to
== -1) to
= GetLength();
1441 if(from
== to
) return;
1443 wxLOiterator first
= FindObject(from
, &firstOffset
);
1444 wxLOiterator last
= FindObject(to
, &lastOffset
);
1446 // Common special case: only one object
1447 if( first
!= NULLIT
&& last
!= NULLIT
&& *first
== *last
)
1449 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1451 llist
->Insert(new wxLayoutObjectText(
1452 ((wxLayoutObjectText
1453 *)*first
)->GetText().substr(firstOffset
,
1454 lastOffset
-firstOffset
))
1458 else // what can we do?
1460 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1461 llist
->Insert( (**first
).Copy() );
1466 // If we reach here, we can safely copy the whole first object from
1467 // the firstOffset position on:
1468 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1470 llist
->Insert(new wxLayoutObjectText(
1471 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1474 else if(firstOffset
== 0)
1475 llist
->Insert( (**first
).Copy() );
1476 // else nothing to copy :-(
1478 // Now we copy all objects before the last one:
1479 wxLOiterator i
= first
; i
++;
1480 for( ; i
!= last
; i
++)
1481 llist
->Insert( (**i
).Copy() );
1483 // And now the last object:
1486 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1488 llist
->Insert(new wxLayoutObjectText(
1489 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1493 llist
->Insert( (**last
).Copy() );
1498 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1500 The wxLayoutList object
1502 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1504 wxLayoutList::wxLayoutList()
1506 #ifdef WXLAYOUT_USE_CARET
1508 #endif // WXLAYOUT_USE_CARET
1511 InvalidateUpdateRect();
1515 wxLayoutList::~wxLayoutList()
1518 m_FirstLine
->DeleteLine(false, this);
1522 wxLayoutList::Empty(void)
1525 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1527 m_CursorPos
= wxPoint(0,0);
1528 m_CursorScreenPos
= wxPoint(0,0);
1529 m_CursorSize
= wxPoint(0,0);
1530 m_movedCursor
= true;
1531 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1532 m_CursorLine
= m_FirstLine
;
1533 InvalidateUpdateRect();
1538 wxLayoutList::InternalClear(void)
1541 m_Selection
.m_selecting
= false;
1542 m_Selection
.m_valid
= false;
1544 m_DefaultStyleInfo
.family
= wxSWISS
;
1545 m_DefaultStyleInfo
.size
= WXLO_DEFAULTFONTSIZE
;
1546 m_DefaultStyleInfo
.style
= wxNORMAL
;
1547 m_DefaultStyleInfo
.weight
= wxNORMAL
;
1548 m_DefaultStyleInfo
.underline
= 0;
1549 m_DefaultStyleInfo
.m_fg_valid
= TRUE
;
1550 m_DefaultStyleInfo
.m_fg
= *wxBLACK
;
1551 m_DefaultStyleInfo
.m_bg_valid
= TRUE
;
1552 m_DefaultStyleInfo
.m_bg
= *wxWHITE
;
1554 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1558 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1559 int underline
, wxColour
*fg
,
1562 if(family
!= -1) m_CurrentStyleInfo
.family
= family
;
1563 if(size
!= -1) m_CurrentStyleInfo
.size
= size
;
1564 if(style
!= -1) m_CurrentStyleInfo
.style
= style
;
1565 if(weight
!= -1) m_CurrentStyleInfo
.weight
= weight
;
1566 if(underline
!= -1) m_CurrentStyleInfo
.underline
= underline
!= 0;
1567 if(fg
) m_CurrentStyleInfo
.m_fg
= *fg
;
1568 if(bg
) m_CurrentStyleInfo
.m_bg
= *bg
;
1570 new wxLayoutObjectCmd(
1571 m_CurrentStyleInfo
.family
,
1572 m_CurrentStyleInfo
.size
,
1573 m_CurrentStyleInfo
.style
,
1574 m_CurrentStyleInfo
.weight
,
1575 m_CurrentStyleInfo
.underline
,
1580 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1581 int underline
, char const *fg
, char const *bg
)
1589 cfg
= wxTheColourDatabase
->FindColour(fg
);
1591 cbg
= wxTheColourDatabase
->FindColour(bg
);
1593 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1597 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1598 int underline
, wxColour
*fg
, wxColour
*bg
)
1601 m_DefaultStyleInfo
= wxLayoutStyleInfo(family
, size
, style
, weight
,
1603 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1607 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1612 for(line
= m_FirstLine
;
1614 line
= line
->GetNextLine())
1616 if(line
->GetLineNumber() >= cpos
.y
)
1618 xpos
= line
->FindText(needle
,
1619 (line
->GetLineNumber() == cpos
.y
) ?
1622 return wxPoint(xpos
, line
->GetLineNumber());
1625 return wxPoint(-1,-1);
1630 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1632 AddCursorPosToUpdateRect();
1634 wxPoint cursorPosOld
= m_CursorPos
;
1636 wxLayoutLine
*line
= m_FirstLine
;
1637 while(line
&& line
->GetLineNumber() != p
.y
)
1638 line
= line
->GetNextLine();
1639 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1641 m_CursorPos
.y
= p
.y
;
1642 m_CursorLine
= line
;
1643 CoordType len
= line
->GetLength();
1646 m_CursorPos
.x
= p
.x
;
1650 m_CursorPos
.x
= len
;
1654 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1656 return m_CursorPos
== p
;
1660 wxLayoutList::MoveCursorVertically(int n
)
1662 AddCursorPosToUpdateRect();
1664 wxPoint cursorPosOld
= m_CursorPos
;
1667 if(n
< 0) // move up
1669 if(m_CursorLine
== m_FirstLine
) return false;
1670 while(n
< 0 && m_CursorLine
)
1672 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1678 m_CursorLine
= m_FirstLine
;
1684 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1685 m_CursorPos
.x
= m_CursorLine
->GetLength();
1691 wxLayoutLine
*last
= m_CursorLine
;
1692 if(! m_CursorLine
->GetNextLine()) return false;
1693 while(n
> 0 && m_CursorLine
)
1697 m_CursorLine
= m_CursorLine
->GetNextLine();
1701 m_CursorLine
= last
;
1707 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1708 m_CursorPos
.x
= m_CursorLine
->GetLength();
1713 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1719 wxLayoutList::MoveCursorHorizontally(int n
)
1721 AddCursorPosToUpdateRect();
1723 wxPoint cursorPosOld
= m_CursorPos
;
1728 if(m_CursorPos
.x
== 0) // at begin of line
1730 if(! MoveCursorVertically(-1))
1732 MoveCursorToEndOfLine();
1737 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1738 m_CursorPos
.x
-= move
; n
+= move
;
1743 int len
= m_CursorLine
->GetLength();
1744 if(m_CursorPos
.x
== len
) // at end of line
1746 if(! MoveCursorVertically(1))
1748 MoveCursorToBeginOfLine();
1753 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1754 m_CursorPos
.x
+= move
;
1758 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1764 wxLayoutList::MoveCursorWord(int n
)
1766 wxCHECK_MSG( m_CursorLine
, false, "no current line" );
1767 wxCHECK_MSG( n
== -1 || n
== +1, false, "not implemented yet" );
1769 CoordType moveDistance
= 0;
1771 for ( wxLOiterator i
= m_CursorLine
->FindObject(m_CursorPos
.x
, &offset
);
1778 wxLayoutObject
*obj
= *i
;
1779 if( obj
->GetType() != WXLO_TYPE_TEXT
)
1781 // any non text objects count as one word
1784 moveDistance
+= obj
->GetLength();
1789 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)obj
;
1791 if ( offset
== tobj
->GetLength() )
1798 const char *start
= tobj
->GetText().c_str();
1799 const char *p
= start
+ offset
;
1801 // to the beginning/end of the next/prev word
1802 while ( isspace(*p
) )
1807 // go to the end/beginning of the word (in a broad sense...)
1808 while ( p
>= start
&& !isspace(*p
) )
1815 // now advance to the beginning of the next word
1816 while ( isspace(*p
) )
1822 moveDistance
= p
- start
- offset
;
1826 // except for the first iteration, offset is 0
1830 MoveCursorHorizontally(moveDistance
);
1836 wxLayoutList::Insert(wxString
const &text
)
1838 wxASSERT(m_CursorLine
);
1839 wxASSERT_MSG( text
.Find('\n') == wxNOT_FOUND
, "use wxLayoutImportText!" );
1844 AddCursorPosToUpdateRect();
1846 if ( !m_CursorLine
->Insert(m_CursorPos
.x
, text
) )
1849 m_CursorPos
.x
+= text
.Length();
1851 m_movedCursor
= true;
1853 m_CursorLine
->RecalculatePositions(0, this);
1859 wxLayoutList::Insert(wxLayoutObject
*obj
)
1861 wxASSERT(m_CursorLine
);
1864 m_CursorLine
= GetFirstLine();
1866 AddCursorPosToUpdateRect();
1868 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1869 m_CursorPos
.x
+= obj
->GetLength();
1870 m_movedCursor
= true;
1872 m_CursorLine
->RecalculatePositions(0, this);
1878 wxLayoutList::Insert(wxLayoutList
*llist
)
1883 for(wxLayoutLine
*line
= llist
->GetFirstLine();
1885 line
= line
->GetNextLine()
1888 for(wxLOiterator i
= line
->GetFirstObject();
1898 wxLayoutList::LineBreak(void)
1900 wxASSERT(m_CursorLine
);
1901 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1903 AddCursorPosToUpdateRect();
1905 wxPoint
position(m_CursorLine
->GetPosition());
1908 width
= m_CursorLine
->GetWidth(),
1909 height
= m_CursorLine
->GetHeight();
1911 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1912 if(setFirst
) // we were at beginning of first line
1913 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1914 if(m_CursorPos
.x
!= 0)
1918 wxLayoutLine
*prev
= m_CursorLine
->GetPreviousLine();
1919 wxCHECK_MSG(prev
, false, "just broke the line, where is the previous one?");
1921 height
+= prev
->GetHeight();
1923 m_movedCursor
= true;
1925 SetUpdateRect(position
);
1926 SetUpdateRect(position
.x
+ width
+ MSW_CORRECTION
,
1927 position
.y
+ height
+ MSW_CORRECTION
);
1933 wxLayoutList::WrapLine(CoordType column
)
1935 if(m_CursorPos
.x
<= column
|| column
< 1)
1936 return false; // do nothing yet
1939 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1941 return false; // cannot break line
1943 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1944 m_CursorPos
.x
= xpos
;
1946 AddCursorPosToUpdateRect();
1949 Delete(1); // delete the space
1950 m_CursorPos
.x
= newpos
;
1952 m_CursorLine
->RecalculatePositions(1, this);
1954 m_movedCursor
= true;
1961 wxLayoutList::Delete(CoordType npos
)
1963 wxCHECK_MSG(m_CursorLine
, false, "can't delete in non existing line");
1968 AddCursorPosToUpdateRect();
1970 // were other lines appended to this one (this is important to know because
1971 // this means that our width _increased_ as the result of deletion)
1972 bool wasMerged
= false;
1974 // the size of the region to update
1975 CoordType totalHeight
= m_CursorLine
->GetHeight(),
1976 totalWidth
= m_CursorLine
->GetWidth();
1981 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1985 // More to delete, continue on next line.
1987 // First, check if line is empty:
1988 if(m_CursorLine
->GetLength() == 0)
1990 // in this case, updating could probably be optimised
1992 wxASSERT(DeleteLines(1) == 0);
2001 // Need to join next line
2002 if(! m_CursorLine
->GetNextLine())
2007 wxLayoutLine
*next
= m_CursorLine
->GetNextLine();
2010 totalHeight
+= next
->GetHeight();
2011 totalWidth
+= next
->GetWidth();
2013 m_CursorLine
->MergeNextLine(this);
2018 wxFAIL_MSG("can't delete all this");
2028 // we need to update the whole tail of the line and the lines which
2032 wxPoint
position(m_CursorLine
->GetPosition());
2033 SetUpdateRect(position
);
2034 SetUpdateRect(position
.x
+ totalWidth
+ MSW_CORRECTION
,
2035 position
.y
+ totalHeight
+ MSW_CORRECTION
);
2042 wxLayoutList::DeleteLines(int n
)
2044 wxASSERT(m_CursorLine
);
2047 AddCursorPosToUpdateRect();
2051 if(!m_CursorLine
->GetNextLine())
2052 { // we cannot delete this line, but we can clear it
2053 MoveCursorToBeginOfLine();
2054 DeleteToEndOfLine();
2055 m_CursorLine
->RecalculatePositions(2, this);
2059 line
= m_CursorLine
;
2060 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
2062 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
2063 wxASSERT(m_FirstLine
);
2064 wxASSERT(m_CursorLine
);
2066 m_CursorLine
->RecalculatePositions(2, this);
2071 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
2073 wxLayoutLine
*line
= m_FirstLine
;
2075 // first, make sure everything is calculated - this might not be
2076 // needed, optimise it later
2077 ApplyStyle(m_DefaultStyleInfo
, dc
);
2080 line
->RecalculatePosition(this); // so we don't need to do it all the time
2081 // little condition to speed up redrawing:
2082 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2083 line
= line
->GetNextLine();
2088 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
,
2089 bool resetCursorMovedFlag
,
2090 const wxPoint
& translate
)
2092 wxCHECK_RET( m_CursorLine
, "no cursor line" );
2094 if ( m_movedCursor
)
2096 // we need to save the current style, in case the layout() of
2097 // the line changes it
2098 wxLayoutStyleInfo SiBackup
= m_CurrentStyleInfo
;
2099 m_CursorLine
->Layout(dc
, this,
2100 &m_CursorScreenPos
, &m_CursorSize
,
2102 /* suppress update */ true);
2103 ApplyStyle(SiBackup
, dc
); // restore it
2105 if ( resetCursorMovedFlag
)
2107 #ifdef WXLAYOUT_USE_CARET
2108 // adjust the caret position
2109 wxPoint
coords(m_CursorScreenPos
);
2110 coords
+= translate
;
2113 m_caret
->Move(coords
);
2114 #endif // WXLAYOUT_USE_CARET
2116 m_movedCursor
= false;
2122 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
2124 // this function is called with wxMemoryDC argument from ScrollToCursor(),
2125 // for example, so it shouldn't clear "cursor moved" flag - or else the
2126 // cursor won't be moved when UpdateCursorScreenPos() is called with the
2127 // "real" (i.e. the one used for drawing) wxDC.
2128 UpdateCursorScreenPos(dc
, false /* don't reset the flag */);
2130 return m_CursorScreenPos
;
2134 Is called before each Draw(). Now, it will re-layout all lines which
2138 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
, bool forceAll
)
2140 // first, make sure everything is calculated - this might not be
2141 // needed, optimise it later
2142 ApplyStyle(m_DefaultStyleInfo
, dc
);
2144 // This one we always Layout() to get the current cursor
2145 // coordinates on the screen:
2146 m_CursorLine
->MarkDirty();
2147 bool wasDirty
= false;
2148 wxLayoutLine
*line
= m_FirstLine
;
2152 ApplyStyle(line
->GetStyleInfo(), dc
);
2153 if(forceAll
|| line
->IsDirty())
2155 // The following Layout() calls will update our
2156 // m_CurrentStyleInfo if needed.
2157 if(line
== m_CursorLine
)
2158 line
->Layout(dc
, this,
2159 (wxPoint
*)&m_CursorScreenPos
,
2160 (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
2162 line
->Layout(dc
, this);
2164 // little condition to speed up redrawing:
2165 if(bottom
!= -1 && line
->GetPosition().y
> bottom
)
2169 line
->RecalculatePositions(1, this);
2170 line
= line
->GetNextLine();
2173 // can only be 0 if we are on the first line and have no next line
2174 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
2175 m_CursorLine
->GetNextLine() == NULL
&&
2176 m_CursorLine
== m_FirstLine
));
2177 AddCursorPosToUpdateRect();
2181 wxLayoutList::Draw(wxDC
&dc
,
2182 wxPoint
const &offset
,
2186 wxLayoutLine
*line
= m_FirstLine
;
2188 /* We need to re-layout all dirty lines to update styleinfos
2189 etc. However, somehow we don't find all dirty lines... */
2190 Layout(dc
); //,-1,true); //FIXME
2191 ApplyStyle(m_DefaultStyleInfo
, dc
);
2192 wxBrush
brush(m_CurrentStyleInfo
.m_bg
, wxSOLID
);
2194 dc
.SetBackgroundMode(wxTRANSPARENT
);
2196 bool style_set
= false;
2199 // only draw if between top and bottom:
2201 line
->GetPosition().y
+ line
->GetHeight() >= top
))
2205 ApplyStyle(line
->GetStyleInfo(), dc
);
2208 line
->Draw(dc
, this, offset
);
2212 line
->Layout(dc
, this);
2214 // little condition to speed up redrawing:
2215 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2216 line
= line
->GetNextLine();
2218 InvalidateUpdateRect();
2220 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
2221 m_Selection
.m_valid
? "valid" : "invalid",
2222 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
2223 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
2227 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
2231 // First, find the right line:
2232 wxLayoutLine
*line
= m_FirstLine
;
2235 ApplyStyle(m_DefaultStyleInfo
, dc
);
2238 p
= line
->GetPosition();
2239 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
2242 // we need to run a layout here to get font sizes right :-(
2244 // VZ: we can't call Layout() from here because it marks the line as
2245 // clean and it is not refreshed when it's called from wxLayoutList::
2246 // Layout() - if we really need to do this, we should introduce an
2247 // extra argument to Layout() to prevent the line from MarkClean()ing
2249 line
->Layout(dc
, this);
2251 line
= line
->GetNextLine();
2255 if(found
) *found
= false;
2256 return NULL
; // not found
2258 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
2259 // Now, find the object in the line:
2260 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
2261 cursorPos
? & cursorPos
->x
: NULL
,
2263 return (i
== NULLIT
) ? NULL
: *i
;
2268 wxLayoutList::GetSize(void) const
2271 *line
= m_FirstLine
,
2274 return wxPoint(0,0);
2276 wxPoint
maxPoint(0,0);
2281 if(line
->GetWidth() > maxPoint
.x
)
2282 maxPoint
.x
= line
->GetWidth();
2284 line
= line
->GetNextLine();
2287 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
2289 // if the line was just added, its height would be 0 and we can't call
2290 // Layout() from here because we don't have a dc and we might be not drawing
2291 // at all, besides... So take the cursor height by default (taking 0 is bad
2292 // because then the scrollbars won't be resized and the new line won't be
2294 if ( last
->IsDirty() )
2296 if ( last
->GetHeight() == 0 )
2297 maxPoint
.y
+= m_CursorSize
.y
;
2298 if ( last
->GetWidth() == 0 && maxPoint
.x
< m_CursorSize
.x
)
2299 maxPoint
.x
= m_CursorSize
.x
;
2307 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
2309 wxPoint
coords(m_CursorScreenPos
);
2310 coords
+= translate
;
2312 #ifdef WXLAYOUT_DEBUG
2313 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
2314 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
2315 (long)coords
.x
, (long)coords
.y
,
2316 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
2317 (long)m_CursorLine
->GetLineNumber(),
2318 (long)m_CursorLine
->GetLength()));
2320 wxLogStatus("Cursor is at (%d, %d)", m_CursorPos
.x
, m_CursorPos
.y
);
2323 #ifndef WXLAYOUT_USE_CARET
2324 dc
.SetBrush(*wxBLACK_BRUSH
);
2325 dc
.SetLogicalFunction(wxXOR
);
2326 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
2329 dc
.DrawRectangle(coords
.x
, coords
.y
,
2330 m_CursorSize
.x
, m_CursorSize
.y
);
2331 SetUpdateRect(coords
.x
, coords
.y
);
2332 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
2336 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
2337 coords
.x
, coords
.y
);
2338 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
2339 SetUpdateRect(coords
.x
, coords
.y
);
2341 dc
.SetLogicalFunction(wxCOPY
);
2342 //dc.SetBrush(wxNullBrush);
2343 #endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
2347 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
2349 if(m_UpdateRectValid
)
2350 GrowRect(m_UpdateRect
, x
, y
);
2355 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
2356 m_UpdateRect
.height
= 4;// wxGTK :-)
2357 m_UpdateRectValid
= true;
2362 wxLayoutList::StartSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2364 wxPoint
cpos(cposOrig
);
2367 WXLO_DEBUG(("Starting selection at %ld/%ld", cpos
.x
, cpos
.y
));
2368 m_Selection
.m_CursorA
= cpos
;
2369 m_Selection
.m_CursorB
= cpos
;
2370 m_Selection
.m_ScreenA
= spos
;
2371 m_Selection
.m_ScreenB
= spos
;
2372 m_Selection
.m_selecting
= true;
2373 m_Selection
.m_valid
= false;
2377 wxLayoutList::ContinueSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2379 wxPoint
cpos(cposOrig
);
2383 wxASSERT(m_Selection
.m_selecting
== true);
2384 wxASSERT(m_Selection
.m_valid
== false);
2385 WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos
.x
, cpos
.y
));
2387 if ( m_Selection
.m_CursorB
<= cpos
)
2389 m_Selection
.m_ScreenB
= spos
;
2390 m_Selection
.m_CursorB
= cpos
;
2394 m_Selection
.m_ScreenA
= spos
;
2395 m_Selection
.m_CursorA
= cpos
;
2398 // we always want m_CursorA <= m_CursorB!
2399 if( m_Selection
.m_CursorA
> m_Selection
.m_CursorB
)
2401 // exchange the start/end points
2402 wxPoint help
= m_Selection
.m_CursorB
;
2403 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
2404 m_Selection
.m_CursorA
= help
;
2406 help
= m_Selection
.m_ScreenB
;
2407 m_Selection
.m_ScreenB
= m_Selection
.m_ScreenA
;
2408 m_Selection
.m_ScreenA
= help
;
2413 wxLayoutList::EndSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2415 wxPoint
cpos(cposOrig
);
2418 ContinueSelection(cpos
);
2419 WXLO_DEBUG(("Ending selection at %ld/%ld", cpos
.x
, cpos
.y
));
2420 m_Selection
.m_selecting
= false;
2421 m_Selection
.m_valid
= true;
2425 wxLayoutList::DiscardSelection()
2427 if ( !HasSelection() )
2430 m_Selection
.m_valid
=
2431 m_Selection
.m_selecting
= false;
2433 // invalidate the area which was previousle selected - and which is not
2434 // selected any more
2435 if ( m_Selection
.HasValidScreenCoords() )
2437 SetUpdateRect(m_Selection
.m_ScreenA
);
2438 SetUpdateRect(m_Selection
.m_ScreenB
);
2447 wxLayoutList::IsSelecting(void)
2449 return m_Selection
.m_selecting
;
2453 wxLayoutList::IsSelected(const wxPoint
&cursor
)
2455 if ( !HasSelection() )
2458 return m_Selection
.m_CursorA
<= cursor
&& cursor
<= m_Selection
.m_CursorB
;
2462 /** Tests whether this layout line is selected and needs
2464 @param line to test for
2465 @return 0 = not selected, 1 = fully selected, -1 = partially
2469 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
2472 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
2474 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
2477 CoordType y
= line
->GetLineNumber();
2478 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
2480 else if(m_Selection
.m_CursorA
.y
== y
)
2482 *from
= m_Selection
.m_CursorA
.x
;
2483 if(m_Selection
.m_CursorB
.y
== y
)
2484 *to
= m_Selection
.m_CursorB
.x
;
2486 *to
= line
->GetLength();
2489 else if(m_Selection
.m_CursorB
.y
== y
)
2491 *to
= m_Selection
.m_CursorB
.x
;
2492 if(m_Selection
.m_CursorA
.y
== y
)
2493 *from
= m_Selection
.m_CursorA
.x
;
2503 wxLayoutList::DeleteSelection(void)
2505 if(! m_Selection
.m_valid
)
2508 m_Selection
.m_valid
= false;
2510 // Only delete part of the current line?
2511 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
2513 MoveCursorTo(m_Selection
.m_CursorA
);
2514 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
2523 for(firstLine
= m_FirstLine
;
2524 firstLine
&& firstLine
->GetLineNumber() < m_Selection
.m_CursorA
.y
;
2525 firstLine
=firstLine
->GetNextLine())
2527 if(!firstLine
|| firstLine
->GetLineNumber() != m_Selection
.m_CursorA
.y
)
2531 for(lastLine
= m_FirstLine
;
2532 lastLine
&& lastLine
->GetLineNumber() < m_Selection
.m_CursorB
.y
;
2533 lastLine
=lastLine
->GetNextLine())
2535 if(!lastLine
|| lastLine
->GetLineNumber() != m_Selection
.m_CursorB
.y
)
2539 // We now know that the two lines are different:
2541 // First, delete what's left of this line:
2542 MoveCursorTo(m_Selection
.m_CursorA
);
2543 DeleteToEndOfLine();
2545 wxLayoutLine
*nextLine
= firstLine
->GetNextLine();
2546 while(nextLine
&& nextLine
!= lastLine
)
2547 nextLine
= nextLine
->DeleteLine(false, this);
2549 // Now nextLine = lastLine;
2550 Delete(1); // This joins firstLine and nextLine
2551 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x
2555 firstLine
->RecalculatePositions(1, this);
2558 /// Starts highlighting the selection
2560 wxLayoutList::StartHighlighting(wxDC
&dc
)
2563 dc
.SetTextForeground(m_CurrentStyleInfo
.m_bg
);
2564 dc
.SetTextBackground(m_CurrentStyleInfo
.m_fg
);
2565 dc
.SetBackgroundMode(wxSOLID
);
2569 /// Ends highlighting the selection
2571 wxLayoutList::EndHighlighting(wxDC
&dc
)
2574 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2575 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2576 dc
.SetBackgroundMode(wxTRANSPARENT
);
2582 wxLayoutList::Copy(const wxPoint
&from
,
2589 for(firstLine
= m_FirstLine
;
2590 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
2591 firstLine
=firstLine
->GetNextLine())
2593 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
2596 for(lastLine
= m_FirstLine
;
2597 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
2598 lastLine
=lastLine
->GetNextLine())
2600 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
2605 wxLayoutLine
*tmp
= firstLine
;
2606 firstLine
= lastLine
;
2610 wxLayoutList
*llist
= new wxLayoutList();
2612 if(firstLine
== lastLine
)
2614 firstLine
->Copy(llist
, from
.x
, to
.x
);
2618 // Extract objects from first line
2619 firstLine
->Copy(llist
, from
.x
);
2621 // Extract all lines between
2622 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
2624 line
= line
->GetNextLine())
2629 // Extract objects from last line
2630 lastLine
->Copy(llist
, 0, to
.x
);
2636 wxLayoutList::GetSelection(wxLayoutDataObject
*wxlo
, bool invalidate
)
2638 if(! m_Selection
.m_valid
)
2640 if(m_Selection
.m_selecting
)
2646 if(invalidate
) m_Selection
.m_valid
= false;
2648 wxLayoutList
*llist
= Copy( m_Selection
.m_CursorA
,
2649 m_Selection
.m_CursorB
);
2651 if(llist
&& wxlo
) // export as data object, too
2655 wxLayoutExportObject
*export
;
2656 wxLayoutExportStatus
status(llist
);
2657 while((export
= wxLayoutExport( &status
, WXLO_EXPORT_AS_OBJECTS
)) != NULL
)
2659 if(export
->type
== WXLO_EXPORT_EMPTYLINE
)
2660 ; //FIXME missing support for linebreaks in string format
2662 export
->content
.object
->Write(string
);
2666 wxlo
->SetData(string
.c_str(), string
.Length()+1);
2673 #define COPY_SI(what) if(si.what != -1) { m_CurrentStyleInfo.what = si.what; fontChanged = TRUE; }
2676 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
const &si
, wxDC
&dc
)
2678 bool fontChanged
= FALSE
;
2685 dc
.SetFont( m_FontCache
.GetFont(m_CurrentStyleInfo
) );
2689 m_CurrentStyleInfo
.m_fg
= si
.m_fg
;
2690 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2694 m_CurrentStyleInfo
.m_bg
= si
.m_bg
;
2695 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2700 #ifdef WXLAYOUT_DEBUG
2703 wxLayoutList::Debug(void)
2705 WXLO_DEBUG(("Cursor is in line %d, screen pos = (%d, %d)",
2706 m_CursorLine
->GetLineNumber(),
2707 m_CursorScreenPos
.x
, m_CursorScreenPos
.y
));
2710 for(line
= m_FirstLine
; line
; line
= line
->GetNextLine())
2719 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2723 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2725 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2726 wxString
const & title
)
2731 // remove any highlighting which could interfere with printing:
2732 m_llist
->StartSelection();
2733 m_llist
->EndSelection();
2736 wxLayoutPrintout::~wxLayoutPrintout()
2741 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2743 // The following bit is taken from the printing sample, let's see
2744 // whether it works for us.
2746 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2747 * the screen text size. This page also draws lines of actual length 5cm
2750 // Get the logical pixels per inch of screen and printer
2751 int ppiScreenX
, ppiScreenY
;
2752 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2753 int ppiPrinterX
, ppiPrinterY
;
2754 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2756 if(ppiScreenX
== 0) // not yet set, need to guess
2761 if(ppiPrinterX
== 0) // not yet set, need to guess
2767 // This scales the DC so that the printout roughly represents the
2768 // the screen scaling. The text point size _should_ be the right size
2769 // but in fact is too small for some reason. This is a detail that will
2770 // need to be addressed at some point but can be fudged for the
2772 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2774 // Now we have to check in case our real page size is reduced
2775 // (e.g. because we're drawing to a print preview memory DC)
2776 int pageWidth
, pageHeight
;
2778 dc
->GetSize(&w
, &h
);
2779 GetPageSizePixels(&pageWidth
, &pageHeight
);
2780 if(pageWidth
!= 0) // doesn't work always
2782 // If printer pageWidth == current DC width, then this doesn't
2783 // change. But w might be the preview bitmap width, so scale down.
2784 scale
= scale
* (float)(w
/(float)pageWidth
);
2786 dc
->SetUserScale(scale
, scale
);
2790 bool wxLayoutPrintout::OnPrintPage(int page
)
2799 top
= (page
- 1)*m_PrintoutHeight
;
2800 bottom
= top
+ m_PrintoutHeight
;
2801 // SetDeviceOrigin() doesn't work here, so we need to manually
2802 // translate all coordinates.
2803 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2804 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2811 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2813 /* We allocate a temporary wxDC for printing, so that we can
2814 determine the correct paper size and scaling. We don't actually
2815 print anything on it. */
2817 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2819 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2822 float scale
= ScaleDC(&psdc
);
2824 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2825 // This sets a left/top origin of 15% and 20%:
2826 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
2828 // This is the length of the printable area.
2829 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
2830 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2834 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2837 *maxPage
= m_NumOfPages
;
2840 *selPageTo
= m_NumOfPages
;
2841 wxRemoveFile(WXLLIST_TEMPFILE
);
2844 bool wxLayoutPrintout::HasPage(int pageNum
)
2846 return pageNum
<= m_NumOfPages
;
2850 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2851 out. It's a waste of paper anyway.
2855 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2856 wxPoint topleft
, wxPoint bottomright
,
2859 // make backups of all essential parameters
2860 const wxBrush
& brush
= dc
.GetBrush();
2861 const wxPen
& pen
= dc
.GetPen();
2862 const wxFont
& font
= dc
.GetFont();
2864 dc
.SetBrush(*wxWHITE_BRUSH
);
2865 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
2866 dc
.DrawRoundedRectangle(topleft
.x
,
2867 topleft
.y
,bottomright
.x
-topleft
.x
,
2868 bottomright
.y
-topleft
.y
);
2869 dc
.SetBrush(*wxBLACK_BRUSH
);
2870 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
2871 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
2875 page
= "9999/9999 "; // many pages...
2877 dc
.GetTextExtent(page
,&w
,&h
);
2878 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
2879 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
2880 dc
.GetTextExtent("XXXX", &w
,&h
);
2881 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
2892 wxFontCache::GetFont(int family
, int size
, int style
, int weight
,
2895 for(wxFCEList::iterator i
= m_FontList
.begin();
2896 i
!= m_FontList
.end(); i
++)
2897 if( (**i
).Matches(family
, size
, style
, weight
, underline
) )
2898 return (**i
).GetFont();
2900 wxFontCacheEntry
*fce
= new wxFontCacheEntry(family
, size
, style
,
2902 m_FontList
.push_back(fce
);
2903 return fce
->GetFont();