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
)
625 m_Width
= m_Height
= 0;
635 RecalculatePosition(llist
);
639 m_LineNumber
= m_Previous
->GetLineNumber() + 1;
640 m_Next
= m_Previous
->GetNextLine();
641 m_Previous
->m_Next
= this;
646 m_Next
->m_Previous
= this;
647 m_Next
->MoveLines(+1);
648 m_Next
->RecalculatePositions(1,llist
);
651 m_StyleInfo
= llist
->GetDefaultStyleInfo();
653 llist
->IncNumLines();
656 wxLayoutLine::~wxLayoutLine()
658 // kbList cleans itself
662 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
664 wxASSERT(m_Previous
|| GetLineNumber() == 0);
666 wxPoint
posOld(m_Position
);
670 m_Position
= m_Previous
->GetPosition();
671 m_Position
.y
+= m_Previous
->GetHeight();
674 m_Position
= wxPoint(0,0);
676 if ( m_Position
!= posOld
)
678 // the whole line moved and must be repainted
679 llist
->SetUpdateRect(m_Position
);
680 llist
->SetUpdateRect(m_Position
.x
+ GetWidth() + MSW_CORRECTION
,
681 m_Position
.y
+ GetHeight() + MSW_CORRECTION
);
682 llist
->SetUpdateRect(posOld
);
683 llist
->SetUpdateRect(posOld
.x
+ GetWidth() + MSW_CORRECTION
,
684 posOld
.y
+ GetHeight() + MSW_CORRECTION
);
691 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
693 //FIXME: is this really needed? We run Layout() anyway.
694 // Recursing here, drives computation time up exponentially, as
695 // each line will cause all following lines to be recalculated.
696 // Yes, or linenumbers go wrong.
698 wxASSERT(recurse
>= 0);
699 wxPoint pos
= m_Position
;
700 CoordType height
= m_Height
;
702 // WXLO_TRACE("RecalculatePositions()");
703 RecalculatePosition(llist
);
707 m_Next
->RecalculatePositions(--recurse
, llist
);
708 else if(pos
!= m_Position
|| m_Height
!= height
)
709 m_Next
->RecalculatePositions(0, llist
);
713 wxLayoutObjectList::iterator
714 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
718 wxLayoutObjectList::iterator
721 CoordType x
= 0, len
;
723 /* We search through the objects. As we don't like returning the
724 object that the cursor is behind, we just remember such an
725 object in "found" so we can return it if there is really no
726 further object following it. */
727 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
729 len
= (**i
).GetLength();
730 if( x
<= xpos
&& xpos
<= x
+ len
)
733 if(xpos
== x
+ len
) // is there another object behind?
735 else // we are really inside this object
738 x
+= (**i
).GetLength();
740 return found
; // ==NULL if really none found
743 wxLayoutObjectList::iterator
744 wxLayoutLine::FindObjectScreen(wxDC
&dc
, wxLayoutList
*llist
,
745 CoordType xpos
, CoordType
*cxpos
,
750 llist
->ApplyStyle(GetStyleInfo(), dc
);
752 wxLayoutObjectList::iterator i
;
753 CoordType x
= 0, cx
= 0, width
;
755 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
757 wxLayoutObject
*obj
= *i
;
758 if ( obj
->GetType() == WXLO_TYPE_CMD
)
760 // this will set the correct font for the objects which follow
761 obj
->Layout(dc
, llist
);
764 width
= obj
->GetWidth();
765 if( x
<= xpos
&& xpos
<= x
+ width
)
767 *cxpos
= cx
+ obj
->GetOffsetScreen(dc
, xpos
-x
);
774 x
+= obj
->GetWidth();
775 cx
+= obj
->GetLength();
778 // behind last object:
783 return m_ObjectList
.tail();
786 /** Finds text in this line.
787 @param needle the text to find
788 @param xpos the position where to start the search
789 @return the cursoor coord where it was found or -1
792 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
) const
797 wxString
const *text
;
799 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
801 if(cpos
>= xpos
) // search from here!
803 if((**i
).GetType() == WXLO_TYPE_TEXT
)
805 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
806 relpos
= text
->Find(needle
);
807 if(relpos
>= cpos
-xpos
) // -1 if not found
812 cpos
+= (**i
).GetLength();
815 return -1; // not found
819 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
822 wxASSERT(obj
!= NULL
);
826 // If we insert a command object, we need to recalculate all lines
827 // to update their styleinfo structure.
828 if(obj
->GetType() == WXLO_TYPE_CMD
)
832 wxLOiterator i
= FindObject(xpos
, &offset
);
835 if(xpos
== 0 ) // aha, empty line!
837 m_ObjectList
.push_back(obj
);
838 m_Length
+= obj
->GetLength();
845 CoordType len
= (**i
).GetLength();
846 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
847 { // insert before this object
848 m_ObjectList
.insert(i
,obj
);
849 m_Length
+= obj
->GetLength();
854 if( i
== m_ObjectList
.tail()) // last object?
855 m_ObjectList
.push_back(obj
);
857 { // insert after current object
859 m_ObjectList
.insert(i
,obj
);
861 m_Length
+= obj
->GetLength();
864 /* Otherwise we need to split the current object.
865 Fortunately this can only be a text object. */
866 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
867 wxString left
, right
;
868 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
869 left
= tobj
->GetText().substr(0,offset
);
870 right
= tobj
->GetText().substr(offset
,len
-offset
);
871 // current text object gets set to right half
872 tobj
->GetText() = right
; // set new text
873 // before it we insert the new object
874 m_ObjectList
.insert(i
,obj
);
875 m_Length
+= obj
->GetLength();
876 // and before that we insert the left half
877 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
882 wxLayoutLine::Insert(CoordType xpos
, const wxString
& text
)
889 wxLOiterator i
= FindObject(xpos
, &offset
);
890 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
892 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
893 tobj
->GetText().insert(offset
, text
);
894 m_Length
+= text
.Length();
898 if ( !Insert(xpos
, new wxLayoutObjectText(text
)) )
906 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
908 CoordType offset
, len
;
913 wxLOiterator i
= FindObject(xpos
, &offset
);
916 if(i
== NULLIT
) return npos
;
917 // now delete from that object:
918 if((**i
).GetType() != WXLO_TYPE_TEXT
)
920 if(offset
!= 0) // at end of line after a non-text object
923 len
= (**i
).GetLength();
926 // If we delete a command object, we need to recalculate all lines
927 // to update their styleinfo structure.
928 if((**i
).GetType() == WXLO_TYPE_CMD
)
930 m_ObjectList
.erase(i
);
934 // tidy up: remove empty text objects
935 if((**i
).GetLength() == 0)
937 m_ObjectList
.erase(i
);
941 CoordType max
= (**i
).GetLength() - offset
;
942 if(npos
< max
) max
= npos
;
945 if(xpos
== GetLength())
948 { // at the end of an object
949 // move to begin of next object:
951 continue; // start over
956 if(offset
== 0 && max
== (**i
).GetLength())
957 m_ObjectList
.erase(i
); // remove the whole object
959 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
967 wxLayoutLine::MarkNextDirty(int recurse
)
969 wxLayoutLine
*line
= GetNextLine();
970 while(line
&& (recurse
== -1 || recurse
>= 0))
973 line
= line
->GetNextLine();
974 if(recurse
> 0) recurse
--;
979 wxLayoutLine::DeleteWord(CoordType xpos
)
985 wxLOiterator i
= FindObject(xpos
, &offset
);
989 if(i
== NULLIT
) return false;
990 if((**i
).GetType() != WXLO_TYPE_TEXT
)
992 // This should only happen when at end of line, behind a non-text
994 if(offset
== (**i
).GetLength()) return false;
995 m_Length
-= (**i
).GetLength(); // -1
996 m_ObjectList
.erase(i
);
997 return true; // we are done
1001 if(offset
== (**i
).GetLength()) // at end of object
1006 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
1008 wxString str
= tobj
->GetText();
1009 str
= str
.substr(offset
,str
.Length()-offset
);
1010 // Find out how many positions we need to delete:
1011 // 1. eat leading space
1012 while(isspace(str
.c_str()[count
])) count
++;
1013 // 2. eat the word itself:
1014 while(isalnum(str
.c_str()[count
])) count
++;
1016 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
1017 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
1023 wxFAIL_MSG("unreachable");
1027 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
1029 // maintain linked list integrity
1031 m_Next
->m_Previous
= m_Previous
;
1033 m_Previous
->m_Next
= m_Next
;
1035 wxLayoutLine
*next
= m_Next
;
1038 // get the line numbers right again
1039 next
->MoveLines(-1);
1045 next
->RecalculatePositions(1, llist
);
1047 /* We assume that if we have more than one object in the list,
1048 this means that we have a command object, so we need to
1049 update the following lines. */
1050 if(m_ObjectList
.size() > 1 ||
1051 ( m_ObjectList
.begin() != NULLIT
&&
1052 (**m_ObjectList
.begin()).GetType() == WXLO_TYPE_CMD
)
1059 llist
->DecNumLines();
1065 wxLayoutLine::Draw(wxDC
&dc
,
1066 wxLayoutList
*llist
,
1067 const wxPoint
& offset
) const
1069 wxLayoutObjectList::iterator i
;
1070 wxPoint pos
= offset
;
1071 pos
= pos
+ GetPosition();
1073 pos
.y
+= m_BaseLine
;
1075 CoordType xpos
= 0; // cursorpos, lenght of line
1077 CoordType from
, to
, tempto
;
1079 int highlight
= llist
->IsSelected(this, &from
, &to
);
1080 // WXLO_DEBUG(("highlight=%d", highlight ));
1081 if(highlight
== 1) // we need to draw the whole line inverted!
1082 llist
->StartHighlighting(dc
);
1084 llist
->EndHighlighting(dc
);
1086 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1088 if(highlight
== -1) // partially highlight line
1090 // parts of the line need highlighting
1091 tempto
= xpos
+(**i
).GetLength();
1092 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, to
-xpos
);
1095 (**i
).Draw(dc
, pos
, llist
);
1096 pos
.x
+= (**i
).GetWidth();
1097 xpos
+= (**i
).GetLength();
1102 This function does all the recalculation, that is, it should only be
1103 called from within wxLayoutList::Layout(), as it uses the current
1104 list's styleinfo and updates it.
1107 wxLayoutLine::Layout(wxDC
&dc
,
1108 wxLayoutList
*llist
,
1110 wxPoint
*cursorSize
,
1111 wxLayoutStyleInfo
*cursorStyle
,
1113 bool suppressSIupdate
)
1115 wxLayoutObjectList::iterator i
;
1117 // when a line becomes dirty, we redraw it from the place where it was
1118 // changed till the end of line (because the following wxLayoutObjects are
1119 // moved when the preceding one changes) - calculate the update rectangle.
1120 CoordType updateTop
= m_Position
.y
,
1122 updateWidth
= m_Width
,
1123 updateHeight
= m_Height
;
1127 bottomHeight
= 0; // above and below baseline
1129 objTopHeight
, objBottomHeight
; // above and below baseline
1133 CoordType heightOld
= m_Height
;
1139 bool cursorFound
= false;
1143 *cursorPos
= m_Position
;
1144 if(cursorSize
) *cursorSize
= wxPoint(0,0);
1147 m_StyleInfo
= llist
->GetStyleInfo(); // save current style
1148 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
1150 wxLayoutObject
*obj
= *i
;
1151 obj
->Layout(dc
, llist
);
1152 wxPoint sizeObj
= obj
->GetSize(&objTopHeight
, &objBottomHeight
);
1154 if(cursorPos
&& ! cursorFound
)
1156 // we need to check whether the text cursor is here
1157 len
= obj
->GetLength();
1158 if(count
<= cx
&& count
+len
> cx
)
1160 if(obj
->GetType() == WXLO_TYPE_TEXT
)
1162 len
= cx
- count
; // pos in object
1163 CoordType width
, height
, descent
;
1164 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
1165 &width
, &height
, &descent
);
1166 cursorPos
->x
+= width
;
1167 cursorPos
->y
= m_Position
.y
;
1169 if(len
< obj
->GetLength())
1170 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
1172 str
= WXLO_CURSORCHAR
;
1173 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
1175 if(cursorStyle
) // set style info
1176 *cursorStyle
= llist
->GetStyleInfo();
1179 // Just in case some joker inserted an empty string object:
1181 width
= WXLO_MINIMUM_CURSOR_WIDTH
;
1184 cursorSize
->x
= width
;
1185 cursorSize
->y
= height
;
1188 cursorFound
= true; // no more checks
1192 // on some other object
1193 CoordType top
, bottom
; // unused
1195 *cursorSize
= obj
->GetSize(&top
,&bottom
);
1196 cursorPos
->y
= m_Position
.y
;
1197 cursorFound
= true; // no more checks
1203 cursorPos
->x
+= obj
->GetWidth();
1207 m_Width
+= sizeObj
.x
;
1208 if(sizeObj
.y
> m_Height
)
1210 m_Height
= sizeObj
.y
;
1213 if(objTopHeight
> topHeight
)
1214 topHeight
= objTopHeight
;
1215 if(objBottomHeight
> bottomHeight
)
1216 bottomHeight
= objBottomHeight
;
1221 if ( updateHeight
< m_Height
)
1222 updateHeight
= m_Height
;
1223 if ( updateWidth
< m_Width
)
1224 updateWidth
= m_Width
;
1226 // update all line if we don't know where to start from
1227 if ( updateLeft
== -1 )
1230 llist
->SetUpdateRect(updateLeft
, updateTop
);
1231 llist
->SetUpdateRect(updateLeft
+ updateWidth
+ MSW_CORRECTION
,
1232 updateTop
+ updateHeight
+ MSW_CORRECTION
);
1235 if(topHeight
+ bottomHeight
> m_Height
)
1237 m_Height
= topHeight
+bottomHeight
;
1240 m_BaseLine
= topHeight
;
1244 CoordType width
, height
, descent
;
1245 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1247 m_BaseLine
= m_Height
- descent
;
1250 // tell next line about coordinate change
1251 if(m_Next
&& m_Height
!= heightOld
)
1253 // FIXME isn't this done in RecalculatePositions() below anyhow?
1254 m_Next
->RecalculatePositions(0, llist
);
1257 // We need to check whether we found a valid cursor size:
1258 if(cursorPos
&& cursorSize
)
1260 // this might be the case if the cursor is at the end of the
1261 // line or on a command object:
1262 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
1264 CoordType width
, height
, descent
;
1265 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
1266 cursorSize
->x
= width
;
1267 cursorSize
->y
= height
;
1269 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
1270 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
1272 RecalculatePositions(1, llist
);
1278 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
1280 wxASSERT(xpos
>= 0);
1284 /* If we are at the begin of a line, we want to move all other
1285 lines down and stay with the cursor where we are. However, if we
1286 are in an empty line, we want to move down with it. */
1287 if(xpos
== 0 && GetLength() > 0)
1288 { // insert an empty line before this one
1289 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
1290 if(m_Previous
== NULL
)
1291 { // We were in first line, need to link in new empty line
1293 prev
->m_Next
= this;
1295 m_Previous
->m_Height
= 0; // this is a wild guess
1298 m_Next
->RecalculatePositions(1, llist
);
1303 wxLOiterator i
= FindObject(xpos
, &offset
);
1305 // must be at the end of the line then
1306 return new wxLayoutLine(this, llist
);
1309 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
1310 // split object at i:
1311 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
1313 wxString left
, right
;
1314 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
1315 left
= tobj
->GetText().substr(0,offset
);
1316 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
1317 // current text object gets set to left half
1318 tobj
->GetText() = left
; // set new text
1319 newLine
->Append(new wxLayoutObjectText(right
));
1320 m_Length
-= right
.Length();
1321 i
++; // don't move this object to the new list
1326 i
++; // move objects from here to new list
1329 while(i
!= m_ObjectList
.end())
1331 wxLayoutObject
*obj
= *i
;
1332 newLine
->Append(obj
);
1333 m_Length
-= obj
->GetLength();
1335 m_ObjectList
.remove(i
); // remove without deleting it
1338 m_Next
->RecalculatePositions(2, llist
);
1344 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
1346 wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
1347 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
1350 MarkDirty(GetWidth());
1352 wxLayoutObject
*last
= NULL
;
1353 for(i
= list
.begin(); i
!= list
.end();)
1355 wxLayoutObject
*current
= *i
;
1357 // merge text objects together for efficiency
1358 if ( last
&& last
->GetType() == WXLO_TYPE_TEXT
&&
1359 current
->GetType() == WXLO_TYPE_TEXT
)
1361 wxLayoutObjectText
*textObj
= (wxLayoutObjectText
*)last
;
1362 wxString
text(textObj
->GetText());
1363 text
+= ((wxLayoutObjectText
*)current
)->GetText();
1364 textObj
->SetText(text
);
1366 list
.erase(i
); // remove and delete it
1370 // just append the object "as was"
1373 list
.remove(i
); // remove without deleting it
1376 wxASSERT(list
.empty());
1378 wxLayoutLine
*oldnext
= GetNextLine();
1379 wxLayoutLine
*nextLine
= oldnext
->GetNextLine();
1383 nextLine
->MoveLines(-1);
1387 // this is now done in Delete(), but if this function is ever called
1388 // from elsewhere, we might have to move refresh code back here (in
1389 // order not to duplicate it)
1391 wxPoint
pos(oldnext
->GetPosition());
1392 llist
->SetUpdateRect(pos
);
1393 llist
->SetUpdateRect(pos
.x
+ oldnext
->GetWidth() + MSW_CORRECTION
,
1394 pos
.y
+ oldnext
->GetHeight() + MSW_CORRECTION
);
1398 llist
->DecNumLines();
1404 wxLayoutLine::GetWrapPosition(CoordType column
)
1407 wxLOiterator i
= FindObject(column
, &offset
);
1408 if(i
== NULLIT
) return -1; // cannot wrap
1410 // go backwards through the list and look for space in text objects
1413 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1417 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1424 }while(offset
!= -1);
1425 i
--; // move on to previous object
1429 column
-= (**i
).GetLength();
1433 offset
= (**i
).GetLength();
1434 }while(i
!= NULLIT
);
1435 /* If we reached the begin of the list and have more than one
1436 object, that one is longer than the margin, so break behind
1439 i
= m_ObjectList
.begin();
1440 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1442 pos
+= (**i
).GetLength();
1445 if(i
== NULLIT
) return -1; //why should this happen?
1446 pos
+= (**i
).GetLength();
1448 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1450 pos
+= (**i
).GetLength();
1453 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1454 // now we are at the second text object:
1455 pos
-= (**i
).GetLength();
1456 return pos
; // in front of it
1460 #ifdef WXLAYOUT_DEBUG
1462 wxLayoutLine::Debug(void)
1465 wxPoint pos
= GetPosition();
1466 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d",
1467 (long int) GetLineNumber(),
1468 (long int) pos
.x
, (long int) pos
.y
,
1469 (long int) GetHeight(),
1470 (long int) m_BaseLine
,
1471 (int) m_StyleInfo
.family
));
1472 if(m_ObjectList
.begin() != NULLIT
)
1473 (**m_ObjectList
.begin()).Debug();
1479 wxLayoutLine::Copy(wxLayoutList
*llist
,
1483 CoordType firstOffset
, lastOffset
;
1485 if(to
== -1) to
= GetLength();
1486 if(from
== to
) return;
1488 wxLOiterator first
= FindObject(from
, &firstOffset
);
1489 wxLOiterator last
= FindObject(to
, &lastOffset
);
1491 // Common special case: only one object
1492 if( first
!= NULLIT
&& last
!= NULLIT
&& *first
== *last
)
1494 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1496 llist
->Insert(new wxLayoutObjectText(
1497 ((wxLayoutObjectText
1498 *)*first
)->GetText().substr(firstOffset
,
1499 lastOffset
-firstOffset
))
1503 else // what can we do?
1505 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1506 llist
->Insert( (**first
).Copy() );
1511 // If we reach here, we can safely copy the whole first object from
1512 // the firstOffset position on:
1513 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1515 llist
->Insert(new wxLayoutObjectText(
1516 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1519 else if(firstOffset
== 0)
1520 llist
->Insert( (**first
).Copy() );
1521 // else nothing to copy :-(
1523 // Now we copy all objects before the last one:
1524 wxLOiterator i
= first
; i
++;
1525 for( ; i
!= last
; i
++)
1526 llist
->Insert( (**i
).Copy() );
1528 // And now the last object:
1531 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1533 llist
->Insert(new wxLayoutObjectText(
1534 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1538 llist
->Insert( (**last
).Copy() );
1543 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1545 The wxLayoutList object
1547 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1549 wxLayoutList::wxLayoutList()
1551 #ifdef WXLAYOUT_USE_CARET
1553 #endif // WXLAYOUT_USE_CARET
1557 InvalidateUpdateRect();
1561 wxLayoutList::~wxLayoutList()
1565 m_FirstLine
->DeleteLine(false, this);
1567 wxASSERT_MSG( m_numLines
== 0, "line count calculation broken" );
1571 wxLayoutList::Empty(void)
1574 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1576 m_CursorPos
= wxPoint(0,0);
1577 m_CursorScreenPos
= wxPoint(0,0);
1578 m_CursorSize
= wxPoint(0,0);
1579 m_movedCursor
= true;
1580 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1581 m_CursorLine
= m_FirstLine
;
1582 InvalidateUpdateRect();
1587 wxLayoutList::InternalClear(void)
1589 m_Selection
.m_selecting
= false;
1590 m_Selection
.m_valid
= false;
1592 m_DefaultStyleInfo
.family
= wxSWISS
;
1593 m_DefaultStyleInfo
.size
= WXLO_DEFAULTFONTSIZE
;
1594 m_DefaultStyleInfo
.style
= wxNORMAL
;
1595 m_DefaultStyleInfo
.weight
= wxNORMAL
;
1596 m_DefaultStyleInfo
.underline
= 0;
1597 m_DefaultStyleInfo
.m_fg_valid
= TRUE
;
1598 m_DefaultStyleInfo
.m_fg
= *wxBLACK
;
1599 m_DefaultStyleInfo
.m_bg_valid
= TRUE
;
1600 m_DefaultStyleInfo
.m_bg
= *wxWHITE
;
1602 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1603 m_CursorStyleInfo
= m_DefaultStyleInfo
;
1607 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1608 int underline
, wxColour
*fg
,
1611 if(family
!= -1) m_CurrentStyleInfo
.family
= family
;
1612 if(size
!= -1) m_CurrentStyleInfo
.size
= size
;
1613 if(style
!= -1) m_CurrentStyleInfo
.style
= style
;
1614 if(weight
!= -1) m_CurrentStyleInfo
.weight
= weight
;
1615 if(underline
!= -1) m_CurrentStyleInfo
.underline
= underline
!= 0;
1616 if(fg
) m_CurrentStyleInfo
.m_fg
= *fg
;
1617 if(bg
) m_CurrentStyleInfo
.m_bg
= *bg
;
1619 new wxLayoutObjectCmd(
1620 m_CurrentStyleInfo
.family
,
1621 m_CurrentStyleInfo
.size
,
1622 m_CurrentStyleInfo
.style
,
1623 m_CurrentStyleInfo
.weight
,
1624 m_CurrentStyleInfo
.underline
,
1629 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1630 int underline
, char const *fg
, char const *bg
)
1638 cfg
= wxTheColourDatabase
->FindColour(fg
);
1640 cbg
= wxTheColourDatabase
->FindColour(bg
);
1642 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1646 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1647 int underline
, wxColour
*fg
, wxColour
*bg
)
1650 m_DefaultStyleInfo
= wxLayoutStyleInfo(family
, size
, style
, weight
,
1652 m_CurrentStyleInfo
= m_DefaultStyleInfo
;
1654 // Empty() should be called after we set m_DefaultStyleInfo because
1655 // otherwise the style info for the first line (created in Empty()) would be
1661 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1666 for(line
= m_FirstLine
;
1668 line
= line
->GetNextLine())
1670 if(line
->GetLineNumber() >= cpos
.y
)
1672 xpos
= line
->FindText(needle
,
1673 (line
->GetLineNumber() == cpos
.y
) ?
1676 return wxPoint(xpos
, line
->GetLineNumber());
1679 return wxPoint(-1,-1);
1684 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1686 AddCursorPosToUpdateRect();
1688 wxPoint cursorPosOld
= m_CursorPos
;
1690 wxLayoutLine
*line
= m_FirstLine
;
1691 while(line
&& line
->GetLineNumber() != p
.y
)
1692 line
= line
->GetNextLine();
1693 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1695 m_CursorPos
.y
= p
.y
;
1696 m_CursorLine
= line
;
1697 CoordType len
= line
->GetLength();
1700 m_CursorPos
.x
= p
.x
;
1704 m_CursorPos
.x
= len
;
1708 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1710 return m_CursorPos
== p
;
1714 wxLayoutList::MoveCursorVertically(int n
)
1716 AddCursorPosToUpdateRect();
1718 wxPoint cursorPosOld
= m_CursorPos
;
1721 if(n
< 0) // move up
1723 if(m_CursorLine
== m_FirstLine
) return false;
1724 while(n
< 0 && m_CursorLine
)
1726 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1732 m_CursorLine
= m_FirstLine
;
1738 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1739 m_CursorPos
.x
= m_CursorLine
->GetLength();
1745 wxLayoutLine
*last
= m_CursorLine
;
1746 if(! m_CursorLine
->GetNextLine()) return false;
1747 while(n
> 0 && m_CursorLine
)
1751 m_CursorLine
= m_CursorLine
->GetNextLine();
1755 m_CursorLine
= last
;
1761 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1762 m_CursorPos
.x
= m_CursorLine
->GetLength();
1767 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1773 wxLayoutList::MoveCursorHorizontally(int n
)
1775 AddCursorPosToUpdateRect();
1777 wxPoint cursorPosOld
= m_CursorPos
;
1782 if(m_CursorPos
.x
== 0) // at begin of line
1784 if(! MoveCursorVertically(-1))
1786 MoveCursorToEndOfLine();
1791 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1792 m_CursorPos
.x
-= move
; n
+= move
;
1797 int len
= m_CursorLine
->GetLength();
1798 if(m_CursorPos
.x
== len
) // at end of line
1800 if(! MoveCursorVertically(1))
1802 MoveCursorToBeginOfLine();
1807 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1808 m_CursorPos
.x
+= move
;
1812 m_movedCursor
= m_CursorPos
!= cursorPosOld
;
1818 wxLayoutList::MoveCursorWord(int n
, bool untilNext
)
1820 wxCHECK_MSG( m_CursorLine
, false, "no current line" );
1821 wxCHECK_MSG( n
== -1 || n
== +1, false, "not implemented yet" );
1823 CoordType moveDistance
= 0;
1825 wxLayoutLine
*lineCur
= m_CursorLine
;
1826 for ( wxLOiterator i
= lineCur
->FindObject(m_CursorPos
.x
, &offset
);
1834 // moving forward, pass to the first object of the next line
1836 lineCur
= lineCur
->GetNextLine();
1838 i
= lineCur
->GetFirstObject();
1842 // moving backwards, pass to the last object of the prev line
1844 lineCur
= lineCur
->GetPreviousLine();
1846 i
= lineCur
->GetLastObject();
1851 // moved to the end/beginning of text
1858 wxLayoutObject
*obj
= *i
;
1862 // calculate offset: we are either at the very beginning or the very
1863 // end of the object, so it isn't very difficult (the only time when
1864 // offset is != -1 is for the very first iteration when its value is
1865 // returned by FindObject)
1869 offset
= obj
->GetLength();
1872 if( obj
->GetType() != WXLO_TYPE_TEXT
)
1874 // any visible non text objects count as one word
1875 if ( obj
->IsVisibleObject() )
1879 moveDistance
+= obj
->GetLength();
1884 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)obj
;
1886 bool canAdvance
= true;
1888 if ( offset
== tobj
->GetLength() )
1893 // can't move further in this text object
1896 // still should move over the object border
1900 else if ( offset
> 0 )
1902 // offset is off by 1, make it a valid index
1909 const wxString
& text
= tobj
->GetText();
1910 const char *start
= text
.c_str();
1911 const char *end
= start
+ text
.length();
1912 const char *p
= start
+ offset
;
1920 // to the beginning/end of the next/prev word
1921 while ( p
>= start
&& p
< end
&& isspace(*p
) )
1926 // go to the end/beginning of the word (in a broad sense...)
1927 while ( p
>= start
&& p
< end
&& !isspace(*p
) )
1936 // now advance to the beginning of the next word
1937 while ( isspace(*p
) && p
< end
)
1943 // in these 2 cases we took 1 char too much
1944 if ( (p
< start
) || isspace(*p
) )
1950 CoordType moveDelta
= p
- start
- offset
;
1951 if ( (n
< 0) && (offset
== tobj
->GetLength() - 1) )
1953 // because we substracted 1 from offset in this case above, now
1954 // compensate for it
1958 if ( moveDelta
!= 0 )
1960 moveDistance
+= moveDelta
;
1967 // except for the first iteration, offset is calculated in the beginning
1972 MoveCursorHorizontally(moveDistance
);
1978 wxLayoutList::Insert(wxString
const &text
)
1980 wxASSERT(m_CursorLine
);
1981 wxASSERT_MSG( text
.Find('\n') == wxNOT_FOUND
, "use wxLayoutImportText!" );
1986 AddCursorPosToUpdateRect();
1988 if ( !m_CursorLine
->Insert(m_CursorPos
.x
, text
) )
1991 m_CursorPos
.x
+= text
.Length();
1993 m_movedCursor
= true;
1995 m_CursorLine
->RecalculatePositions(0, this);
2001 wxLayoutList::Insert(wxLayoutObject
*obj
)
2003 wxASSERT(m_CursorLine
);
2006 m_CursorLine
= GetFirstLine();
2008 AddCursorPosToUpdateRect();
2010 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
2011 m_CursorPos
.x
+= obj
->GetLength();
2012 m_movedCursor
= true;
2014 m_CursorLine
->RecalculatePositions(0, this);
2020 wxLayoutList::Insert(wxLayoutList
*llist
)
2025 for(wxLayoutLine
*line
= llist
->GetFirstLine();
2027 line
= line
->GetNextLine()
2030 for(wxLOiterator i
= line
->GetFirstObject();
2040 wxLayoutList::LineBreak(void)
2042 wxASSERT(m_CursorLine
);
2044 AddCursorPosToUpdateRect();
2046 wxPoint
position(m_CursorLine
->GetPosition());
2049 width
= m_CursorLine
->GetWidth(),
2050 height
= m_CursorLine
->GetHeight();
2052 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
2053 if(m_CursorLine
->GetPreviousLine() == NULL
)
2054 m_FirstLine
= m_CursorLine
;
2055 if(m_CursorPos
.x
> 0)
2059 // The following code will produce a height which is guaranteed to
2060 // be too high: old lineheight + the height of both new lines.
2061 // We can probably drop the old line height and start with height =
2063 wxLayoutLine
*prev
= m_CursorLine
->GetPreviousLine();
2065 height
+= prev
->GetHeight();
2066 height
+= m_CursorLine
->GetHeight();
2068 m_movedCursor
= true;
2070 SetUpdateRect(position
);
2071 SetUpdateRect(position
.x
+ width
+ MSW_CORRECTION
,
2072 position
.y
+ height
+ MSW_CORRECTION
);
2078 wxLayoutList::WrapLine(CoordType column
)
2080 if(m_CursorPos
.x
<= column
|| column
< 1)
2081 return false; // do nothing yet
2084 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
2086 return false; // cannot break line
2088 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
2089 m_CursorPos
.x
= xpos
;
2091 AddCursorPosToUpdateRect();
2094 Delete(1); // delete the space
2095 m_CursorPos
.x
= newpos
;
2097 m_CursorLine
->RecalculatePositions(1, this);
2099 m_movedCursor
= true;
2106 wxLayoutList::Delete(CoordType npos
)
2108 wxCHECK_MSG(m_CursorLine
, false, "can't delete in non existing line");
2113 AddCursorPosToUpdateRect();
2115 // were other lines appended to this one (this is important to know because
2116 // this means that our width _increased_ as the result of deletion)
2117 bool wasMerged
= false;
2119 // the size of the region to update
2120 CoordType totalHeight
= m_CursorLine
->GetHeight(),
2121 totalWidth
= m_CursorLine
->GetWidth();
2126 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
2130 // More to delete, continue on next line.
2132 // First, check if line is empty:
2133 if(m_CursorLine
->GetLength() == 0)
2135 // in this case, updating could probably be optimised
2137 wxASSERT(DeleteLines(1) == 0);
2146 // Need to join next line
2147 if(! m_CursorLine
->GetNextLine())
2152 wxLayoutLine
*next
= m_CursorLine
->GetNextLine();
2155 totalHeight
+= next
->GetHeight();
2156 totalWidth
+= next
->GetWidth();
2158 m_CursorLine
->MergeNextLine(this);
2163 wxFAIL_MSG("can't delete all this");
2173 // we need to update the whole tail of the line and the lines which
2177 wxPoint
position(m_CursorLine
->GetPosition());
2178 SetUpdateRect(position
);
2179 SetUpdateRect(position
.x
+ totalWidth
+ MSW_CORRECTION
,
2180 position
.y
+ totalHeight
+ MSW_CORRECTION
);
2187 wxLayoutList::DeleteLines(int n
)
2189 wxASSERT(m_CursorLine
);
2192 AddCursorPosToUpdateRect();
2196 if(!m_CursorLine
->GetNextLine())
2197 { // we cannot delete this line, but we can clear it
2198 MoveCursorToBeginOfLine();
2199 DeleteToEndOfLine();
2200 m_CursorLine
->RecalculatePositions(2, this);
2204 line
= m_CursorLine
;
2205 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
2207 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
2208 wxASSERT(m_FirstLine
);
2209 wxASSERT(m_CursorLine
);
2211 m_CursorLine
->RecalculatePositions(2, this);
2216 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
2218 wxLayoutLine
*line
= m_FirstLine
;
2220 // first, make sure everything is calculated - this might not be
2221 // needed, optimise it later
2222 ApplyStyle(m_DefaultStyleInfo
, dc
);
2225 line
->RecalculatePosition(this); // so we don't need to do it all the time
2226 // little condition to speed up redrawing:
2227 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
2228 line
= line
->GetNextLine();
2233 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
2235 return m_CursorScreenPos
;
2239 Is called before each Draw(). Now, it will re-layout all lines which
2243 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
, bool forceAll
,
2244 wxPoint
*cpos
, wxPoint
*csize
)
2246 // first, make sure everything is calculated - this might not be
2247 // needed, optimise it later
2248 ApplyStyle(m_DefaultStyleInfo
, dc
);
2250 // This one we always Layout() to get the current cursor
2251 // coordinates on the screen:
2252 m_CursorLine
->MarkDirty();
2253 bool wasDirty
= false;
2254 wxLayoutLine
*line
= m_FirstLine
;
2258 ApplyStyle(line
->GetStyleInfo(), dc
);
2259 if(forceAll
|| line
->IsDirty()
2260 || (cpos
&& line
->GetLineNumber() == cpos
->y
))
2262 // The following Layout() calls will update our
2263 // m_CurrentStyleInfo if needed.
2264 if(line
== m_CursorLine
)
2266 line
->Layout(dc
, this,
2267 (wxPoint
*)&m_CursorScreenPos
,
2268 (wxPoint
*)&m_CursorSize
,
2271 // we cannot layout the line twice, so copy the coords:
2272 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2274 *cpos
= m_CursorScreenPos
;
2276 *csize
= m_CursorSize
;
2280 if(cpos
&& line
->GetLineNumber() == cpos
->y
)
2281 line
->Layout(dc
, this,
2283 csize
, NULL
, cpos
->x
);
2285 line
->Layout(dc
, this);
2286 // little condition to speed up redrawing:
2287 if(bottom
!= -1 && line
->GetPosition().y
> bottom
)
2291 line
->RecalculatePositions(1, this);
2292 line
= line
->GetNextLine();
2295 // can only be 0 if we are on the first line and have no next line
2296 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
2297 m_CursorLine
->GetNextLine() == NULL
&&
2298 m_CursorLine
== m_FirstLine
));
2299 AddCursorPosToUpdateRect();
2303 wxLayoutList::GetScreenPos(wxDC
&dc
, const wxPoint
&cpos
, wxPoint
*csize
)
2306 Layout(dc
, -1, false, &pos
, csize
);
2311 wxLayoutList::Draw(wxDC
&dc
,
2312 wxPoint
const &offset
,
2316 wxLayoutLine
*line
= m_FirstLine
;
2318 if ( m_Selection
.m_discarded
)
2320 // calculate them if we don't have them already
2321 if ( !m_Selection
.HasValidScreenCoords() )
2323 m_Selection
.m_ScreenA
= GetScreenPos(dc
, m_Selection
.m_CursorA
);
2324 m_Selection
.m_ScreenB
= GetScreenPos(dc
, m_Selection
.m_CursorB
);
2327 // invalidate the area which was previousle selected - and which is not
2328 // selected any more
2329 SetUpdateRect(m_Selection
.m_ScreenA
);
2330 SetUpdateRect(m_Selection
.m_ScreenB
);
2332 m_Selection
.m_discarded
= false;
2335 /* We need to re-layout all dirty lines to update styleinfos
2336 etc. However, somehow we don't find all dirty lines... */
2337 Layout(dc
); //,-1,true); //FIXME
2338 ApplyStyle(m_DefaultStyleInfo
, dc
);
2339 wxBrush
brush(m_CurrentStyleInfo
.m_bg
, wxSOLID
);
2341 dc
.SetBackgroundMode(wxTRANSPARENT
);
2343 bool style_set
= false;
2346 // only draw if between top and bottom:
2348 line
->GetPosition().y
+ line
->GetHeight() > top
))
2352 ApplyStyle(line
->GetStyleInfo(), dc
);
2355 // little condition to speed up redrawing:
2357 && line
->GetPosition().y
+line
->GetHeight() >= bottom
)
2359 line
->Draw(dc
, this, offset
);
2361 line
= line
->GetNextLine();
2363 InvalidateUpdateRect();
2365 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
2366 m_Selection
.m_valid
? "valid" : "invalid",
2367 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
2368 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
2372 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
2376 // First, find the right line:
2378 *line
= m_FirstLine
,
2379 *lastline
= m_FirstLine
;
2382 ApplyStyle(m_DefaultStyleInfo
, dc
);
2385 p
= line
->GetPosition();
2386 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
2389 line
= line
->GetNextLine();
2396 // use the last line:
2401 cursorPos
->y
= line
->GetLineNumber();
2403 bool foundinline
= true;
2404 // Now, find the object in the line:
2405 wxLOiterator i
= line
->FindObjectScreen(dc
, this,
2407 cursorPos
? &cursorPos
->x
: NULL
,
2410 *found
= *found
&& foundinline
;
2411 return (i
== NULLIT
) ? NULL
: *i
;
2416 wxLayoutList::GetSize(void) const
2419 *line
= m_FirstLine
,
2422 return wxPoint(0,0);
2424 wxPoint
maxPoint(0,0);
2429 if(line
->GetWidth() > maxPoint
.x
)
2430 maxPoint
.x
= line
->GetWidth();
2432 line
= line
->GetNextLine();
2435 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
2437 // if the line was just added, its height would be 0 and we can't call
2438 // Layout() from here because we don't have a dc and we might be not drawing
2439 // at all, besides... So take the cursor height by default (taking 0 is bad
2440 // because then the scrollbars won't be resized and the new line won't be
2442 if ( last
->IsDirty() )
2444 if ( last
->GetHeight() == 0 )
2445 maxPoint
.y
+= m_CursorSize
.y
;
2446 if ( last
->GetWidth() == 0 && maxPoint
.x
< m_CursorSize
.x
)
2447 maxPoint
.x
= m_CursorSize
.x
;
2455 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
2457 if ( m_movedCursor
)
2458 m_movedCursor
= false;
2460 wxPoint
coords(m_CursorScreenPos
);
2461 coords
+= translate
;
2463 #ifdef WXLAYOUT_DEBUG
2464 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
2465 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
2466 (long)coords
.x
, (long)coords
.y
,
2467 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
2468 (long)m_CursorLine
->GetLineNumber(),
2469 (long)m_CursorLine
->GetLength()));
2471 wxLogStatus("Cursor is at (%d, %d)", m_CursorPos
.x
, m_CursorPos
.y
);
2474 #ifdef WXLAYOUT_USE_CARET
2475 m_caret
->Move(coords
);
2476 #else // !WXLAYOUT_USE_CARET
2477 dc
.SetBrush(*wxWHITE_BRUSH
);
2478 //FIXME: wxGTK XOR is borken at the moment!!!dc.SetLogicalFunction(wxXOR);
2479 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
2482 dc
.SetLogicalFunction(wxXOR
);
2483 dc
.DrawRectangle(coords
.x
, coords
.y
,
2484 m_CursorSize
.x
, m_CursorSize
.y
);
2485 SetUpdateRect(coords
.x
, coords
.y
);
2486 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
2490 dc
.SetLogicalFunction(wxCOPY
);
2491 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
2492 coords
.x
, coords
.y
);
2493 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
2494 SetUpdateRect(coords
.x
, coords
.y
);
2496 dc
.SetLogicalFunction(wxCOPY
);
2497 //dc.SetBrush(wxNullBrush);
2498 #endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
2502 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
2504 if(m_UpdateRectValid
)
2505 GrowRect(m_UpdateRect
, x
, y
);
2510 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
2511 m_UpdateRect
.height
= 4;// wxGTK :-)
2512 m_UpdateRectValid
= true;
2517 wxLayoutList::StartSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2519 wxPoint
cpos(cposOrig
);
2522 WXLO_DEBUG(("Starting selection at %ld/%ld", cpos
.x
, cpos
.y
));
2523 m_Selection
.m_CursorA
= cpos
;
2524 m_Selection
.m_CursorB
= cpos
;
2525 m_Selection
.m_ScreenA
= spos
;
2526 m_Selection
.m_ScreenB
= spos
;
2527 m_Selection
.m_selecting
= true;
2528 m_Selection
.m_valid
= false;
2532 wxLayoutList::ContinueSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2534 wxPoint
cpos(cposOrig
);
2538 wxASSERT(m_Selection
.m_selecting
== true);
2539 wxASSERT(m_Selection
.m_valid
== false);
2540 WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos
.x
, cpos
.y
));
2542 if ( m_Selection
.m_CursorB
<= cpos
)
2544 m_Selection
.m_ScreenB
= spos
;
2545 m_Selection
.m_CursorB
= cpos
;
2549 m_Selection
.m_ScreenA
= spos
;
2550 m_Selection
.m_CursorA
= cpos
;
2553 // we always want m_CursorA <= m_CursorB!
2554 if( m_Selection
.m_CursorA
> m_Selection
.m_CursorB
)
2556 // exchange the start/end points
2557 wxPoint help
= m_Selection
.m_CursorB
;
2558 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
2559 m_Selection
.m_CursorA
= help
;
2561 help
= m_Selection
.m_ScreenB
;
2562 m_Selection
.m_ScreenB
= m_Selection
.m_ScreenA
;
2563 m_Selection
.m_ScreenA
= help
;
2568 wxLayoutList::EndSelection(const wxPoint
& cposOrig
, const wxPoint
& spos
)
2570 wxPoint
cpos(cposOrig
);
2573 ContinueSelection(cpos
);
2574 WXLO_DEBUG(("Ending selection at %ld/%ld", cpos
.x
, cpos
.y
));
2575 m_Selection
.m_selecting
= false;
2576 m_Selection
.m_valid
= true;
2580 wxLayoutList::DiscardSelection()
2582 if ( !HasSelection() )
2585 m_Selection
.m_valid
=
2586 m_Selection
.m_selecting
= false;
2587 m_Selection
.m_discarded
= true;
2591 wxLayoutList::IsSelecting(void) const
2593 return m_Selection
.m_selecting
;
2597 wxLayoutList::IsSelected(const wxPoint
&cursor
) const
2599 if ( !HasSelection() )
2602 return m_Selection
.m_CursorA
<= cursor
&& cursor
<= m_Selection
.m_CursorB
;
2606 /** Tests whether this layout line is selected and needs
2608 @param line to test for
2609 @return 0 = not selected, 1 = fully selected, -1 = partially
2613 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
2616 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
2618 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
2621 CoordType y
= line
->GetLineNumber();
2622 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
2624 else if(m_Selection
.m_CursorA
.y
== y
)
2626 *from
= m_Selection
.m_CursorA
.x
;
2627 if(m_Selection
.m_CursorB
.y
== y
)
2628 *to
= m_Selection
.m_CursorB
.x
;
2630 *to
= line
->GetLength();
2633 else if(m_Selection
.m_CursorB
.y
== y
)
2635 *to
= m_Selection
.m_CursorB
.x
;
2636 if(m_Selection
.m_CursorA
.y
== y
)
2637 *from
= m_Selection
.m_CursorA
.x
;
2647 wxLayoutList::DeleteSelection(void)
2649 if(! m_Selection
.m_valid
)
2652 m_Selection
.m_valid
= false;
2654 // Only delete part of the current line?
2655 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
2657 MoveCursorTo(m_Selection
.m_CursorA
);
2658 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
2662 // We now know that the two lines are different:
2665 * firstLine
= GetLine(m_Selection
.m_CursorA
.y
),
2666 * lastLine
= GetLine(m_Selection
.m_CursorB
.y
);
2668 // First, delete what's left of this line:
2669 MoveCursorTo(m_Selection
.m_CursorA
);
2670 DeleteToEndOfLine();
2672 wxLayoutLine
*prevLine
= firstLine
->GetPreviousLine(),
2673 *nextLine
= firstLine
->GetNextLine();
2674 while(nextLine
&& nextLine
!= lastLine
)
2675 nextLine
= nextLine
->DeleteLine(false, this);
2677 // Now nextLine = lastLine;
2678 Delete(1); // This joins firstLine and nextLine
2679 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x positions
2681 // Recalculate the line positions and numbers but notice that firstLine
2682 // might not exist any more - it could be deleted by Delete(1) above
2683 wxLayoutLine
*firstLine2
= prevLine
? prevLine
->GetNextLine() : m_FirstLine
;
2684 firstLine2
->RecalculatePositions(1, this);
2687 /// Starts highlighting the selection
2689 wxLayoutList::StartHighlighting(wxDC
&dc
)
2692 dc
.SetTextForeground(m_CurrentStyleInfo
.m_bg
);
2693 dc
.SetTextBackground(m_CurrentStyleInfo
.m_fg
);
2694 dc
.SetBackgroundMode(wxSOLID
);
2698 /// Ends highlighting the selection
2700 wxLayoutList::EndHighlighting(wxDC
&dc
)
2703 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2704 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2705 dc
.SetBackgroundMode(wxTRANSPARENT
);
2711 wxLayoutList::Copy(const wxPoint
&from
,
2718 for(firstLine
= m_FirstLine
;
2719 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
2720 firstLine
=firstLine
->GetNextLine())
2722 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
2725 for(lastLine
= m_FirstLine
;
2726 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
2727 lastLine
=lastLine
->GetNextLine())
2729 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
2734 wxLayoutLine
*tmp
= firstLine
;
2735 firstLine
= lastLine
;
2739 wxLayoutList
*llist
= new wxLayoutList();
2741 if(firstLine
== lastLine
)
2743 firstLine
->Copy(llist
, from
.x
, to
.x
);
2747 // Extract objects from first line
2748 firstLine
->Copy(llist
, from
.x
);
2750 // Extract all lines between
2751 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
2753 line
= line
->GetNextLine())
2758 // Extract objects from last line
2759 lastLine
->Copy(llist
, 0, to
.x
);
2765 wxLayoutList::GetSelection(wxLayoutDataObject
*wxlo
, bool invalidate
)
2767 if(! m_Selection
.m_valid
)
2769 if(m_Selection
.m_selecting
)
2775 if(invalidate
) m_Selection
.m_valid
= false;
2777 wxLayoutList
*llist
= Copy( m_Selection
.m_CursorA
,
2778 m_Selection
.m_CursorB
);
2780 if(llist
&& wxlo
) // export as data object, too
2784 wxLayoutExportObject
*export
;
2785 wxLayoutExportStatus
status(llist
);
2786 while((export
= wxLayoutExport( &status
, WXLO_EXPORT_AS_OBJECTS
)) != NULL
)
2788 if(export
->type
== WXLO_EXPORT_EMPTYLINE
)
2789 ; //FIXME missing support for linebreaks in string format
2791 export
->content
.object
->Write(string
);
2795 wxlo
->SetData(string
.c_str(), string
.Length()+1);
2802 #define COPY_SI(what) if(si.what != -1) { m_CurrentStyleInfo.what = si.what; fontChanged = TRUE; }
2805 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
const &si
, wxDC
&dc
)
2807 bool fontChanged
= FALSE
;
2814 dc
.SetFont( m_FontCache
.GetFont(m_CurrentStyleInfo
) );
2818 m_CurrentStyleInfo
.m_fg
= si
.m_fg
;
2819 dc
.SetTextForeground(m_CurrentStyleInfo
.m_fg
);
2823 m_CurrentStyleInfo
.m_bg
= si
.m_bg
;
2824 dc
.SetTextBackground(m_CurrentStyleInfo
.m_bg
);
2829 #ifdef WXLAYOUT_DEBUG
2832 wxLayoutList::Debug(void)
2834 WXLO_DEBUG(("Cursor is in line %d, screen pos = (%d, %d)",
2835 m_CursorLine
->GetLineNumber(),
2836 m_CursorScreenPos
.x
, m_CursorScreenPos
.y
));
2839 for(line
= m_FirstLine
; line
; line
= line
->GetNextLine())
2848 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2852 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2854 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2855 wxString
const & title
)
2860 // remove any highlighting which could interfere with printing:
2861 m_llist
->StartSelection();
2862 m_llist
->EndSelection();
2865 wxLayoutPrintout::~wxLayoutPrintout()
2870 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2872 // The following bit is taken from the printing sample, let's see
2873 // whether it works for us.
2875 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2876 * the screen text size. This page also draws lines of actual length 5cm
2879 // Get the logical pixels per inch of screen and printer
2880 int ppiScreenX
, ppiScreenY
;
2881 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2882 int ppiPrinterX
, ppiPrinterY
;
2883 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2885 if(ppiScreenX
== 0) // not yet set, need to guess
2890 if(ppiPrinterX
== 0) // not yet set, need to guess
2896 // This scales the DC so that the printout roughly represents the
2897 // the screen scaling. The text point size _should_ be the right size
2898 // but in fact is too small for some reason. This is a detail that will
2899 // need to be addressed at some point but can be fudged for the
2901 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2903 // Now we have to check in case our real page size is reduced
2904 // (e.g. because we're drawing to a print preview memory DC)
2905 int pageWidth
, pageHeight
;
2907 dc
->GetSize(&w
, &h
);
2908 GetPageSizePixels(&pageWidth
, &pageHeight
);
2909 if(pageWidth
!= 0) // doesn't work always
2911 // If printer pageWidth == current DC width, then this doesn't
2912 // change. But w might be the preview bitmap width, so scale down.
2913 scale
= scale
* (float)(w
/(float)pageWidth
);
2915 dc
->SetUserScale(scale
, scale
);
2919 bool wxLayoutPrintout::OnPrintPage(int page
)
2928 top
= (page
- 1)*m_PrintoutHeight
;
2929 bottom
= top
+ m_PrintoutHeight
;
2931 WXLO_DEBUG(("OnPrintPage(%d) printing from %d to %d", page
, top
,
2933 // SetDeviceOrigin() doesn't work here, so we need to manually
2934 // translate all coordinates.
2935 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2936 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2943 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2945 /* We allocate a temporary wxDC for printing, so that we can
2946 determine the correct paper size and scaling. We don't actually
2947 print anything on it. */
2949 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2951 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2954 float scale
= ScaleDC(&psdc
);
2956 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2958 // This sets a left/top origin of 10% and 7%:
2959 m_Offset
= wxPoint((10*m_PageWidth
)/100, (7*m_PageHeight
)/100);
2961 // This is the length of the printable area.
2962 m_PrintoutHeight
= m_PageHeight
- 2*m_Offset
.y
;
2963 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2965 // We should really use the margin settings of wxWindows somehow.
2966 m_Offset
= wxPoint(0,0);
2967 // This is the length of the printable area.
2968 m_PrintoutHeight
= m_PageHeight
;
2969 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2974 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2977 *maxPage
= m_NumOfPages
;
2980 *selPageTo
= m_NumOfPages
;
2981 wxRemoveFile(WXLLIST_TEMPFILE
);
2984 bool wxLayoutPrintout::HasPage(int pageNum
)
2986 return pageNum
<= m_NumOfPages
;
2990 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2991 out. It's a waste of paper anyway.
2995 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2996 wxPoint topleft
, wxPoint bottomright
,
2999 // make backups of all essential parameters
3000 const wxBrush
& brush
= dc
.GetBrush();
3001 const wxPen
& pen
= dc
.GetPen();
3002 const wxFont
& font
= dc
.GetFont();
3004 dc
.SetBrush(*wxWHITE_BRUSH
);
3005 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
3006 dc
.DrawRoundedRectangle(topleft
.x
,
3007 topleft
.y
,bottomright
.x
-topleft
.x
,
3008 bottomright
.y
-topleft
.y
);
3009 dc
.SetBrush(*wxBLACK_BRUSH
);
3010 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
3011 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
3015 page
= "9999/9999 "; // many pages...
3017 dc
.GetTextExtent(page
,&w
,&h
);
3018 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
3019 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
3020 dc
.GetTextExtent("XXXX", &w
,&h
);
3021 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
3032 wxFontCache::GetFont(int family
, int size
, int style
, int weight
,
3035 for(wxFCEList::iterator i
= m_FontList
.begin();
3036 i
!= m_FontList
.end(); i
++)
3037 if( (**i
).Matches(family
, size
, style
, weight
, underline
) )
3038 return (**i
).GetFont();
3040 wxFontCacheEntry
*fce
= new wxFontCacheEntry(family
, size
, style
,
3042 m_FontList
.push_back(fce
);
3043 return fce
->GetFont();