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
,
470 underline
= iul
!= 0;
472 m_fg_valid
= fg
!= 0;
473 m_bg_valid
= bg
!= 0;
474 m_fg
= m_fg_valid
? *fg
: *wxBLACK
;
475 m_bg
= m_fg_valid
? *bg
: *wxWHITE
;
478 #define COPY_SI_(what) if(right.what != -1) what = right.what;
481 wxLayoutStyleInfo::operator=(const wxLayoutStyleInfo
&right
)
488 if(right
.m_fg_valid
) m_fg
= right
.m_fg
;
489 if(right
.m_bg_valid
) m_bg
= right
.m_bg
;
493 wxLayoutObjectCmd::wxLayoutObjectCmd(int family
, int size
, int style
, int
494 weight
, int underline
,
495 wxColour
*fg
, wxColour
*bg
)
498 m_StyleInfo
= new wxLayoutStyleInfo(family
, size
,style
,weight
,underline
,fg
,bg
);
502 wxLayoutObjectCmd::Copy(void)
504 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
509 m_StyleInfo
->underline
,
510 m_StyleInfo
->m_fg_valid
?
511 &m_StyleInfo
->m_fg
: NULL
,
512 m_StyleInfo
->m_bg_valid
?
513 &m_StyleInfo
->m_bg
: NULL
);
514 obj
->SetUserData(m_UserData
);
519 wxLayoutObjectCmd::Write(wxString
&ostr
)
521 ostr
<< WXLO_TYPE_CMD
<< '\n'
522 << m_StyleInfo
->size
<< '\n'
523 << m_StyleInfo
->family
<< '\n'
524 << m_StyleInfo
->style
<< '\n'
525 << m_StyleInfo
->weight
<< '\n'
526 << m_StyleInfo
->underline
<< '\n'
527 << m_StyleInfo
->m_fg_valid
<< '\n'
528 << m_StyleInfo
->m_bg_valid
<< '\n';
529 if(m_StyleInfo
->m_fg_valid
)
531 ostr
<< m_StyleInfo
->m_fg
.Red() << '\n'
532 << m_StyleInfo
->m_fg
.Green() << '\n'
533 << m_StyleInfo
->m_fg
.Blue() << '\n';
535 if(m_StyleInfo
->m_bg_valid
)
537 ostr
<< m_StyleInfo
->m_bg
.Red() << '\n'
538 << m_StyleInfo
->m_bg
.Green() << '\n'
539 << m_StyleInfo
->m_bg
.Blue() << '\n';
544 wxLayoutObjectCmd::Read(wxString
&istr
)
546 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd
;
549 ReadString(tmp
, istr
);
550 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->size
);
551 ReadString(tmp
, istr
);
552 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->family
);
553 ReadString(tmp
, istr
);
554 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->style
);
555 ReadString(tmp
, istr
);
556 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->weight
);
557 ReadString(tmp
, istr
);
558 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->underline
);
559 ReadString(tmp
, istr
);
560 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_fg_valid
);
561 ReadString(tmp
, istr
);
562 sscanf(tmp
.c_str(),"%d", &obj
->m_StyleInfo
->m_bg_valid
);
563 if(obj
->m_StyleInfo
->m_fg_valid
)
565 int red
, green
, blue
;
566 ReadString(tmp
, istr
);
567 sscanf(tmp
.c_str(),"%d", &red
);
568 ReadString(tmp
, istr
);
569 sscanf(tmp
.c_str(),"%d", &green
);
570 ReadString(tmp
, istr
);
571 sscanf(tmp
.c_str(),"%d", &blue
);
572 obj
->m_StyleInfo
->m_fg
= wxColour(red
, green
, blue
);
574 if(obj
->m_StyleInfo
->m_bg_valid
)
576 int red
, green
, blue
;
577 ReadString(tmp
, istr
);
578 sscanf(tmp
.c_str(),"%d", &red
);
579 ReadString(tmp
, istr
);
580 sscanf(tmp
.c_str(),"%d", &green
);
581 ReadString(tmp
, istr
);
582 sscanf(tmp
.c_str(),"%d", &blue
);
583 obj
->m_StyleInfo
->m_bg
= wxColour(red
, green
, blue
);
589 wxLayoutObjectCmd::~wxLayoutObjectCmd()
595 wxLayoutObjectCmd::GetStyle(void) const
601 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
602 wxLayoutList
*wxllist
,
603 CoordType begin
, CoordType
/* len */)
605 wxASSERT(m_StyleInfo
);
606 wxllist
->ApplyStyle(*m_StyleInfo
, dc
);
610 wxLayoutObjectCmd::Layout(wxDC
&dc
, class wxLayoutList
* llist
)
612 // this get called, so that recalculation uses right font sizes
613 Draw(dc
, wxPoint(0,0), llist
);
617 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
619 The wxLayoutLine object
621 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
623 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
626 m_Width
= m_Height
= 0;
632 RecalculatePosition(llist
);
635 m_LineNumber
= m_Previous
->GetLineNumber()+1;
636 m_Next
= m_Previous
->GetNextLine();
637 m_Previous
->m_Next
= this;
641 m_Next
->m_Previous
= this;
642 m_Next
->MoveLines(+1);
643 m_Next
->RecalculatePositions(1,llist
);
647 wxLayoutLine::~wxLayoutLine()
649 // kbList cleans itself
653 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
655 wxASSERT(m_Previous
|| GetLineNumber() == 0);
657 wxPoint
posOld(m_Position
);
661 m_Position
= m_Previous
->GetPosition();
662 m_Position
.y
+= m_Previous
->GetHeight();
665 m_Position
= wxPoint(0,0);
667 if ( m_Position
!= posOld
)
669 // the whole line moved and must be repainted
670 llist
->SetUpdateRect(m_Position
);
671 llist
->SetUpdateRect(m_Position
.x
+ GetWidth() + MSW_CORRECTION
,
672 m_Position
.y
+ GetHeight() + MSW_CORRECTION
);
673 llist
->SetUpdateRect(posOld
);
674 llist
->SetUpdateRect(posOld
.x
+ GetWidth() + MSW_CORRECTION
,
675 posOld
.y
+ GetHeight() + MSW_CORRECTION
);
682 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
684 //FIXME: is this really needed? We run Layout() anyway.
685 // Recursing here, drives computation time up exponentially, as
686 // each line will cause all following lines to be recalculated.
687 // Yes, or linenumbers go wrong.
689 wxASSERT(recurse
>= 0);
690 wxPoint pos
= m_Position
;
691 CoordType height
= m_Height
;
693 // WXLO_TRACE("RecalculatePositions()");
694 RecalculatePosition(llist
);
698 m_Next
->RecalculatePositions(--recurse
, llist
);
699 else if(pos
!= m_Position
|| m_Height
!= height
)
700 m_Next
->RecalculatePositions(0, llist
);
704 wxLayoutObjectList::iterator
705 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
709 wxLayoutObjectList::iterator
712 CoordType x
= 0, len
;
714 /* We search through the objects. As we don't like returning the
715 object that the cursor is behind, we just remember such an
716 object in "found" so we can return it if there is really no
717 further object following it. */
718 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
720 len
= (**i
).GetLength();
721 if( x
<= xpos
&& xpos
<= x
+ len
)
724 if(xpos
== x
+ len
) // is there another object behind?
726 else // we are really inside this object
729 x
+= (**i
).GetLength();
731 return found
; // ==NULL if really none found
734 wxLayoutObjectList::iterator
735 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
736 CoordType xpos
, CoordType
*cxpos
,
741 wxLayoutObjectList::iterator i
;
742 CoordType x
= 0, cx
= 0, width
;
744 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
746 width
= (**i
).GetWidth();
747 if( x
<= xpos
&& xpos
<= x
+ width
)
749 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
750 if(found
) *found
= true;
753 x
+= (**i
).GetWidth();
754 cx
+= (**i
).GetLength();
756 // behind last object:
758 if(found
) *found
= false;
759 return m_ObjectList
.tail();
762 /** Finds text in this line.
763 @param needle the text to find
764 @param xpos the position where to start the search
765 @return the cursoor coord where it was found or -1
768 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
) const
773 wxString
const *text
;
775 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
777 if(cpos
>= xpos
) // search from here!
779 if((**i
).GetType() == WXLO_TYPE_TEXT
)
781 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
782 relpos
= text
->Find(needle
);
783 if(relpos
>= cpos
-xpos
) // -1 if not found
788 cpos
+= (**i
).GetLength();
791 return -1; // not found
795 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
798 wxASSERT(obj
!= NULL
);
802 // If we insert a command object, we need to recalculate all lines
803 // to update their styleinfo structure.
804 if(obj
->GetType() == WXLO_TYPE_CMD
)
808 wxLOiterator i
= FindObject(xpos
, &offset
);
811 if(xpos
== 0 ) // aha, empty line!
813 m_ObjectList
.push_back(obj
);
814 m_Length
+= obj
->GetLength();
821 CoordType len
= (**i
).GetLength();
822 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
823 { // insert before this object
824 m_ObjectList
.insert(i
,obj
);
825 m_Length
+= obj
->GetLength();
830 if( i
== m_ObjectList
.tail()) // last object?
831 m_ObjectList
.push_back(obj
);
833 { // insert after current object
835 m_ObjectList
.insert(i
,obj
);
837 m_Length
+= obj
->GetLength();
840 /* Otherwise we need to split the current object.
841 Fortunately this can only be a text object. */
842 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
843 wxString left
, right
;
844 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
845 left
= tobj
->GetText().substr(0,offset
);
846 right
= tobj
->GetText().substr(offset
,len
-offset
);
847 // current text object gets set to right half
848 tobj
->GetText() = right
; // set new text
849 // before it we insert the new object
850 m_ObjectList
.insert(i
,obj
);
851 m_Length
+= obj
->GetLength();
852 // and before that we insert the left half
853 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
858 wxLayoutLine::Insert(CoordType xpos
, const wxString
& text
)
865 wxLOiterator i
= FindObject(xpos
, &offset
);
866 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
868 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
869 tobj
->GetText().insert(offset
, text
);
870 m_Length
+= text
.Length();
874 if ( !Insert(xpos
, new wxLayoutObjectText(text
)) )
882 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
884 CoordType offset
, len
;
889 wxLOiterator i
= FindObject(xpos
, &offset
);
892 if(i
== NULLIT
) return npos
;
893 // now delete from that object:
894 if((**i
).GetType() != WXLO_TYPE_TEXT
)
896 if(offset
!= 0) // at end of line after a non-text object
899 len
= (**i
).GetLength();
902 // If we delete a command object, we need to recalculate all lines
903 // to update their styleinfo structure.
904 if((**i
).GetType() == WXLO_TYPE_CMD
)
906 m_ObjectList
.erase(i
);
910 // tidy up: remove empty text objects
911 if((**i
).GetLength() == 0)
913 m_ObjectList
.erase(i
);
917 CoordType max
= (**i
).GetLength() - offset
;
918 if(npos
< max
) max
= npos
;
921 if(xpos
== GetLength())
924 { // at the end of an object
925 // move to begin of next object:
927 continue; // start over
932 if(offset
== 0 && max
== (**i
).GetLength())
933 m_ObjectList
.erase(i
); // remove the whole object
935 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
943 wxLayoutLine::MarkNextDirty(int recurse
)
945 wxLayoutLine
*line
= GetNextLine();
946 while(line
&& (recurse
== -1 || recurse
>= 0))
949 line
= line
->GetNextLine();
950 if(recurse
> 0) recurse
--;
955 wxLayoutLine::DeleteWord(CoordType xpos
)
961 wxLOiterator i
= FindObject(xpos
, &offset
);
965 if(i
== NULLIT
) return false;
966 if((**i
).GetType() != WXLO_TYPE_TEXT
)
968 // This should only happen when at end of line, behind a non-text
970 if(offset
== (**i
).GetLength()) return false;
971 m_Length
-= (**i
).GetLength(); // -1
972 m_ObjectList
.erase(i
);
973 return true; // we are done
977 if(offset
== (**i
).GetLength()) // at end of object
982 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
984 wxString str
= tobj
->GetText();
985 str
= str
.substr(offset
,str
.Length()-offset
);
986 // Find out how many positions we need to delete:
987 // 1. eat leading space
988 while(isspace(str
.c_str()[count
])) count
++;
989 // 2. eat the word itself:
990 while(isalnum(str
.c_str()[count
])) count
++;
992 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
993 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
999 wxFAIL_MSG("unreachable");
1003 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
1005 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
1006 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
1009 m_Next
->MoveLines(-1);
1010 m_Next
->RecalculatePositions(1, llist
);
1011 /* We assume that if we have more than one object in the list,
1012 this means that we have a command object, so we need to
1013 update the following lines. */
1014 if(m_ObjectList
.size() > 1 ||
1015 ( m_ObjectList
.begin() != NULLIT
&&
1016 (**m_ObjectList
.begin()).GetType() == WXLO_TYPE_CMD
)
1020 wxLayoutLine
*next
= m_Next
;
1026 wxLayoutLine::Draw(wxDC
&dc
,
1027 wxLayoutList
*llist
,
1028 const wxPoint
& offset
) const
1030 wxLayoutObjectList::iterator i
;
1031 wxPoint pos
= offset
;
1032 pos
= pos
+ GetPosition();
1034 pos
.y
+= m_BaseLine
;
1036 CoordType xpos
= 0; // cursorpos, lenght of line
1038 CoordType from
, to
, tempto
;
1040 int highlight
= llist
->IsSelected(this, &from
, &to
);
1041 // WXLO_DEBUG(("highlight=%d", highlight ));
1042 if(highlight
== 1) // we need to draw the whole line inverted!
1043 llist
->StartHighlighting(dc
);
1045 llist
->EndHighlighting(dc
);
1047 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1049 if(highlight
== -1) // partially highlight line
1051 // parts of the line need highlighting
1052 tempto
= xpos
+(**i
).GetLength();
1053 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, to
-xpos
);
1056 (**i
).Draw(dc
, pos
, llist
);
1057 pos
.x
+= (**i
).GetWidth();
1058 xpos
+= (**i
).GetLength();
1063 This function does all the recalculation, that is, it should only be
1064 called from within wxLayoutList::Layout(), as it uses the current
1065 list's styleinfo and updates it.
1068 wxLayoutLine::Layout(wxDC
&dc
,
1069 wxLayoutList
*llist
,
1071 wxPoint
*cursorSize
,
1073 bool suppressSIupdate
)
1075 wxLayoutObjectList::iterator i
;
1077 // when a line becomes dirty, we redraw it from the place where it was
1078 // changed till the end of line (because the following wxLayoutObjects are
1079 // moved when the preceding one changes) - calculate the update rectangle.
1080 CoordType updateTop
= m_Position
.y
,
1082 updateWidth
= m_Width
,
1083 updateHeight
= m_Height
;
1087 bottomHeight
= 0; // above and below baseline
1089 objTopHeight
, objBottomHeight
; // above and below baseline
1093 CoordType heightOld
= m_Height
;
1099 bool cursorFound
= false;
1103 *cursorPos
= m_Position
;
1104 if(cursorSize
) *cursorSize
= wxPoint(0,0);
1107 m_StyleInfo
= llist
->GetStyleInfo(); // save current style
1108 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1110 wxLayoutObject
*obj
= *i
;
1111 obj
->Layout(dc
, llist
);
1112 wxPoint sizeObj
= obj
->GetSize(&objTopHeight
, &objBottomHeight
);
1114 if(cursorPos
&& ! cursorFound
)
1116 // we need to check whether the text cursor is here
1117 len
= obj
->GetLength();
1118 if(count
<= cx
&& count
+len
> cx
)
1120 if(obj
->GetType() == WXLO_TYPE_TEXT
)
1122 len
= cx
- count
; // pos in object
1123 CoordType width
, height
, descent
;
1124 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
1125 &width
, &height
, &descent
);
1126 cursorPos
->x
+= width
;
1127 cursorPos
->y
= m_Position
.y
;
1129 if(len
< obj
->GetLength())
1130 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
1132 str
= WXLO_CURSORCHAR
;
1133 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
1134 wxASSERT(cursorSize
);
1135 // Just in case some joker inserted an empty string object:
1136 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
1137 if(height
== 0) height
= sizeObj
.y
;
1138 cursorSize
->x
= width
;
1139 cursorSize
->y
= height
;
1140 cursorFound
= true; // no more checks
1144 // on some other object
1145 CoordType top
, bottom
; // unused
1146 *cursorSize
= obj
->GetSize(&top
,&bottom
);
1147 cursorPos
->y
= m_Position
.y
;
1148 cursorFound
= true; // no more checks
1154 cursorPos
->x
+= obj
->GetWidth();
1158 m_Width
+= sizeObj
.x
;
1159 if(sizeObj
.y
> m_Height
)
1161 m_Height
= sizeObj
.y
;
1164 if(objTopHeight
> topHeight
)
1165 topHeight
= objTopHeight
;
1166 if(objBottomHeight
> bottomHeight
)
1167 bottomHeight
= objBottomHeight
;
1172 if ( updateHeight
< m_Height
)
1173 updateHeight
= m_Height
;
1174 if ( updateWidth
< m_Width
)
1175 updateWidth
= m_Width
;
1177 // update all line if we don't know where to start from
1178 if ( updateLeft
== -1 )
1181 llist
->SetUpdateRect(updateLeft
, updateTop
);
1182 llist
->SetUpdateRect(updateLeft
+ updateWidth
+ MSW_CORRECTION
,
1183 updateTop
+ updateHeight
+ MSW_CORRECTION
);
1186 if(topHeight
+ bottomHeight
> m_Height
)
1188 m_Height
= topHeight
+bottomHeight
;
1191 m_BaseLine
= topHeight
;
1195 CoordType width
, height
, descent
;
1196 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1198 m_BaseLine
= m_Height
- descent
;
1201 // tell next line about coordinate change
1202 if(m_Next
&& m_Height
!= heightOld
)
1204 // FIXME isn't this done in RecalculatePositions() below anyhow?
1205 m_Next
->RecalculatePositions(0, llist
);
1208 // We need to check whether we found a valid cursor size:
1211 // this might be the case if the cursor is at the end of the
1212 // line or on a command object:
1213 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
1215 CoordType width
, height
, descent
;
1216 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1217 cursorSize
->x
= width
;
1218 cursorSize
->y
= height
;
1220 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
1221 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
1223 RecalculatePositions(1, llist
);
1229 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
1231 wxASSERT(xpos
>= 0);
1235 /* If we are at the begin of a line, we want to move all other
1236 lines down and stay with the cursor where we are. However, if we
1237 are in an empty line, we want to move down with it. */
1238 if(xpos
== 0 && GetLength() > 0)
1239 { // insert an empty line before this one
1240 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
1241 if(m_Previous
== NULL
)
1242 { // We were in first line, need to link in new empty line
1244 prev
->m_Next
= this;
1246 m_Previous
->m_Height
= 0; // this is a wild guess
1249 m_Next
->RecalculatePositions(1, llist
);
1254 wxLOiterator i
= FindObject(xpos
, &offset
);
1256 // must be at the end of the line then
1257 return new wxLayoutLine(this, llist
);
1260 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
1261 // split object at i:
1262 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
1264 wxString left
, right
;
1265 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
1266 left
= tobj
->GetText().substr(0,offset
);
1267 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
1268 // current text object gets set to left half
1269 tobj
->GetText() = left
; // set new text
1270 newLine
->Append(new wxLayoutObjectText(right
));
1271 m_Length
-= right
.Length();
1272 i
++; // don't move this object to the new list
1277 i
++; // move objects from here to new list
1280 while(i
!= m_ObjectList
.end())
1282 wxLayoutObject
*obj
= *i
;
1283 newLine
->Append(obj
);
1284 m_Length
-= obj
->GetLength();
1286 m_ObjectList
.remove(i
); // remove without deleting it
1289 m_Next
->RecalculatePositions(2, llist
);
1295 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
1297 wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
1298 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
1301 MarkDirty(GetWidth());
1303 wxLayoutObject
*last
= NULL
;
1304 for(i
= list
.begin(); i
!= list
.end();)
1306 wxLayoutObject
*current
= *i
;
1308 // merge text objects together for efficiency
1309 if ( last
&& last
->GetType() == WXLO_TYPE_TEXT
&&
1310 current
->GetType() == WXLO_TYPE_TEXT
)
1312 wxLayoutObjectText
*textObj
= (wxLayoutObjectText
*)last
;
1313 wxString
text(textObj
->GetText());
1314 text
+= ((wxLayoutObjectText
*)current
)->GetText();
1315 textObj
->SetText(text
);
1317 list
.erase(i
); // remove and delete it
1321 // just append the object "as was"
1324 list
.remove(i
); // remove without deleting it
1327 wxASSERT(list
.empty());
1329 wxLayoutLine
*oldnext
= GetNextLine();
1330 wxLayoutLine
*nextLine
= oldnext
->GetNextLine();
1334 nextLine
->MoveLines(-1);
1338 // this is now done in Delete(), but if this function is ever called
1339 // from elsewhere, we might have to move refresh code back here (in
1340 // order not to duplicate it)
1342 wxPoint
pos(oldnext
->GetPosition());
1343 llist
->SetUpdateRect(pos
);
1344 llist
->SetUpdateRect(pos
.x
+ oldnext
->GetWidth() + MSW_CORRECTION
,
1345 pos
.y
+ oldnext
->GetHeight() + MSW_CORRECTION
);
1353 wxLayoutLine::GetWrapPosition(CoordType column
)
1356 wxLOiterator i
= FindObject(column
, &offset
);
1357 if(i
== NULLIT
) return -1; // cannot wrap
1359 // go backwards through the list and look for space in text objects
1362 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1366 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1373 }while(offset
!= -1);
1374 i
--; // move on to previous object
1378 column
-= (**i
).GetLength();
1382 offset
= (**i
).GetLength();
1383 }while(i
!= NULLIT
);
1384 /* If we reached the begin of the list and have more than one
1385 object, that one is longer than the margin, so break behind
1388 i
= m_ObjectList
.begin();
1389 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1391 pos
+= (**i
).GetLength();
1394 if(i
== NULLIT
) return -1; //why should this happen?
1395 pos
+= (**i
).GetLength();
1397 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1399 pos
+= (**i
).GetLength();
1402 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1403 // now we are at the second text object:
1404 pos
-= (**i
).GetLength();
1405 return pos
; // in front of it
1409 #ifdef WXLAYOUT_DEBUG
1411 wxLayoutLine::Debug(void)
1414 wxPoint pos
= GetPosition();
1415 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d",
1416 (long int) GetLineNumber(),
1417 (long int) pos
.x
, (long int) pos
.y
,
1418 (long int) GetHeight(),
1419 (long int) m_BaseLine
,
1420 (int) m_StyleInfo
.family
));
1421 if(m_ObjectList
.begin() != NULLIT
)
1422 (**m_ObjectList
.begin()).Debug();
1428 wxLayoutLine::Copy(wxLayoutList
*llist
,
1432 CoordType firstOffset
, lastOffset
;
1434 if(to
== -1) to
= GetLength();
1435 if(from
== to
) return;
1437 wxLOiterator first
= FindObject(from
, &firstOffset
);
1438 wxLOiterator last
= FindObject(to
, &lastOffset
);
1440 // Common special case: only one object
1441 if( first
!= NULLIT
&& last
!= NULLIT
&& *first
== *last
)
1443 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1445 llist
->Insert(new wxLayoutObjectText(
1446 ((wxLayoutObjectText
1447 *)*first
)->GetText().substr(firstOffset
,
1448 lastOffset
-firstOffset
))
1452 else // what can we do?
1454 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1455 llist
->Insert( (**first
).Copy() );
1460 // If we reach here, we can safely copy the whole first object from
1461 // the firstOffset position on:
1462 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1464 llist
->Insert(new wxLayoutObjectText(
1465 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1468 else if(firstOffset
== 0)
1469 llist
->Insert( (**first
).Copy() );
1470 // else nothing to copy :-(
1472 // Now we copy all objects before the last one:
1473 wxLOiterator i
= first
; i
++;
1474 for( ; i
!= last
; i
++)
1475 llist
->Insert( (**i
).Copy() );
1477 // And now the last object:
1480 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1482 llist
->Insert(new wxLayoutObjectText(
1483 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1487 llist
->Insert( (**last
).Copy() );
1492 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1494 The wxLayoutList object
1496 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1498 wxLayoutList::wxLayoutList()
1500 #ifdef WXLAYOUT_USE_CARET
1502 #endif // WXLAYOUT_USE_CARET
1505 InvalidateUpdateRect();
1509 wxLayoutList::~wxLayoutList()
1512 m_FirstLine
->DeleteLine(false, this);
1516 wxLayoutList::Empty(void)
1519 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1521 m_CursorPos
= wxPoint(0,0);
1522 m_CursorScreenPos
= wxPoint(0,0);
1523 m_CursorSize
= wxPoint(0,0);
1524 m_movedCursor
= true;
1525 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1526 m_CursorLine
= m_FirstLine
;
1527 InvalidateUpdateRect();
1532 wxLayoutList::InternalClear(void)
1535 m_Selection
.m_selecting
= false;
1536 m_Selection
.m_valid
= false;
1538 m_DefaultStyleInfo
.family
= wxSWISS
;
1539 m_DefaultStyleInfo
.size
= WXLO_DEFAULTFONTSIZE
;
1540 m_DefaultStyleInfo
.style
= wxNORMAL
;
1541 m_DefaultStyleInfo
.weight
= wxNORMAL
;
1542 m_DefaultStyleInfo
.underline
= 0;
1543 m_DefaultStyleInfo
.m_fg_valid
= TRUE
;
1544 m_DefaultStyleInfo
.m_fg
= *wxBLACK
;
1545 m_DefaultStyleInfo
.m_bg_valid
= TRUE
;
1546 m_DefaultStyleInfo
.m_bg
= *wxWHITE
;
1548 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1552 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1553 int underline
, wxColour
*fg
,
1556 if(family
!= -1) m_CurrentStyleInfo
.family
= family
;
1557 if(size
!= -1) m_CurrentStyleInfo
.size
= size
;
1558 if(style
!= -1) m_CurrentStyleInfo
.style
= style
;
1559 if(weight
!= -1) m_CurrentStyleInfo
.weight
= weight
;
1560 if(underline
!= -1) m_CurrentStyleInfo
.underline
= underline
!= 0;
1561 if(fg
) m_CurrentStyleInfo
.m_fg
= *fg
;
1562 if(bg
) m_CurrentStyleInfo
.m_bg
= *bg
;
1564 new wxLayoutObjectCmd(
1565 m_CurrentStyleInfo
.family
,
1566 m_CurrentStyleInfo
.size
,
1567 m_CurrentStyleInfo
.style
,
1568 m_CurrentStyleInfo
.weight
,
1569 m_CurrentStyleInfo
.underline
,
1574 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1575 int underline
, char const *fg
, char const *bg
)
1583 cfg
= wxTheColourDatabase
->FindColour(fg
);
1585 cbg
= wxTheColourDatabase
->FindColour(bg
);
1587 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1591 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1592 int underline
, wxColour
*fg
, wxColour
*bg
)
1595 m_DefaultStyleInfo
= wxLayoutStyleInfo(family
, size
, style
, weight
,
1597 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1601 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1606 for(line
= m_FirstLine
;
1608 line
= line
->GetNextLine())
1610 if(line
->GetLineNumber() >= cpos
.y
)
1612 xpos
= line
->FindText(needle
,
1613 (line
->GetLineNumber() == cpos
.y
) ?
1616 return wxPoint(xpos
, line
->GetLineNumber());
1619 return wxPoint(-1,-1);
1624 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1626 AddCursorPosToUpdateRect();
1628 wxPoint cursorPosOld
= m_CursorPos
;
1630 wxLayoutLine
*line
= m_FirstLine
;
1631 while(line
&& line
->GetLineNumber() != p
.y
)
1632 line
= line
->GetNextLine();
1633 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1635 m_CursorPos
.y
= p
.y
;
1636 m_CursorLine
= line
;
1637 CoordType len
= line
->GetLength();
1640 m_CursorPos
.x
= p
.x
;
1644 m_CursorPos
.x
= len
;
1648 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1650 return m_CursorPos
== p
;
1654 wxLayoutList::MoveCursorVertically(int n
)
1656 AddCursorPosToUpdateRect();
1658 wxPoint cursorPosOld
= m_CursorPos
;
1661 if(n
< 0) // move up
1663 if(m_CursorLine
== m_FirstLine
) return false;
1664 while(n
< 0 && m_CursorLine
)
1666 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1672 m_CursorLine
= m_FirstLine
;
1678 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1679 m_CursorPos
.x
= m_CursorLine
->GetLength();
1685 wxLayoutLine
*last
= m_CursorLine
;
1686 if(! m_CursorLine
->GetNextLine()) return false;
1687 while(n
> 0 && m_CursorLine
)
1691 m_CursorLine
= m_CursorLine
->GetNextLine();
1695 m_CursorLine
= last
;
1701 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1702 m_CursorPos
.x
= m_CursorLine
->GetLength();
1707 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1713 wxLayoutList::MoveCursorHorizontally(int n
)
1715 AddCursorPosToUpdateRect();
1717 wxPoint cursorPosOld
= m_CursorPos
;
1722 if(m_CursorPos
.x
== 0) // at begin of line
1724 if(! MoveCursorVertically(-1))
1726 MoveCursorToEndOfLine();
1731 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1732 m_CursorPos
.x
-= move
; n
+= move
;
1737 int len
= m_CursorLine
->GetLength();
1738 if(m_CursorPos
.x
== len
) // at end of line
1740 if(! MoveCursorVertically(1))
1742 MoveCursorToBeginOfLine();
1747 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1748 m_CursorPos
.x
+= move
;
1752 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1758 wxLayoutList::MoveCursorWord(int n
)
1760 wxCHECK_MSG( m_CursorLine
, false, "no current line" );
1761 wxCHECK_MSG( n
== -1 || n
== +1, false, "not implemented yet" );
1763 CoordType moveDistance
= 0;
1765 for ( wxLOiterator i
= m_CursorLine
->FindObject(m_CursorPos
.x
, &offset
);
1772 wxLayoutObject
*obj
= *i
;
1773 if( obj
->GetType() != WXLO_TYPE_TEXT
)
1775 // any non text objects count as one word
1778 moveDistance
+= obj
->GetLength();
1783 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)obj
;
1785 if ( offset
== tobj
->GetLength() )
1792 const char *start
= tobj
->GetText().c_str();
1793 const char *p
= start
+ offset
;
1795 // to the beginning/end of the next/prev word
1796 while ( isspace(*p
) )
1801 // go to the end/beginning of the word (in a broad sense...)
1802 while ( p
>= start
&& !isspace(*p
) )
1809 // now advance to the beginning of the next word
1810 while ( isspace(*p
) )
1816 moveDistance
= p
- start
- offset
;
1820 // except for the first iteration, offset is 0
1824 MoveCursorHorizontally(moveDistance
);
1830 wxLayoutList::Insert(wxString
const &text
)
1832 wxASSERT(m_CursorLine
);
1833 wxASSERT_MSG( text
.Find('\n') == wxNOT_FOUND
, "use wxLayoutImportText!" );
1838 AddCursorPosToUpdateRect();
1840 if ( !m_CursorLine
->Insert(m_CursorPos
.x
, text
) )
1843 m_CursorPos
.x
+= text
.Length();
1845 m_movedCursor
= true;
1847 m_CursorLine
->RecalculatePositions(0, this);
1853 wxLayoutList::Insert(wxLayoutObject
*obj
)
1855 wxASSERT(m_CursorLine
);
1858 m_CursorLine
= GetFirstLine();
1860 AddCursorPosToUpdateRect();
1862 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1863 m_CursorPos
.x
+= obj
->GetLength();
1864 m_movedCursor
= true;
1866 m_CursorLine
->RecalculatePositions(0, this);
1872 wxLayoutList::Insert(wxLayoutList
*llist
)
1877 for(wxLayoutLine
*line
= llist
->GetFirstLine();
1879 line
= line
->GetNextLine()
1882 for(wxLOiterator i
= line
->GetFirstObject();
1892 wxLayoutList::LineBreak(void)
1894 wxASSERT(m_CursorLine
);
1895 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1897 AddCursorPosToUpdateRect();
1899 wxPoint
position(m_CursorLine
->GetPosition());
1902 width
= m_CursorLine
->GetWidth(),
1903 height
= m_CursorLine
->GetHeight();
1905 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1906 if(setFirst
) // we were at beginning of first line
1907 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1908 if(m_CursorPos
.x
!= 0)
1912 wxLayoutLine
*prev
= m_CursorLine
->GetPreviousLine();
1913 wxCHECK_MSG(prev
, false, "just broke the line, where is the previous one?");
1915 height
+= prev
->GetHeight();
1917 m_movedCursor
= true;
1919 SetUpdateRect(position
);
1920 SetUpdateRect(position
.x
+ width
+ MSW_CORRECTION
,
1921 position
.y
+ height
+ MSW_CORRECTION
);
1927 wxLayoutList::WrapLine(CoordType column
)
1929 if(m_CursorPos
.x
<= column
|| column
< 1)
1930 return false; // do nothing yet
1933 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1935 return false; // cannot break line
1937 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1938 m_CursorPos
.x
= xpos
;
1940 AddCursorPosToUpdateRect();
1943 Delete(1); // delete the space
1944 m_CursorPos
.x
= newpos
;
1946 m_CursorLine
->RecalculatePositions(1, this);
1948 m_movedCursor
= true;
1955 wxLayoutList::Delete(CoordType npos
)
1957 wxCHECK_MSG(m_CursorLine
, false, "can't delete in non existing line");
1962 AddCursorPosToUpdateRect();
1964 // were other lines appended to this one (this is important to know because
1965 // this means that our width _increased_ as the result of deletion)
1966 bool wasMerged
= false;
1968 // the size of the region to update
1969 CoordType totalHeight
= m_CursorLine
->GetHeight(),
1970 totalWidth
= m_CursorLine
->GetWidth();
1975 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1979 // More to delete, continue on next line.
1981 // First, check if line is empty:
1982 if(m_CursorLine
->GetLength() == 0)
1984 // in this case, updating could probably be optimised
1986 wxASSERT(DeleteLines(1) == 0);
1995 // Need to join next line
1996 if(! m_CursorLine
->GetNextLine())
2001 wxLayoutLine
*next
= m_CursorLine
->GetNextLine();
2004 totalHeight
+= next
->GetHeight();
2005 totalWidth
+= next
->GetWidth();
2007 m_CursorLine
->MergeNextLine(this);
2012 wxFAIL_MSG("can't delete all this");
2022 // we need to update the whole tail of the line and the lines which
2026 wxPoint
position(m_CursorLine
->GetPosition());
2027 SetUpdateRect(position
);
2028 SetUpdateRect(position
.x
+ totalWidth
+ MSW_CORRECTION
,
2029 position
.y
+ totalHeight
+ MSW_CORRECTION
);
2036 wxLayoutList::DeleteLines(int n
)
2038 wxASSERT(m_CursorLine
);
2041 AddCursorPosToUpdateRect();
2045 if(!m_CursorLine
->GetNextLine())
2046 { // we cannot delete this line, but we can clear it
2047 MoveCursorToBeginOfLine();
2048 DeleteToEndOfLine();
2049 m_CursorLine
->RecalculatePositions(2, this);
2053 line
= m_CursorLine
;
2054 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
2056 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
2057 wxASSERT(m_FirstLine
);
2058 wxASSERT(m_CursorLine
);
2060 m_CursorLine
->RecalculatePositions(2, this);
2065 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
2067 wxLayoutLine
*line
= m_FirstLine
;
2069 // first, make sure everything is calculated - this might not be
2070 // needed, optimise it later
2071 ApplyStyle(m_DefaultStyleInfo
, dc
);
2074 line
->RecalculatePosition(this); // so we don't need to do it all the time
2075 // little condition to speed up redrawing:
2076 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2077 line
= line
->GetNextLine();
2082 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
)
2084 wxCHECK_RET( m_CursorLine
, "no cursor line" );
2086 // we need to save the current style, in case the layout() of the line
2088 wxLayoutStyleInfo SiBackup
= m_CurrentStyleInfo
;
2089 m_CursorLine
->Layout(dc
, this,
2090 &m_CursorScreenPos
, &m_CursorSize
,
2092 true /* suppress update */);
2093 ApplyStyle(SiBackup
, dc
); // restore it
2097 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
2099 UpdateCursorScreenPos(dc
);
2101 return m_CursorScreenPos
;
2105 Is called before each Draw(). Now, it will re-layout all lines which
2109 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
, bool forceAll
,
2110 wxPoint
*cpos
, wxPoint
*csize
)
2112 // first, make sure everything is calculated - this might not be
2113 // needed, optimise it later
2114 ApplyStyle(m_DefaultStyleInfo
, dc
);
2116 // This one we always Layout() to get the current cursor
2117 // coordinates on the screen:
2118 m_CursorLine
->MarkDirty();
2119 bool wasDirty
= false;
2120 wxLayoutLine
*line
= m_FirstLine
;
2124 ApplyStyle(line
->GetStyleInfo(), dc
);
2125 if(forceAll
|| line
->IsDirty()
2126 || (cpos
&& line
->GetLineNumber() == cpos
->y
))
2128 // The following Layout() calls will update our
2129 // m_CurrentStyleInfo if needed.
2130 if(line
== m_CursorLine
)
2131 line
->Layout(dc
, this,
2132 (wxPoint
*)&m_CursorScreenPos
,
2133 (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
2134 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2135 line
->Layout(dc
, this,
2139 line
->Layout(dc
, this);
2140 // little condition to speed up redrawing:
2141 if(bottom
!= -1 && line
->GetPosition().y
> bottom
)
2145 line
->RecalculatePositions(1, this);
2146 line
= line
->GetNextLine();
2149 // can only be 0 if we are on the first line and have no next line
2150 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
2151 m_CursorLine
->GetNextLine() == NULL
&&
2152 m_CursorLine
== m_FirstLine
));
2153 AddCursorPosToUpdateRect();
2157 wxLayoutList::GetScreenPos(wxDC
&dc
, const wxPoint
&cpos
, wxPoint
*csize
)
2160 Layout(dc
, -1, false, &pos
, csize
);
2165 wxLayoutList::Draw(wxDC
&dc
,
2166 wxPoint
const &offset
,
2170 wxLayoutLine
*line
= m_FirstLine
;
2172 /* We need to re-layout all dirty lines to update styleinfos
2173 etc. However, somehow we don't find all dirty lines... */
2174 Layout(dc
); //,-1,true); //FIXME
2175 ApplyStyle(m_DefaultStyleInfo
, dc
);
2176 wxBrush
brush(m_CurrentStyleInfo
.m_bg
, wxSOLID
);
2178 dc
.SetBackgroundMode(wxTRANSPARENT
);
2180 bool style_set
= false;
2183 // only draw if between top and bottom:
2185 line
->GetPosition().y
+ line
->GetHeight() >= top
))
2189 ApplyStyle(line
->GetStyleInfo(), dc
);
2192 line
->Draw(dc
, this, offset
);
2196 line
->Layout(dc
, this);
2198 // little condition to speed up redrawing:
2199 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2200 line
= line
->GetNextLine();
2202 InvalidateUpdateRect();
2204 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
2205 m_Selection
.m_valid
? "valid" : "invalid",
2206 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
2207 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
2211 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
2215 // First, find the right line:
2216 wxLayoutLine
*line
= m_FirstLine
;
2219 ApplyStyle(m_DefaultStyleInfo
, dc
);
2222 p
= line
->GetPosition();
2223 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
2226 // we need to run a layout here to get font sizes right :-(
2228 // VZ: we can't call Layout() from here because it marks the line as
2229 // clean and it is not refreshed when it's called from wxLayoutList::
2230 // Layout() - if we really need to do this, we should introduce an
2231 // extra argument to Layout() to prevent the line from MarkClean()ing
2233 line
->Layout(dc
, this);
2235 line
= line
->GetNextLine();
2239 if(found
) *found
= false;
2240 return NULL
; // not found
2242 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
2243 // Now, find the object in the line:
2244 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
2245 cursorPos
? & cursorPos
->x
: NULL
,
2247 return (i
== NULLIT
) ? NULL
: *i
;
2252 wxLayoutList::GetSize(void) const
2255 *line
= m_FirstLine
,
2258 return wxPoint(0,0);
2260 wxPoint
maxPoint(0,0);
2265 if(line
->GetWidth() > maxPoint
.x
)
2266 maxPoint
.x
= line
->GetWidth();
2268 line
= line
->GetNextLine();
2271 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
2273 // if the line was just added, its height would be 0 and we can't call
2274 // Layout() from here because we don't have a dc and we might be not drawing
2275 // at all, besides... So take the cursor height by default (taking 0 is bad
2276 // because then the scrollbars won't be resized and the new line won't be
2278 if ( last
->IsDirty() )
2280 if ( last
->GetHeight() == 0 )
2281 maxPoint
.y
+= m_CursorSize
.y
;
2282 if ( last
->GetWidth() == 0 && maxPoint
.x
< m_CursorSize
.x
)
2283 maxPoint
.x
= m_CursorSize
.x
;
2291 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
2293 if ( m_movedCursor
)
2295 UpdateCursorScreenPos(dc
);
2297 m_movedCursor
= false;
2300 wxPoint
coords(m_CursorScreenPos
);
2301 coords
+= translate
;
2303 #ifdef WXLAYOUT_DEBUG
2304 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
2305 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
2306 (long)coords
.x
, (long)coords
.y
,
2307 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
2308 (long)m_CursorLine
->GetLineNumber(),
2309 (long)m_CursorLine
->GetLength()));
2311 wxLogStatus("Cursor is at (%d, %d)", m_CursorPos
.x
, m_CursorPos
.y
);
2314 #ifdef WXLAYOUT_USE_CARET
2315 m_caret
->Move(coords
);
2316 #else // !WXLAYOUT_USE_CARET
2317 dc
.SetBrush(*wxBLACK_BRUSH
);
2318 dc
.SetLogicalFunction(wxXOR
);
2319 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
2322 dc
.DrawRectangle(coords
.x
, coords
.y
,
2323 m_CursorSize
.x
, m_CursorSize
.y
);
2324 SetUpdateRect(coords
.x
, coords
.y
);
2325 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
2329 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
2330 coords
.x
, coords
.y
);
2331 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
2332 SetUpdateRect(coords
.x
, coords
.y
);
2334 dc
.SetLogicalFunction(wxCOPY
);
2335 //dc.SetBrush(wxNullBrush);
2336 #endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
2340 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
2342 if(m_UpdateRectValid
)
2343 GrowRect(m_UpdateRect
, x
, y
);
2348 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
2349 m_UpdateRect
.height
= 4;// wxGTK :-)
2350 m_UpdateRectValid
= true;
2355 wxLayoutList::StartSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2357 wxPoint
cpos(cposOrig
);
2360 WXLO_DEBUG(("Starting selection at %ld/%ld", cpos
.x
, cpos
.y
));
2361 m_Selection
.m_CursorA
= cpos
;
2362 m_Selection
.m_CursorB
= cpos
;
2363 m_Selection
.m_ScreenA
= spos
;
2364 m_Selection
.m_ScreenB
= spos
;
2365 m_Selection
.m_selecting
= true;
2366 m_Selection
.m_valid
= false;
2370 wxLayoutList::ContinueSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2372 wxPoint
cpos(cposOrig
);
2376 wxASSERT(m_Selection
.m_selecting
== true);
2377 wxASSERT(m_Selection
.m_valid
== false);
2378 WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos
.x
, cpos
.y
));
2380 if ( m_Selection
.m_CursorB
<= cpos
)
2382 m_Selection
.m_ScreenB
= spos
;
2383 m_Selection
.m_CursorB
= cpos
;
2387 m_Selection
.m_ScreenA
= spos
;
2388 m_Selection
.m_CursorA
= cpos
;
2391 // we always want m_CursorA <= m_CursorB!
2392 if( m_Selection
.m_CursorA
> m_Selection
.m_CursorB
)
2394 // exchange the start/end points
2395 wxPoint help
= m_Selection
.m_CursorB
;
2396 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
2397 m_Selection
.m_CursorA
= help
;
2399 help
= m_Selection
.m_ScreenB
;
2400 m_Selection
.m_ScreenB
= m_Selection
.m_ScreenA
;
2401 m_Selection
.m_ScreenA
= help
;
2406 wxLayoutList::EndSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2408 wxPoint
cpos(cposOrig
);
2411 ContinueSelection(cpos
);
2412 WXLO_DEBUG(("Ending selection at %ld/%ld", cpos
.x
, cpos
.y
));
2413 m_Selection
.m_selecting
= false;
2414 m_Selection
.m_valid
= true;
2418 wxLayoutList::DiscardSelection()
2420 if ( !HasSelection() )
2423 m_Selection
.m_valid
=
2424 m_Selection
.m_selecting
= false;
2426 // invalidate the area which was previousle selected - and which is not
2427 // selected any more
2428 if ( m_Selection
.HasValidScreenCoords() )
2430 SetUpdateRect(m_Selection
.m_ScreenA
);
2431 SetUpdateRect(m_Selection
.m_ScreenB
);
2440 wxLayoutList::IsSelecting(void)
2442 return m_Selection
.m_selecting
;
2446 wxLayoutList::IsSelected(const wxPoint
&cursor
)
2448 if ( !HasSelection() )
2451 return m_Selection
.m_CursorA
<= cursor
&& cursor
<= m_Selection
.m_CursorB
;
2455 /** Tests whether this layout line is selected and needs
2457 @param line to test for
2458 @return 0 = not selected, 1 = fully selected, -1 = partially
2462 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
2465 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
2467 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
2470 CoordType y
= line
->GetLineNumber();
2471 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
2473 else if(m_Selection
.m_CursorA
.y
== y
)
2475 *from
= m_Selection
.m_CursorA
.x
;
2476 if(m_Selection
.m_CursorB
.y
== y
)
2477 *to
= m_Selection
.m_CursorB
.x
;
2479 *to
= line
->GetLength();
2482 else if(m_Selection
.m_CursorB
.y
== y
)
2484 *to
= m_Selection
.m_CursorB
.x
;
2485 if(m_Selection
.m_CursorA
.y
== y
)
2486 *from
= m_Selection
.m_CursorA
.x
;
2496 wxLayoutList::DeleteSelection(void)
2498 if(! m_Selection
.m_valid
)
2501 m_Selection
.m_valid
= false;
2503 // Only delete part of the current line?
2504 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
2506 MoveCursorTo(m_Selection
.m_CursorA
);
2507 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
2516 for(firstLine
= m_FirstLine
;
2517 firstLine
&& firstLine
->GetLineNumber() < m_Selection
.m_CursorA
.y
;
2518 firstLine
=firstLine
->GetNextLine())
2520 if(!firstLine
|| firstLine
->GetLineNumber() != m_Selection
.m_CursorA
.y
)
2524 for(lastLine
= m_FirstLine
;
2525 lastLine
&& lastLine
->GetLineNumber() < m_Selection
.m_CursorB
.y
;
2526 lastLine
=lastLine
->GetNextLine())
2528 if(!lastLine
|| lastLine
->GetLineNumber() != m_Selection
.m_CursorB
.y
)
2532 // We now know that the two lines are different:
2534 // First, delete what's left of this line:
2535 MoveCursorTo(m_Selection
.m_CursorA
);
2536 DeleteToEndOfLine();
2538 wxLayoutLine
*nextLine
= firstLine
->GetNextLine();
2539 while(nextLine
&& nextLine
!= lastLine
)
2540 nextLine
= nextLine
->DeleteLine(false, this);
2542 // Now nextLine = lastLine;
2543 Delete(1); // This joins firstLine and nextLine
2544 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x
2548 firstLine
->RecalculatePositions(1, this);
2551 /// Starts highlighting the selection
2553 wxLayoutList::StartHighlighting(wxDC
&dc
)
2556 dc
.SetTextForeground(m_CurrentStyleInfo
.m_bg
);
2557 dc
.SetTextBackground(m_CurrentStyleInfo
.m_fg
);
2558 dc
.SetBackgroundMode(wxSOLID
);
2562 /// Ends highlighting the selection
2564 wxLayoutList::EndHighlighting(wxDC
&dc
)
2567 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2568 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2569 dc
.SetBackgroundMode(wxTRANSPARENT
);
2575 wxLayoutList::Copy(const wxPoint
&from
,
2582 for(firstLine
= m_FirstLine
;
2583 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
2584 firstLine
=firstLine
->GetNextLine())
2586 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
2589 for(lastLine
= m_FirstLine
;
2590 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
2591 lastLine
=lastLine
->GetNextLine())
2593 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
2598 wxLayoutLine
*tmp
= firstLine
;
2599 firstLine
= lastLine
;
2603 wxLayoutList
*llist
= new wxLayoutList();
2605 if(firstLine
== lastLine
)
2607 firstLine
->Copy(llist
, from
.x
, to
.x
);
2611 // Extract objects from first line
2612 firstLine
->Copy(llist
, from
.x
);
2614 // Extract all lines between
2615 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
2617 line
= line
->GetNextLine())
2622 // Extract objects from last line
2623 lastLine
->Copy(llist
, 0, to
.x
);
2629 wxLayoutList::GetSelection(wxLayoutDataObject
*wxlo
, bool invalidate
)
2631 if(! m_Selection
.m_valid
)
2633 if(m_Selection
.m_selecting
)
2639 if(invalidate
) m_Selection
.m_valid
= false;
2641 wxLayoutList
*llist
= Copy( m_Selection
.m_CursorA
,
2642 m_Selection
.m_CursorB
);
2644 if(llist
&& wxlo
) // export as data object, too
2648 wxLayoutExportObject
*export
;
2649 wxLayoutExportStatus
status(llist
);
2650 while((export
= wxLayoutExport( &status
, WXLO_EXPORT_AS_OBJECTS
)) != NULL
)
2652 if(export
->type
== WXLO_EXPORT_EMPTYLINE
)
2653 ; //FIXME missing support for linebreaks in string format
2655 export
->content
.object
->Write(string
);
2659 wxlo
->SetData(string
.c_str(), string
.Length()+1);
2666 #define COPY_SI(what) if(si.what != -1) { m_CurrentStyleInfo.what = si.what; fontChanged = TRUE; }
2669 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
const &si
, wxDC
&dc
)
2671 bool fontChanged
= FALSE
;
2678 dc
.SetFont( m_FontCache
.GetFont(m_CurrentStyleInfo
) );
2682 m_CurrentStyleInfo
.m_fg
= si
.m_fg
;
2683 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2687 m_CurrentStyleInfo
.m_bg
= si
.m_bg
;
2688 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2693 #ifdef WXLAYOUT_DEBUG
2696 wxLayoutList::Debug(void)
2698 WXLO_DEBUG(("Cursor is in line %d, screen pos = (%d, %d)",
2699 m_CursorLine
->GetLineNumber(),
2700 m_CursorScreenPos
.x
, m_CursorScreenPos
.y
));
2703 for(line
= m_FirstLine
; line
; line
= line
->GetNextLine())
2712 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2716 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2718 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2719 wxString
const & title
)
2724 // remove any highlighting which could interfere with printing:
2725 m_llist
->StartSelection();
2726 m_llist
->EndSelection();
2729 wxLayoutPrintout::~wxLayoutPrintout()
2734 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2736 // The following bit is taken from the printing sample, let's see
2737 // whether it works for us.
2739 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2740 * the screen text size. This page also draws lines of actual length 5cm
2743 // Get the logical pixels per inch of screen and printer
2744 int ppiScreenX
, ppiScreenY
;
2745 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2746 int ppiPrinterX
, ppiPrinterY
;
2747 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2749 if(ppiScreenX
== 0) // not yet set, need to guess
2754 if(ppiPrinterX
== 0) // not yet set, need to guess
2760 // This scales the DC so that the printout roughly represents the
2761 // the screen scaling. The text point size _should_ be the right size
2762 // but in fact is too small for some reason. This is a detail that will
2763 // need to be addressed at some point but can be fudged for the
2765 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2767 // Now we have to check in case our real page size is reduced
2768 // (e.g. because we're drawing to a print preview memory DC)
2769 int pageWidth
, pageHeight
;
2771 dc
->GetSize(&w
, &h
);
2772 GetPageSizePixels(&pageWidth
, &pageHeight
);
2773 if(pageWidth
!= 0) // doesn't work always
2775 // If printer pageWidth == current DC width, then this doesn't
2776 // change. But w might be the preview bitmap width, so scale down.
2777 scale
= scale
* (float)(w
/(float)pageWidth
);
2779 dc
->SetUserScale(scale
, scale
);
2783 bool wxLayoutPrintout::OnPrintPage(int page
)
2792 top
= (page
- 1)*m_PrintoutHeight
;
2793 bottom
= top
+ m_PrintoutHeight
;
2794 // SetDeviceOrigin() doesn't work here, so we need to manually
2795 // translate all coordinates.
2796 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2797 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2804 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2806 /* We allocate a temporary wxDC for printing, so that we can
2807 determine the correct paper size and scaling. We don't actually
2808 print anything on it. */
2810 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2812 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2815 float scale
= ScaleDC(&psdc
);
2817 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2818 // This sets a left/top origin of 15% and 20%:
2819 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
2821 // This is the length of the printable area.
2822 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
2823 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2827 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2830 *maxPage
= m_NumOfPages
;
2833 *selPageTo
= m_NumOfPages
;
2834 wxRemoveFile(WXLLIST_TEMPFILE
);
2837 bool wxLayoutPrintout::HasPage(int pageNum
)
2839 return pageNum
<= m_NumOfPages
;
2843 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2844 out. It's a waste of paper anyway.
2848 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2849 wxPoint topleft
, wxPoint bottomright
,
2852 // make backups of all essential parameters
2853 const wxBrush
& brush
= dc
.GetBrush();
2854 const wxPen
& pen
= dc
.GetPen();
2855 const wxFont
& font
= dc
.GetFont();
2857 dc
.SetBrush(*wxWHITE_BRUSH
);
2858 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
2859 dc
.DrawRoundedRectangle(topleft
.x
,
2860 topleft
.y
,bottomright
.x
-topleft
.x
,
2861 bottomright
.y
-topleft
.y
);
2862 dc
.SetBrush(*wxBLACK_BRUSH
);
2863 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
2864 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
2868 page
= "9999/9999 "; // many pages...
2870 dc
.GetTextExtent(page
,&w
,&h
);
2871 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
2872 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
2873 dc
.GetTextExtent("XXXX", &w
,&h
);
2874 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
2885 wxFontCache::GetFont(int family
, int size
, int style
, int weight
,
2888 for(wxFCEList::iterator i
= m_FontList
.begin();
2889 i
!= m_FontList
.end(); i
++)
2890 if( (**i
).Matches(family
, size
, style
, weight
, underline
) )
2891 return (**i
).GetFont();
2893 wxFontCacheEntry
*fce
= new wxFontCacheEntry(family
, size
, style
,
2895 m_FontList
.push_back(fce
);
2896 return fce
->GetFont();