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_bg_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
);
646 m_StyleInfo
= llist
->GetDefaultStyleInfo();
648 llist
->IncNumLines();
651 wxLayoutLine::~wxLayoutLine()
653 // kbList cleans itself
657 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
659 wxASSERT(m_Previous
|| GetLineNumber() == 0);
661 wxPoint
posOld(m_Position
);
665 m_Position
= m_Previous
->GetPosition();
666 m_Position
.y
+= m_Previous
->GetHeight();
669 m_Position
= wxPoint(0,0);
671 if ( m_Position
!= posOld
)
673 // the whole line moved and must be repainted
674 llist
->SetUpdateRect(m_Position
);
675 llist
->SetUpdateRect(m_Position
.x
+ GetWidth() + MSW_CORRECTION
,
676 m_Position
.y
+ GetHeight() + MSW_CORRECTION
);
677 llist
->SetUpdateRect(posOld
);
678 llist
->SetUpdateRect(posOld
.x
+ GetWidth() + MSW_CORRECTION
,
679 posOld
.y
+ GetHeight() + MSW_CORRECTION
);
686 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
688 //FIXME: is this really needed? We run Layout() anyway.
689 // Recursing here, drives computation time up exponentially, as
690 // each line will cause all following lines to be recalculated.
691 // Yes, or linenumbers go wrong.
693 wxASSERT(recurse
>= 0);
694 wxPoint pos
= m_Position
;
695 CoordType height
= m_Height
;
697 // WXLO_TRACE("RecalculatePositions()");
698 RecalculatePosition(llist
);
702 m_Next
->RecalculatePositions(--recurse
, llist
);
703 else if(pos
!= m_Position
|| m_Height
!= height
)
704 m_Next
->RecalculatePositions(0, llist
);
708 wxLayoutObjectList::iterator
709 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
713 wxLayoutObjectList::iterator
716 CoordType x
= 0, len
;
718 /* We search through the objects. As we don't like returning the
719 object that the cursor is behind, we just remember such an
720 object in "found" so we can return it if there is really no
721 further object following it. */
722 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
724 len
= (**i
).GetLength();
725 if( x
<= xpos
&& xpos
<= x
+ len
)
728 if(xpos
== x
+ len
) // is there another object behind?
730 else // we are really inside this object
733 x
+= (**i
).GetLength();
735 return found
; // ==NULL if really none found
738 wxLayoutObjectList::iterator
739 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
740 CoordType xpos
, CoordType
*cxpos
,
745 wxLayoutObjectList::iterator i
;
746 CoordType x
= 0, cx
= 0, width
;
748 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
750 width
= (**i
).GetWidth();
751 if( x
<= xpos
&& xpos
<= x
+ width
)
753 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
754 if(found
) *found
= true;
757 x
+= (**i
).GetWidth();
758 cx
+= (**i
).GetLength();
760 // behind last object:
762 if(found
) *found
= false;
763 return m_ObjectList
.tail();
766 /** Finds text in this line.
767 @param needle the text to find
768 @param xpos the position where to start the search
769 @return the cursoor coord where it was found or -1
772 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
) const
777 wxString
const *text
;
779 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
781 if(cpos
>= xpos
) // search from here!
783 if((**i
).GetType() == WXLO_TYPE_TEXT
)
785 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
786 relpos
= text
->Find(needle
);
787 if(relpos
>= cpos
-xpos
) // -1 if not found
792 cpos
+= (**i
).GetLength();
795 return -1; // not found
799 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
802 wxASSERT(obj
!= NULL
);
806 // If we insert a command object, we need to recalculate all lines
807 // to update their styleinfo structure.
808 if(obj
->GetType() == WXLO_TYPE_CMD
)
812 wxLOiterator i
= FindObject(xpos
, &offset
);
815 if(xpos
== 0 ) // aha, empty line!
817 m_ObjectList
.push_back(obj
);
818 m_Length
+= obj
->GetLength();
825 CoordType len
= (**i
).GetLength();
826 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
827 { // insert before this object
828 m_ObjectList
.insert(i
,obj
);
829 m_Length
+= obj
->GetLength();
834 if( i
== m_ObjectList
.tail()) // last object?
835 m_ObjectList
.push_back(obj
);
837 { // insert after current object
839 m_ObjectList
.insert(i
,obj
);
841 m_Length
+= obj
->GetLength();
844 /* Otherwise we need to split the current object.
845 Fortunately this can only be a text object. */
846 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
847 wxString left
, right
;
848 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
849 left
= tobj
->GetText().substr(0,offset
);
850 right
= tobj
->GetText().substr(offset
,len
-offset
);
851 // current text object gets set to right half
852 tobj
->GetText() = right
; // set new text
853 // before it we insert the new object
854 m_ObjectList
.insert(i
,obj
);
855 m_Length
+= obj
->GetLength();
856 // and before that we insert the left half
857 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
862 wxLayoutLine::Insert(CoordType xpos
, const wxString
& text
)
869 wxLOiterator i
= FindObject(xpos
, &offset
);
870 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
872 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
873 tobj
->GetText().insert(offset
, text
);
874 m_Length
+= text
.Length();
878 if ( !Insert(xpos
, new wxLayoutObjectText(text
)) )
886 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
888 CoordType offset
, len
;
893 wxLOiterator i
= FindObject(xpos
, &offset
);
896 if(i
== NULLIT
) return npos
;
897 // now delete from that object:
898 if((**i
).GetType() != WXLO_TYPE_TEXT
)
900 if(offset
!= 0) // at end of line after a non-text object
903 len
= (**i
).GetLength();
906 // If we delete a command object, we need to recalculate all lines
907 // to update their styleinfo structure.
908 if((**i
).GetType() == WXLO_TYPE_CMD
)
910 m_ObjectList
.erase(i
);
914 // tidy up: remove empty text objects
915 if((**i
).GetLength() == 0)
917 m_ObjectList
.erase(i
);
921 CoordType max
= (**i
).GetLength() - offset
;
922 if(npos
< max
) max
= npos
;
925 if(xpos
== GetLength())
928 { // at the end of an object
929 // move to begin of next object:
931 continue; // start over
936 if(offset
== 0 && max
== (**i
).GetLength())
937 m_ObjectList
.erase(i
); // remove the whole object
939 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
947 wxLayoutLine::MarkNextDirty(int recurse
)
949 wxLayoutLine
*line
= GetNextLine();
950 while(line
&& (recurse
== -1 || recurse
>= 0))
953 line
= line
->GetNextLine();
954 if(recurse
> 0) recurse
--;
959 wxLayoutLine::DeleteWord(CoordType xpos
)
965 wxLOiterator i
= FindObject(xpos
, &offset
);
969 if(i
== NULLIT
) return false;
970 if((**i
).GetType() != WXLO_TYPE_TEXT
)
972 // This should only happen when at end of line, behind a non-text
974 if(offset
== (**i
).GetLength()) return false;
975 m_Length
-= (**i
).GetLength(); // -1
976 m_ObjectList
.erase(i
);
977 return true; // we are done
981 if(offset
== (**i
).GetLength()) // at end of object
986 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
988 wxString str
= tobj
->GetText();
989 str
= str
.substr(offset
,str
.Length()-offset
);
990 // Find out how many positions we need to delete:
991 // 1. eat leading space
992 while(isspace(str
.c_str()[count
])) count
++;
993 // 2. eat the word itself:
994 while(isalnum(str
.c_str()[count
])) count
++;
996 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
997 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
1003 wxFAIL_MSG("unreachable");
1007 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
1009 // maintain linked list integrity
1011 m_Next
->m_Previous
= m_Previous
;
1013 m_Previous
->m_Next
= m_Next
;
1017 m_Next
->MoveLines(-1);
1018 m_Next
->RecalculatePositions(1, llist
);
1019 /* We assume that if we have more than one object in the list,
1020 this means that we have a command object, so we need to
1021 update the following lines. */
1022 if(m_ObjectList
.size() > 1 ||
1023 ( m_ObjectList
.begin() != NULLIT
&&
1024 (**m_ObjectList
.begin()).GetType() == WXLO_TYPE_CMD
)
1028 wxLayoutLine
*next
= m_Next
;
1031 llist
->DecNumLines();
1037 wxLayoutLine::Draw(wxDC
&dc
,
1038 wxLayoutList
*llist
,
1039 const wxPoint
& offset
) const
1041 wxLayoutObjectList::iterator i
;
1042 wxPoint pos
= offset
;
1043 pos
= pos
+ GetPosition();
1045 pos
.y
+= m_BaseLine
;
1047 CoordType xpos
= 0; // cursorpos, lenght of line
1049 CoordType from
, to
, tempto
;
1051 int highlight
= llist
->IsSelected(this, &from
, &to
);
1052 // WXLO_DEBUG(("highlight=%d", highlight ));
1053 if(highlight
== 1) // we need to draw the whole line inverted!
1054 llist
->StartHighlighting(dc
);
1056 llist
->EndHighlighting(dc
);
1058 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1060 if(highlight
== -1) // partially highlight line
1062 // parts of the line need highlighting
1063 tempto
= xpos
+(**i
).GetLength();
1064 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, to
-xpos
);
1067 (**i
).Draw(dc
, pos
, llist
);
1068 pos
.x
+= (**i
).GetWidth();
1069 xpos
+= (**i
).GetLength();
1074 This function does all the recalculation, that is, it should only be
1075 called from within wxLayoutList::Layout(), as it uses the current
1076 list's styleinfo and updates it.
1079 wxLayoutLine::Layout(wxDC
&dc
,
1080 wxLayoutList
*llist
,
1082 wxPoint
*cursorSize
,
1083 wxLayoutStyleInfo
*cursorStyle
,
1085 bool suppressSIupdate
)
1087 wxLayoutObjectList::iterator i
;
1089 // when a line becomes dirty, we redraw it from the place where it was
1090 // changed till the end of line (because the following wxLayoutObjects are
1091 // moved when the preceding one changes) - calculate the update rectangle.
1092 CoordType updateTop
= m_Position
.y
,
1094 updateWidth
= m_Width
,
1095 updateHeight
= m_Height
;
1099 bottomHeight
= 0; // above and below baseline
1101 objTopHeight
, objBottomHeight
; // above and below baseline
1105 CoordType heightOld
= m_Height
;
1111 bool cursorFound
= false;
1115 *cursorPos
= m_Position
;
1116 if(cursorSize
) *cursorSize
= wxPoint(0,0);
1119 m_StyleInfo
= llist
->GetStyleInfo(); // save current style
1120 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1122 wxLayoutObject
*obj
= *i
;
1123 obj
->Layout(dc
, llist
);
1124 wxPoint sizeObj
= obj
->GetSize(&objTopHeight
, &objBottomHeight
);
1126 if(cursorPos
&& ! cursorFound
)
1128 // we need to check whether the text cursor is here
1129 len
= obj
->GetLength();
1130 if(count
<= cx
&& count
+len
> cx
)
1132 if(obj
->GetType() == WXLO_TYPE_TEXT
)
1134 len
= cx
- count
; // pos in object
1135 CoordType width
, height
, descent
;
1136 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
1137 &width
, &height
, &descent
);
1138 cursorPos
->x
+= width
;
1139 cursorPos
->y
= m_Position
.y
;
1141 if(len
< obj
->GetLength())
1142 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
1144 str
= WXLO_CURSORCHAR
;
1145 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
1147 if(cursorStyle
) // set style info
1148 *cursorStyle
= llist
->GetStyleInfo();
1151 // Just in case some joker inserted an empty string object:
1153 width
= WXLO_MINIMUM_CURSOR_WIDTH
;
1156 cursorSize
->x
= width
;
1157 cursorSize
->y
= height
;
1160 cursorFound
= true; // no more checks
1164 // on some other object
1165 CoordType top
, bottom
; // unused
1167 *cursorSize
= obj
->GetSize(&top
,&bottom
);
1168 cursorPos
->y
= m_Position
.y
;
1169 cursorFound
= true; // no more checks
1175 cursorPos
->x
+= obj
->GetWidth();
1179 m_Width
+= sizeObj
.x
;
1180 if(sizeObj
.y
> m_Height
)
1182 m_Height
= sizeObj
.y
;
1185 if(objTopHeight
> topHeight
)
1186 topHeight
= objTopHeight
;
1187 if(objBottomHeight
> bottomHeight
)
1188 bottomHeight
= objBottomHeight
;
1193 if ( updateHeight
< m_Height
)
1194 updateHeight
= m_Height
;
1195 if ( updateWidth
< m_Width
)
1196 updateWidth
= m_Width
;
1198 // update all line if we don't know where to start from
1199 if ( updateLeft
== -1 )
1202 llist
->SetUpdateRect(updateLeft
, updateTop
);
1203 llist
->SetUpdateRect(updateLeft
+ updateWidth
+ MSW_CORRECTION
,
1204 updateTop
+ updateHeight
+ MSW_CORRECTION
);
1207 if(topHeight
+ bottomHeight
> m_Height
)
1209 m_Height
= topHeight
+bottomHeight
;
1212 m_BaseLine
= topHeight
;
1216 CoordType width
, height
, descent
;
1217 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1219 m_BaseLine
= m_Height
- descent
;
1222 // tell next line about coordinate change
1223 if(m_Next
&& m_Height
!= heightOld
)
1225 // FIXME isn't this done in RecalculatePositions() below anyhow?
1226 m_Next
->RecalculatePositions(0, llist
);
1229 // We need to check whether we found a valid cursor size:
1230 if(cursorPos
&& cursorSize
)
1232 // this might be the case if the cursor is at the end of the
1233 // line or on a command object:
1234 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
1236 CoordType width
, height
, descent
;
1237 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1238 cursorSize
->x
= width
;
1239 cursorSize
->y
= height
;
1241 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
1242 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
1244 RecalculatePositions(1, llist
);
1250 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
1252 wxASSERT(xpos
>= 0);
1256 /* If we are at the begin of a line, we want to move all other
1257 lines down and stay with the cursor where we are. However, if we
1258 are in an empty line, we want to move down with it. */
1259 if(xpos
== 0 && GetLength() > 0)
1260 { // insert an empty line before this one
1261 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
1262 if(m_Previous
== NULL
)
1263 { // We were in first line, need to link in new empty line
1265 prev
->m_Next
= this;
1267 m_Previous
->m_Height
= 0; // this is a wild guess
1270 m_Next
->RecalculatePositions(1, llist
);
1275 wxLOiterator i
= FindObject(xpos
, &offset
);
1277 // must be at the end of the line then
1278 return new wxLayoutLine(this, llist
);
1281 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
1282 // split object at i:
1283 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
1285 wxString left
, right
;
1286 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
1287 left
= tobj
->GetText().substr(0,offset
);
1288 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
1289 // current text object gets set to left half
1290 tobj
->GetText() = left
; // set new text
1291 newLine
->Append(new wxLayoutObjectText(right
));
1292 m_Length
-= right
.Length();
1293 i
++; // don't move this object to the new list
1298 i
++; // move objects from here to new list
1301 while(i
!= m_ObjectList
.end())
1303 wxLayoutObject
*obj
= *i
;
1304 newLine
->Append(obj
);
1305 m_Length
-= obj
->GetLength();
1307 m_ObjectList
.remove(i
); // remove without deleting it
1310 m_Next
->RecalculatePositions(2, llist
);
1316 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
1318 wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
1319 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
1322 MarkDirty(GetWidth());
1324 wxLayoutObject
*last
= NULL
;
1325 for(i
= list
.begin(); i
!= list
.end();)
1327 wxLayoutObject
*current
= *i
;
1329 // merge text objects together for efficiency
1330 if ( last
&& last
->GetType() == WXLO_TYPE_TEXT
&&
1331 current
->GetType() == WXLO_TYPE_TEXT
)
1333 wxLayoutObjectText
*textObj
= (wxLayoutObjectText
*)last
;
1334 wxString
text(textObj
->GetText());
1335 text
+= ((wxLayoutObjectText
*)current
)->GetText();
1336 textObj
->SetText(text
);
1338 list
.erase(i
); // remove and delete it
1342 // just append the object "as was"
1345 list
.remove(i
); // remove without deleting it
1348 wxASSERT(list
.empty());
1350 wxLayoutLine
*oldnext
= GetNextLine();
1351 wxLayoutLine
*nextLine
= oldnext
->GetNextLine();
1355 nextLine
->MoveLines(-1);
1359 // this is now done in Delete(), but if this function is ever called
1360 // from elsewhere, we might have to move refresh code back here (in
1361 // order not to duplicate it)
1363 wxPoint
pos(oldnext
->GetPosition());
1364 llist
->SetUpdateRect(pos
);
1365 llist
->SetUpdateRect(pos
.x
+ oldnext
->GetWidth() + MSW_CORRECTION
,
1366 pos
.y
+ oldnext
->GetHeight() + MSW_CORRECTION
);
1374 wxLayoutLine::GetWrapPosition(CoordType column
)
1377 wxLOiterator i
= FindObject(column
, &offset
);
1378 if(i
== NULLIT
) return -1; // cannot wrap
1380 // go backwards through the list and look for space in text objects
1383 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1387 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1394 }while(offset
!= -1);
1395 i
--; // move on to previous object
1399 column
-= (**i
).GetLength();
1403 offset
= (**i
).GetLength();
1404 }while(i
!= NULLIT
);
1405 /* If we reached the begin of the list and have more than one
1406 object, that one is longer than the margin, so break behind
1409 i
= m_ObjectList
.begin();
1410 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1412 pos
+= (**i
).GetLength();
1415 if(i
== NULLIT
) return -1; //why should this happen?
1416 pos
+= (**i
).GetLength();
1418 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1420 pos
+= (**i
).GetLength();
1423 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1424 // now we are at the second text object:
1425 pos
-= (**i
).GetLength();
1426 return pos
; // in front of it
1430 #ifdef WXLAYOUT_DEBUG
1432 wxLayoutLine::Debug(void)
1435 wxPoint pos
= GetPosition();
1436 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d",
1437 (long int) GetLineNumber(),
1438 (long int) pos
.x
, (long int) pos
.y
,
1439 (long int) GetHeight(),
1440 (long int) m_BaseLine
,
1441 (int) m_StyleInfo
.family
));
1442 if(m_ObjectList
.begin() != NULLIT
)
1443 (**m_ObjectList
.begin()).Debug();
1449 wxLayoutLine::Copy(wxLayoutList
*llist
,
1453 CoordType firstOffset
, lastOffset
;
1455 if(to
== -1) to
= GetLength();
1456 if(from
== to
) return;
1458 wxLOiterator first
= FindObject(from
, &firstOffset
);
1459 wxLOiterator last
= FindObject(to
, &lastOffset
);
1461 // Common special case: only one object
1462 if( first
!= NULLIT
&& last
!= NULLIT
&& *first
== *last
)
1464 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1466 llist
->Insert(new wxLayoutObjectText(
1467 ((wxLayoutObjectText
1468 *)*first
)->GetText().substr(firstOffset
,
1469 lastOffset
-firstOffset
))
1473 else // what can we do?
1475 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1476 llist
->Insert( (**first
).Copy() );
1481 // If we reach here, we can safely copy the whole first object from
1482 // the firstOffset position on:
1483 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1485 llist
->Insert(new wxLayoutObjectText(
1486 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1489 else if(firstOffset
== 0)
1490 llist
->Insert( (**first
).Copy() );
1491 // else nothing to copy :-(
1493 // Now we copy all objects before the last one:
1494 wxLOiterator i
= first
; i
++;
1495 for( ; i
!= last
; i
++)
1496 llist
->Insert( (**i
).Copy() );
1498 // And now the last object:
1501 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1503 llist
->Insert(new wxLayoutObjectText(
1504 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1508 llist
->Insert( (**last
).Copy() );
1513 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1515 The wxLayoutList object
1517 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1519 wxLayoutList::wxLayoutList()
1521 #ifdef WXLAYOUT_USE_CARET
1523 #endif // WXLAYOUT_USE_CARET
1527 InvalidateUpdateRect();
1531 wxLayoutList::~wxLayoutList()
1534 m_FirstLine
->DeleteLine(false, this);
1536 wxASSERT_MSG( m_numLines
== 0, "line count calculation broken" );
1540 wxLayoutList::Empty(void)
1543 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1545 m_CursorPos
= wxPoint(0,0);
1546 m_CursorScreenPos
= wxPoint(0,0);
1547 m_CursorSize
= wxPoint(0,0);
1548 m_movedCursor
= true;
1549 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1550 m_CursorLine
= m_FirstLine
;
1551 InvalidateUpdateRect();
1556 wxLayoutList::InternalClear(void)
1559 m_Selection
.m_selecting
= false;
1560 m_Selection
.m_valid
= false;
1562 m_DefaultStyleInfo
.family
= wxSWISS
;
1563 m_DefaultStyleInfo
.size
= WXLO_DEFAULTFONTSIZE
;
1564 m_DefaultStyleInfo
.style
= wxNORMAL
;
1565 m_DefaultStyleInfo
.weight
= wxNORMAL
;
1566 m_DefaultStyleInfo
.underline
= 0;
1567 m_DefaultStyleInfo
.m_fg_valid
= TRUE
;
1568 m_DefaultStyleInfo
.m_fg
= *wxBLACK
;
1569 m_DefaultStyleInfo
.m_bg_valid
= TRUE
;
1570 m_DefaultStyleInfo
.m_bg
= *wxWHITE
;
1572 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1573 m_CursorStyleInfo
= m_DefaultStyleInfo
;
1577 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1578 int underline
, wxColour
*fg
,
1581 if(family
!= -1) m_CurrentStyleInfo
.family
= family
;
1582 if(size
!= -1) m_CurrentStyleInfo
.size
= size
;
1583 if(style
!= -1) m_CurrentStyleInfo
.style
= style
;
1584 if(weight
!= -1) m_CurrentStyleInfo
.weight
= weight
;
1585 if(underline
!= -1) m_CurrentStyleInfo
.underline
= underline
!= 0;
1586 if(fg
) m_CurrentStyleInfo
.m_fg
= *fg
;
1587 if(bg
) m_CurrentStyleInfo
.m_bg
= *bg
;
1589 new wxLayoutObjectCmd(
1590 m_CurrentStyleInfo
.family
,
1591 m_CurrentStyleInfo
.size
,
1592 m_CurrentStyleInfo
.style
,
1593 m_CurrentStyleInfo
.weight
,
1594 m_CurrentStyleInfo
.underline
,
1599 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1600 int underline
, char const *fg
, char const *bg
)
1608 cfg
= wxTheColourDatabase
->FindColour(fg
);
1610 cbg
= wxTheColourDatabase
->FindColour(bg
);
1612 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1616 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1617 int underline
, wxColour
*fg
, wxColour
*bg
)
1620 m_DefaultStyleInfo
= wxLayoutStyleInfo(family
, size
, style
, weight
,
1622 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1626 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1631 for(line
= m_FirstLine
;
1633 line
= line
->GetNextLine())
1635 if(line
->GetLineNumber() >= cpos
.y
)
1637 xpos
= line
->FindText(needle
,
1638 (line
->GetLineNumber() == cpos
.y
) ?
1641 return wxPoint(xpos
, line
->GetLineNumber());
1644 return wxPoint(-1,-1);
1649 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1651 AddCursorPosToUpdateRect();
1653 wxPoint cursorPosOld
= m_CursorPos
;
1655 wxLayoutLine
*line
= m_FirstLine
;
1656 while(line
&& line
->GetLineNumber() != p
.y
)
1657 line
= line
->GetNextLine();
1658 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1660 m_CursorPos
.y
= p
.y
;
1661 m_CursorLine
= line
;
1662 CoordType len
= line
->GetLength();
1665 m_CursorPos
.x
= p
.x
;
1669 m_CursorPos
.x
= len
;
1673 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1675 return m_CursorPos
== p
;
1679 wxLayoutList::MoveCursorVertically(int n
)
1681 AddCursorPosToUpdateRect();
1683 wxPoint cursorPosOld
= m_CursorPos
;
1686 if(n
< 0) // move up
1688 if(m_CursorLine
== m_FirstLine
) return false;
1689 while(n
< 0 && m_CursorLine
)
1691 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1697 m_CursorLine
= m_FirstLine
;
1703 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1704 m_CursorPos
.x
= m_CursorLine
->GetLength();
1710 wxLayoutLine
*last
= m_CursorLine
;
1711 if(! m_CursorLine
->GetNextLine()) return false;
1712 while(n
> 0 && m_CursorLine
)
1716 m_CursorLine
= m_CursorLine
->GetNextLine();
1720 m_CursorLine
= last
;
1726 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1727 m_CursorPos
.x
= m_CursorLine
->GetLength();
1732 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1738 wxLayoutList::MoveCursorHorizontally(int n
)
1740 AddCursorPosToUpdateRect();
1742 wxPoint cursorPosOld
= m_CursorPos
;
1747 if(m_CursorPos
.x
== 0) // at begin of line
1749 if(! MoveCursorVertically(-1))
1751 MoveCursorToEndOfLine();
1756 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1757 m_CursorPos
.x
-= move
; n
+= move
;
1762 int len
= m_CursorLine
->GetLength();
1763 if(m_CursorPos
.x
== len
) // at end of line
1765 if(! MoveCursorVertically(1))
1767 MoveCursorToBeginOfLine();
1772 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1773 m_CursorPos
.x
+= move
;
1777 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1783 wxLayoutList::MoveCursorWord(int n
, bool untilNext
)
1785 wxCHECK_MSG( m_CursorLine
, false, "no current line" );
1786 wxCHECK_MSG( n
== -1 || n
== +1, false, "not implemented yet" );
1788 CoordType moveDistance
= 0;
1790 for ( wxLOiterator i
= m_CursorLine
->FindObject(m_CursorPos
.x
, &offset
);
1797 wxLayoutObject
*obj
= *i
;
1798 if( obj
->GetType() != WXLO_TYPE_TEXT
)
1800 // any visible non text objects count as one word
1801 if ( obj
->IsVisibleObject() )
1805 moveDistance
+= obj
->GetLength();
1810 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)obj
;
1812 bool canAdvance
= true;
1814 if ( offset
== tobj
->GetLength() )
1819 // can't move further in this text object
1824 else if ( offset
> 0 )
1826 // offset is off by 1, make it a valid index
1833 const wxString
& text
= tobj
->GetText();
1834 const char *start
= text
.c_str();
1835 const char *end
= start
+ text
.length();
1836 const char *p
= start
+ offset
;
1844 // to the beginning/end of the next/prev word
1845 while ( p
>= start
&& p
< end
&& isspace(*p
) )
1850 // go to the end/beginning of the word (in a broad sense...)
1851 while ( p
>= start
&& p
< end
&& !isspace(*p
) )
1860 // now advance to the beginning of the next word
1861 while ( isspace(*p
) && p
< end
)
1867 // in these 2 cases we took 1 char too much
1868 if ( (p
< start
) || isspace(*p
) )
1876 moveDistance
= p
- start
- offset
;
1880 // except for the first iteration, offset is 0
1884 MoveCursorHorizontally(moveDistance
);
1890 wxLayoutList::Insert(wxString
const &text
)
1892 wxASSERT(m_CursorLine
);
1893 wxASSERT_MSG( text
.Find('\n') == wxNOT_FOUND
, "use wxLayoutImportText!" );
1898 AddCursorPosToUpdateRect();
1900 if ( !m_CursorLine
->Insert(m_CursorPos
.x
, text
) )
1903 m_CursorPos
.x
+= text
.Length();
1905 m_movedCursor
= true;
1907 m_CursorLine
->RecalculatePositions(0, this);
1913 wxLayoutList::Insert(wxLayoutObject
*obj
)
1915 wxASSERT(m_CursorLine
);
1918 m_CursorLine
= GetFirstLine();
1920 AddCursorPosToUpdateRect();
1922 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1923 m_CursorPos
.x
+= obj
->GetLength();
1924 m_movedCursor
= true;
1926 m_CursorLine
->RecalculatePositions(0, this);
1932 wxLayoutList::Insert(wxLayoutList
*llist
)
1937 for(wxLayoutLine
*line
= llist
->GetFirstLine();
1939 line
= line
->GetNextLine()
1942 for(wxLOiterator i
= line
->GetFirstObject();
1952 wxLayoutList::LineBreak(void)
1954 wxASSERT(m_CursorLine
);
1955 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1957 AddCursorPosToUpdateRect();
1959 wxPoint
position(m_CursorLine
->GetPosition());
1962 width
= m_CursorLine
->GetWidth(),
1963 height
= m_CursorLine
->GetHeight();
1965 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1966 if(setFirst
) // we were at beginning of first line
1967 m_FirstLine
= m_CursorLine
;
1968 wxASSERT(m_FirstLine
);
1969 if(m_CursorPos
.x
!= 0)
1974 // The following code will produce a height which is guaranteed to
1975 // be too high: old lineheight + the height of both new lines.
1976 // We can probably drop the old line height and start with height =
1978 wxLayoutLine
*prev
= m_CursorLine
->GetPreviousLine();
1980 height
+= prev
->GetHeight();
1981 height
+= m_CursorLine
->GetHeight();
1983 m_movedCursor
= true;
1985 SetUpdateRect(position
);
1986 SetUpdateRect(position
.x
+ width
+ MSW_CORRECTION
,
1987 position
.y
+ height
+ MSW_CORRECTION
);
1993 wxLayoutList::WrapLine(CoordType column
)
1995 if(m_CursorPos
.x
<= column
|| column
< 1)
1996 return false; // do nothing yet
1999 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
2001 return false; // cannot break line
2003 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
2004 m_CursorPos
.x
= xpos
;
2006 AddCursorPosToUpdateRect();
2009 Delete(1); // delete the space
2010 m_CursorPos
.x
= newpos
;
2012 m_CursorLine
->RecalculatePositions(1, this);
2014 m_movedCursor
= true;
2021 wxLayoutList::Delete(CoordType npos
)
2023 wxCHECK_MSG(m_CursorLine
, false, "can't delete in non existing line");
2028 AddCursorPosToUpdateRect();
2030 // were other lines appended to this one (this is important to know because
2031 // this means that our width _increased_ as the result of deletion)
2032 bool wasMerged
= false;
2034 // the size of the region to update
2035 CoordType totalHeight
= m_CursorLine
->GetHeight(),
2036 totalWidth
= m_CursorLine
->GetWidth();
2041 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
2045 // More to delete, continue on next line.
2047 // First, check if line is empty:
2048 if(m_CursorLine
->GetLength() == 0)
2050 // in this case, updating could probably be optimised
2052 wxASSERT(DeleteLines(1) == 0);
2061 // Need to join next line
2062 if(! m_CursorLine
->GetNextLine())
2067 wxLayoutLine
*next
= m_CursorLine
->GetNextLine();
2070 totalHeight
+= next
->GetHeight();
2071 totalWidth
+= next
->GetWidth();
2073 m_CursorLine
->MergeNextLine(this);
2078 wxFAIL_MSG("can't delete all this");
2088 // we need to update the whole tail of the line and the lines which
2092 wxPoint
position(m_CursorLine
->GetPosition());
2093 SetUpdateRect(position
);
2094 SetUpdateRect(position
.x
+ totalWidth
+ MSW_CORRECTION
,
2095 position
.y
+ totalHeight
+ MSW_CORRECTION
);
2102 wxLayoutList::DeleteLines(int n
)
2104 wxASSERT(m_CursorLine
);
2107 AddCursorPosToUpdateRect();
2111 if(!m_CursorLine
->GetNextLine())
2112 { // we cannot delete this line, but we can clear it
2113 MoveCursorToBeginOfLine();
2114 DeleteToEndOfLine();
2115 m_CursorLine
->RecalculatePositions(2, this);
2119 line
= m_CursorLine
;
2120 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
2122 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
2123 wxASSERT(m_FirstLine
);
2124 wxASSERT(m_CursorLine
);
2126 m_CursorLine
->RecalculatePositions(2, this);
2131 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
2133 wxLayoutLine
*line
= m_FirstLine
;
2135 // first, make sure everything is calculated - this might not be
2136 // needed, optimise it later
2137 ApplyStyle(m_DefaultStyleInfo
, dc
);
2140 line
->RecalculatePosition(this); // so we don't need to do it all the time
2141 // little condition to speed up redrawing:
2142 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2143 line
= line
->GetNextLine();
2148 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
2150 return m_CursorScreenPos
;
2154 Is called before each Draw(). Now, it will re-layout all lines which
2158 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
, bool forceAll
,
2159 wxPoint
*cpos
, wxPoint
*csize
)
2161 // first, make sure everything is calculated - this might not be
2162 // needed, optimise it later
2163 ApplyStyle(m_DefaultStyleInfo
, dc
);
2165 // This one we always Layout() to get the current cursor
2166 // coordinates on the screen:
2167 m_CursorLine
->MarkDirty();
2168 bool wasDirty
= false;
2169 wxLayoutLine
*line
= m_FirstLine
;
2173 ApplyStyle(line
->GetStyleInfo(), dc
);
2174 if(forceAll
|| line
->IsDirty()
2175 || (cpos
&& line
->GetLineNumber() == cpos
->y
))
2177 // The following Layout() calls will update our
2178 // m_CurrentStyleInfo if needed.
2179 if(line
== m_CursorLine
)
2181 line
->Layout(dc
, this,
2182 (wxPoint
*)&m_CursorScreenPos
,
2183 (wxPoint
*)&m_CursorSize
,
2186 // we cannot layout the line twice, so copy the coords:
2187 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2189 *cpos
= m_CursorScreenPos
;
2191 *csize
= m_CursorSize
;
2195 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2196 line
->Layout(dc
, this,
2198 csize
, NULL
, cpos
->x
);
2200 line
->Layout(dc
, this);
2201 // little condition to speed up redrawing:
2202 if(bottom
!= -1 && line
->GetPosition().y
> bottom
)
2206 line
->RecalculatePositions(1, this);
2207 line
= line
->GetNextLine();
2210 // can only be 0 if we are on the first line and have no next line
2211 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
2212 m_CursorLine
->GetNextLine() == NULL
&&
2213 m_CursorLine
== m_FirstLine
));
2214 AddCursorPosToUpdateRect();
2218 wxLayoutList::GetScreenPos(wxDC
&dc
, const wxPoint
&cpos
, wxPoint
*csize
)
2221 Layout(dc
, -1, false, &pos
, csize
);
2226 wxLayoutList::Draw(wxDC
&dc
,
2227 wxPoint
const &offset
,
2231 wxLayoutLine
*line
= m_FirstLine
;
2233 if ( m_Selection
.m_discarded
)
2235 // calculate them if we don't have them already
2236 if ( !m_Selection
.HasValidScreenCoords() )
2238 m_Selection
.m_ScreenA
= GetScreenPos(dc
, m_Selection
.m_CursorA
);
2239 m_Selection
.m_ScreenB
= GetScreenPos(dc
, m_Selection
.m_CursorB
);
2242 // invalidate the area which was previousle selected - and which is not
2243 // selected any more
2244 SetUpdateRect(m_Selection
.m_ScreenA
);
2245 SetUpdateRect(m_Selection
.m_ScreenB
);
2247 m_Selection
.m_discarded
= false;
2250 /* We need to re-layout all dirty lines to update styleinfos
2251 etc. However, somehow we don't find all dirty lines... */
2252 Layout(dc
); //,-1,true); //FIXME
2253 ApplyStyle(m_DefaultStyleInfo
, dc
);
2254 wxBrush
brush(m_CurrentStyleInfo
.m_bg
, wxSOLID
);
2256 dc
.SetBackgroundMode(wxTRANSPARENT
);
2258 bool style_set
= false;
2261 // only draw if between top and bottom:
2263 line
->GetPosition().y
+ line
->GetHeight() >= top
))
2267 ApplyStyle(line
->GetStyleInfo(), dc
);
2270 line
->Draw(dc
, this, offset
);
2272 // little condition to speed up redrawing:
2273 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2274 line
= line
->GetNextLine();
2276 InvalidateUpdateRect();
2278 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
2279 m_Selection
.m_valid
? "valid" : "invalid",
2280 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
2281 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
2285 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
2289 // First, find the right line:
2290 wxLayoutLine
*line
= m_FirstLine
;
2293 ApplyStyle(m_DefaultStyleInfo
, dc
);
2296 p
= line
->GetPosition();
2297 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
2300 // we need to run a layout here to get font sizes right :-(
2302 // VZ: we can't call Layout() from here because it marks the line as
2303 // clean and it is not refreshed when it's called from wxLayoutList::
2304 // Layout() - if we really need to do this, we should introduce an
2305 // extra argument to Layout() to prevent the line from MarkClean()ing
2307 line
->Layout(dc
, this);
2309 line
= line
->GetNextLine();
2317 return NULL
; // not found
2321 cursorPos
->y
= line
->GetLineNumber();
2323 // Now, find the object in the line:
2324 ApplyStyle(line
->GetStyleInfo(), dc
);
2325 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
2326 cursorPos
? &cursorPos
->x
: NULL
,
2328 return (i
== NULLIT
) ? NULL
: *i
;
2333 wxLayoutList::GetSize(void) const
2336 *line
= m_FirstLine
,
2339 return wxPoint(0,0);
2341 wxPoint
maxPoint(0,0);
2346 if(line
->GetWidth() > maxPoint
.x
)
2347 maxPoint
.x
= line
->GetWidth();
2349 line
= line
->GetNextLine();
2352 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
2354 // if the line was just added, its height would be 0 and we can't call
2355 // Layout() from here because we don't have a dc and we might be not drawing
2356 // at all, besides... So take the cursor height by default (taking 0 is bad
2357 // because then the scrollbars won't be resized and the new line won't be
2359 if ( last
->IsDirty() )
2361 if ( last
->GetHeight() == 0 )
2362 maxPoint
.y
+= m_CursorSize
.y
;
2363 if ( last
->GetWidth() == 0 && maxPoint
.x
< m_CursorSize
.x
)
2364 maxPoint
.x
= m_CursorSize
.x
;
2372 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
2374 if ( m_movedCursor
)
2375 m_movedCursor
= false;
2377 wxPoint
coords(m_CursorScreenPos
);
2378 coords
+= translate
;
2380 #ifdef WXLAYOUT_DEBUG
2381 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
2382 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
2383 (long)coords
.x
, (long)coords
.y
,
2384 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
2385 (long)m_CursorLine
->GetLineNumber(),
2386 (long)m_CursorLine
->GetLength()));
2388 wxLogStatus("Cursor is at (%d, %d)", m_CursorPos
.x
, m_CursorPos
.y
);
2391 #ifdef WXLAYOUT_USE_CARET
2392 m_caret
->Move(coords
);
2393 #else // !WXLAYOUT_USE_CARET
2394 dc
.SetBrush(*wxWHITE_BRUSH
);
2395 //FIXME: wxGTK XOR is borken at the moment!!!dc.SetLogicalFunction(wxXOR);
2396 dc
.SetLogicalFunction(wxXOR
);
2397 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
2400 dc
.DrawRectangle(coords
.x
, coords
.y
,
2401 m_CursorSize
.x
, m_CursorSize
.y
);
2402 SetUpdateRect(coords
.x
, coords
.y
);
2403 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
2407 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
2408 coords
.x
, coords
.y
);
2409 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
2410 SetUpdateRect(coords
.x
, coords
.y
);
2412 dc
.SetLogicalFunction(wxCOPY
);
2413 //dc.SetBrush(wxNullBrush);
2414 #endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
2418 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
2420 if(m_UpdateRectValid
)
2421 GrowRect(m_UpdateRect
, x
, y
);
2426 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
2427 m_UpdateRect
.height
= 4;// wxGTK :-)
2428 m_UpdateRectValid
= true;
2433 wxLayoutList::StartSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2435 wxPoint
cpos(cposOrig
);
2438 WXLO_DEBUG(("Starting selection at %ld/%ld", cpos
.x
, cpos
.y
));
2439 m_Selection
.m_CursorA
= cpos
;
2440 m_Selection
.m_CursorB
= cpos
;
2441 m_Selection
.m_ScreenA
= spos
;
2442 m_Selection
.m_ScreenB
= spos
;
2443 m_Selection
.m_selecting
= true;
2444 m_Selection
.m_valid
= false;
2448 wxLayoutList::ContinueSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2450 wxPoint
cpos(cposOrig
);
2454 wxASSERT(m_Selection
.m_selecting
== true);
2455 wxASSERT(m_Selection
.m_valid
== false);
2456 WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos
.x
, cpos
.y
));
2458 if ( m_Selection
.m_CursorB
<= cpos
)
2460 m_Selection
.m_ScreenB
= spos
;
2461 m_Selection
.m_CursorB
= cpos
;
2465 m_Selection
.m_ScreenA
= spos
;
2466 m_Selection
.m_CursorA
= cpos
;
2469 // we always want m_CursorA <= m_CursorB!
2470 if( m_Selection
.m_CursorA
> m_Selection
.m_CursorB
)
2472 // exchange the start/end points
2473 wxPoint help
= m_Selection
.m_CursorB
;
2474 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
2475 m_Selection
.m_CursorA
= help
;
2477 help
= m_Selection
.m_ScreenB
;
2478 m_Selection
.m_ScreenB
= m_Selection
.m_ScreenA
;
2479 m_Selection
.m_ScreenA
= help
;
2484 wxLayoutList::EndSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2486 wxPoint
cpos(cposOrig
);
2489 ContinueSelection(cpos
);
2490 WXLO_DEBUG(("Ending selection at %ld/%ld", cpos
.x
, cpos
.y
));
2491 m_Selection
.m_selecting
= false;
2492 m_Selection
.m_valid
= true;
2496 wxLayoutList::DiscardSelection()
2498 if ( !HasSelection() )
2501 m_Selection
.m_valid
=
2502 m_Selection
.m_selecting
= false;
2503 m_Selection
.m_discarded
= true;
2507 wxLayoutList::IsSelecting(void) const
2509 return m_Selection
.m_selecting
;
2513 wxLayoutList::IsSelected(const wxPoint
&cursor
) const
2515 if ( !HasSelection() )
2518 return m_Selection
.m_CursorA
<= cursor
&& cursor
<= m_Selection
.m_CursorB
;
2522 /** Tests whether this layout line is selected and needs
2524 @param line to test for
2525 @return 0 = not selected, 1 = fully selected, -1 = partially
2529 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
2532 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
2534 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
2537 CoordType y
= line
->GetLineNumber();
2538 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
2540 else if(m_Selection
.m_CursorA
.y
== y
)
2542 *from
= m_Selection
.m_CursorA
.x
;
2543 if(m_Selection
.m_CursorB
.y
== y
)
2544 *to
= m_Selection
.m_CursorB
.x
;
2546 *to
= line
->GetLength();
2549 else if(m_Selection
.m_CursorB
.y
== y
)
2551 *to
= m_Selection
.m_CursorB
.x
;
2552 if(m_Selection
.m_CursorA
.y
== y
)
2553 *from
= m_Selection
.m_CursorA
.x
;
2563 wxLayoutList::DeleteSelection(void)
2565 if(! m_Selection
.m_valid
)
2568 m_Selection
.m_valid
= false;
2570 // Only delete part of the current line?
2571 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
2573 MoveCursorTo(m_Selection
.m_CursorA
);
2574 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
2583 for(firstLine
= m_FirstLine
;
2584 firstLine
&& firstLine
->GetLineNumber() < m_Selection
.m_CursorA
.y
;
2585 firstLine
=firstLine
->GetNextLine())
2587 if(!firstLine
|| firstLine
->GetLineNumber() != m_Selection
.m_CursorA
.y
)
2591 for(lastLine
= m_FirstLine
;
2592 lastLine
&& lastLine
->GetLineNumber() < m_Selection
.m_CursorB
.y
;
2593 lastLine
=lastLine
->GetNextLine())
2595 if(!lastLine
|| lastLine
->GetLineNumber() != m_Selection
.m_CursorB
.y
)
2599 // We now know that the two lines are different:
2601 // First, delete what's left of this line:
2602 MoveCursorTo(m_Selection
.m_CursorA
);
2603 DeleteToEndOfLine();
2605 wxLayoutLine
*nextLine
= firstLine
->GetNextLine();
2606 while(nextLine
&& nextLine
!= lastLine
)
2607 nextLine
= nextLine
->DeleteLine(false, this);
2609 // Now nextLine = lastLine;
2610 Delete(1); // This joins firstLine and nextLine
2611 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x
2615 firstLine
->RecalculatePositions(1, this);
2618 /// Starts highlighting the selection
2620 wxLayoutList::StartHighlighting(wxDC
&dc
)
2623 dc
.SetTextForeground(m_CurrentStyleInfo
.m_bg
);
2624 dc
.SetTextBackground(m_CurrentStyleInfo
.m_fg
);
2625 dc
.SetBackgroundMode(wxSOLID
);
2629 /// Ends highlighting the selection
2631 wxLayoutList::EndHighlighting(wxDC
&dc
)
2634 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2635 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2636 dc
.SetBackgroundMode(wxTRANSPARENT
);
2642 wxLayoutList::Copy(const wxPoint
&from
,
2649 for(firstLine
= m_FirstLine
;
2650 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
2651 firstLine
=firstLine
->GetNextLine())
2653 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
2656 for(lastLine
= m_FirstLine
;
2657 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
2658 lastLine
=lastLine
->GetNextLine())
2660 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
2665 wxLayoutLine
*tmp
= firstLine
;
2666 firstLine
= lastLine
;
2670 wxLayoutList
*llist
= new wxLayoutList();
2672 if(firstLine
== lastLine
)
2674 firstLine
->Copy(llist
, from
.x
, to
.x
);
2678 // Extract objects from first line
2679 firstLine
->Copy(llist
, from
.x
);
2681 // Extract all lines between
2682 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
2684 line
= line
->GetNextLine())
2689 // Extract objects from last line
2690 lastLine
->Copy(llist
, 0, to
.x
);
2696 wxLayoutList::GetSelection(wxLayoutDataObject
*wxlo
, bool invalidate
)
2698 if(! m_Selection
.m_valid
)
2700 if(m_Selection
.m_selecting
)
2706 if(invalidate
) m_Selection
.m_valid
= false;
2708 wxLayoutList
*llist
= Copy( m_Selection
.m_CursorA
,
2709 m_Selection
.m_CursorB
);
2711 if(llist
&& wxlo
) // export as data object, too
2715 wxLayoutExportObject
*export
;
2716 wxLayoutExportStatus
status(llist
);
2717 while((export
= wxLayoutExport( &status
, WXLO_EXPORT_AS_OBJECTS
)) != NULL
)
2719 if(export
->type
== WXLO_EXPORT_EMPTYLINE
)
2720 ; //FIXME missing support for linebreaks in string format
2722 export
->content
.object
->Write(string
);
2726 wxlo
->SetData(string
.c_str(), string
.Length()+1);
2733 #define COPY_SI(what) if(si.what != -1) { m_CurrentStyleInfo.what = si.what; fontChanged = TRUE; }
2736 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
const &si
, wxDC
&dc
)
2738 bool fontChanged
= FALSE
;
2745 dc
.SetFont( m_FontCache
.GetFont(m_CurrentStyleInfo
) );
2749 m_CurrentStyleInfo
.m_fg
= si
.m_fg
;
2750 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2754 m_CurrentStyleInfo
.m_bg
= si
.m_bg
;
2755 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2760 #ifdef WXLAYOUT_DEBUG
2763 wxLayoutList::Debug(void)
2765 WXLO_DEBUG(("Cursor is in line %d, screen pos = (%d, %d)",
2766 m_CursorLine
->GetLineNumber(),
2767 m_CursorScreenPos
.x
, m_CursorScreenPos
.y
));
2770 for(line
= m_FirstLine
; line
; line
= line
->GetNextLine())
2779 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2783 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2785 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2786 wxString
const & title
)
2791 // remove any highlighting which could interfere with printing:
2792 m_llist
->StartSelection();
2793 m_llist
->EndSelection();
2796 wxLayoutPrintout::~wxLayoutPrintout()
2801 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2803 // The following bit is taken from the printing sample, let's see
2804 // whether it works for us.
2806 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2807 * the screen text size. This page also draws lines of actual length 5cm
2810 // Get the logical pixels per inch of screen and printer
2811 int ppiScreenX
, ppiScreenY
;
2812 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2813 int ppiPrinterX
, ppiPrinterY
;
2814 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2816 if(ppiScreenX
== 0) // not yet set, need to guess
2821 if(ppiPrinterX
== 0) // not yet set, need to guess
2827 // This scales the DC so that the printout roughly represents the
2828 // the screen scaling. The text point size _should_ be the right size
2829 // but in fact is too small for some reason. This is a detail that will
2830 // need to be addressed at some point but can be fudged for the
2832 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2834 // Now we have to check in case our real page size is reduced
2835 // (e.g. because we're drawing to a print preview memory DC)
2836 int pageWidth
, pageHeight
;
2838 dc
->GetSize(&w
, &h
);
2839 GetPageSizePixels(&pageWidth
, &pageHeight
);
2840 if(pageWidth
!= 0) // doesn't work always
2842 // If printer pageWidth == current DC width, then this doesn't
2843 // change. But w might be the preview bitmap width, so scale down.
2844 scale
= scale
* (float)(w
/(float)pageWidth
);
2846 dc
->SetUserScale(scale
, scale
);
2850 bool wxLayoutPrintout::OnPrintPage(int page
)
2859 top
= (page
- 1)*m_PrintoutHeight
;
2860 bottom
= top
+ m_PrintoutHeight
;
2861 // SetDeviceOrigin() doesn't work here, so we need to manually
2862 // translate all coordinates.
2863 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2864 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2871 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2873 /* We allocate a temporary wxDC for printing, so that we can
2874 determine the correct paper size and scaling. We don't actually
2875 print anything on it. */
2877 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2879 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2882 float scale
= ScaleDC(&psdc
);
2884 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2885 // This sets a left/top origin of 15% and 20%:
2886 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
2888 // This is the length of the printable area.
2889 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
2890 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2894 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2897 *maxPage
= m_NumOfPages
;
2900 *selPageTo
= m_NumOfPages
;
2901 wxRemoveFile(WXLLIST_TEMPFILE
);
2904 bool wxLayoutPrintout::HasPage(int pageNum
)
2906 return pageNum
<= m_NumOfPages
;
2910 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2911 out. It's a waste of paper anyway.
2915 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2916 wxPoint topleft
, wxPoint bottomright
,
2919 // make backups of all essential parameters
2920 const wxBrush
& brush
= dc
.GetBrush();
2921 const wxPen
& pen
= dc
.GetPen();
2922 const wxFont
& font
= dc
.GetFont();
2924 dc
.SetBrush(*wxWHITE_BRUSH
);
2925 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
2926 dc
.DrawRoundedRectangle(topleft
.x
,
2927 topleft
.y
,bottomright
.x
-topleft
.x
,
2928 bottomright
.y
-topleft
.y
);
2929 dc
.SetBrush(*wxBLACK_BRUSH
);
2930 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
2931 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
2935 page
= "9999/9999 "; // many pages...
2937 dc
.GetTextExtent(page
,&w
,&h
);
2938 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
2939 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
2940 dc
.GetTextExtent("XXXX", &w
,&h
);
2941 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
2952 wxFontCache::GetFont(int family
, int size
, int style
, int weight
,
2955 for(wxFCEList::iterator i
= m_FontList
.begin();
2956 i
!= m_FontList
.end(); i
++)
2957 if( (**i
).Matches(family
, size
, style
, weight
, underline
) )
2958 return (**i
).GetFont();
2960 wxFontCacheEntry
*fce
= new wxFontCacheEntry(family
, size
, style
,
2962 m_FontList
.push_back(fce
);
2963 return fce
->GetFont();