1 /*-*- c++ -*-********************************************************
2 * wxllist: wxLayoutList, a layout engine for text and graphics *
4 * (C) 1998-1999 by Karsten Ballüder (Ballueder@usa.net) *
7 *******************************************************************/
14 #pragma implementation "wxllist.h"
20 #include "wx/wxprec.h"
26 # include "gui/wxllist.h"
27 # define SHOW_SELECTIONS 1
30 # include "wxlparser.h"
31 # define SHOW_SELECTIONS 1
35 # include "iostream.h"
38 # include <wx/print.h>
44 /// This should never really get created
45 #define WXLLIST_TEMPFILE "__wxllist.tmp"
49 # define TypewxString(t) g_aTypewxStrings[t]
50 # define WXLO_DEBUG(x) wxLogDebug x
52 static const char *g_aTypewxStrings
[] =
54 "invalid", "text", "cmd", "icon"
57 wxLayoutObject::Debug(void)
59 WXLO_DEBUG(("%s",g_aTypewxStrings
[GetType()]));
62 # define TypewxString(t) ""
63 # define WXLO_DEBUG(x)
67 /// Cursors smaller than this disappear in XOR drawing mode
68 #define WXLO_MINIMUM_CURSOR_WIDTH 4
70 /// Use this character to estimate a cursor size when none is available.
71 #define WXLO_CURSORCHAR "E"
72 /** @name Helper functions */
74 /// allows me to compare to wxPoints
75 bool operator ==(wxPoint
const &p1
, wxPoint
const &p2
)
77 return p1
.x
== p2
.x
&& p1
.y
== p2
.y
;
80 /// allows me to compare to wxPoints
81 bool operator !=(wxPoint
const &p1
, wxPoint
const &p2
)
83 return p1
.x
!= p2
.x
|| p1
.y
!= p2
.y
;
86 /// allows me to compare to wxPoints
87 bool operator <=(wxPoint
const &p1
, wxPoint
const &p2
)
89 return p1
.y
< p2
.y
|| (p1
.y
== p2
.y
&& p1
.x
<= p2
.x
);
92 /// grows a wxRect so that it includes the given point
95 void GrowRect(wxRect
&r
, CoordType x
, CoordType y
)
99 else if(r
.x
+ r
.width
< x
)
104 else if(r
.y
+ r
.height
< y
)
110 /// returns true if the point is in the rectangle
112 bool Contains(const wxRect
&r
, const wxPoint
&p
)
114 return r
.x
<= p
.x
&& r
.y
<= p
.y
&& (r
.x
+r
.width
) >= p
.x
&& (r
.y
+ r
.height
) >= p
.y
;
121 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
125 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
127 wxLayoutObjectText::wxLayoutObjectText(const wxString
&txt
)
137 wxLayoutObjectText::Copy(void)
139 wxLayoutObjectText
*obj
= new wxLayoutObjectText(m_Text
);
140 obj
->m_Width
= m_Width
;
141 obj
->m_Height
= m_Height
;
143 obj
->m_Bottom
= m_Bottom
;
144 obj
->SetUserData(m_UserData
);
149 wxLayoutObjectText::GetSize(CoordType
*top
, CoordType
*bottom
) const
152 *top
= m_Top
; *bottom
= m_Bottom
;
153 return wxPoint(m_Width
, m_Height
);
157 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &coords
,
158 wxLayoutList
*wxllist
,
159 CoordType begin
, CoordType end
)
162 dc
.DrawText(m_Text
, coords
.x
, coords
.y
-m_Top
);
165 // highlight the bit between begin and len
169 ypos
= coords
.y
-m_Top
;
170 long width
, height
, descent
;
172 str
= m_Text
.Mid(0, begin
);
173 dc
.DrawText(str
, xpos
, ypos
);
174 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
176 wxllist
->StartHighlighting(dc
);
177 str
= m_Text
.Mid(begin
, end
-begin
);
178 dc
.DrawText(str
, xpos
, ypos
);
179 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
181 wxllist
->EndHighlighting(dc
);
182 str
= m_Text
.Mid(end
, m_Text
.Length()-end
);
183 dc
.DrawText(str
, xpos
, ypos
);
188 wxLayoutObjectText::GetOffsetScreen(wxDC
&dc
, CoordType xpos
) const
192 maxlen
= m_Text
.Length();
195 height
, descent
= 0l;
197 if(xpos
== 0) return 0; // easy
199 while(width
< xpos
&& offs
< maxlen
)
201 dc
.GetTextExtent(m_Text
.substr(0,offs
),
202 &width
, &height
, &descent
);
205 /* We have to substract 1 to compensate for the offs++, and another
206 one because we don't want to position the cursor behind the
207 object what we clicked on, but before - otherwise it looks
209 return (xpos
> 2) ? offs
-2 : 0;
213 wxLayoutObjectText::Layout(wxDC
&dc
, class wxLayoutList
* )
217 dc
.GetTextExtent(m_Text
,&m_Width
, &m_Height
, &descent
);
219 m_Top
= m_Height
- m_Bottom
;
222 #ifdef WXLAYOUT_DEBUG
224 wxLayoutObjectText::Debug(void)
226 wxLayoutObject::Debug();
227 WXLO_DEBUG((" `%s`", m_Text
.c_str()));
231 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
235 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
237 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
const &icon
)
239 m_Icon
= new wxBitmap(icon
);
243 wxLayoutObjectIcon::Copy(void)
245 wxLayoutObjectIcon
*obj
= new wxLayoutObjectIcon(new
247 obj
->SetUserData(m_UserData
);
251 wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap
*icon
)
257 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &coords
,
258 wxLayoutList
*wxllist
,
259 CoordType begin
, CoordType
/* len */)
261 dc
.DrawBitmap(*m_Icon
, coords
.x
, coords
.y
-m_Icon
->GetHeight(),
262 (m_Icon
->GetMask() == NULL
) ? FALSE
: TRUE
);
266 wxLayoutObjectIcon::Layout(wxDC
& /* dc */, class wxLayoutList
* )
271 wxLayoutObjectIcon::GetSize(CoordType
*top
, CoordType
*bottom
) const
273 *top
= m_Icon
->GetHeight();
275 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
280 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
284 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
287 wxLayoutStyleInfo::wxLayoutStyleInfo(int ifamily
,
295 family
= ifamily
; size
= isize
;
296 style
= istyle
; weight
= iweight
;
314 #define COPY_SI_(what) if(right.what != -1) what = right.what;
317 wxLayoutStyleInfo::operator=(const wxLayoutStyleInfo
&right
)
324 if(right
.m_fg_valid
) m_fg
= right
.m_fg
;
325 if(right
.m_bg_valid
) m_bg
= right
.m_bg
;
329 wxLayoutObjectCmd::wxLayoutObjectCmd(int family
, int size
, int style
, int
330 weight
, int underline
,
331 wxColour
*fg
, wxColour
*bg
)
334 m_StyleInfo
= new wxLayoutStyleInfo(family
, size
,style
,weight
,underline
,fg
,bg
);
338 wxLayoutObjectCmd::Copy(void)
340 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
345 m_StyleInfo
->underline
,
346 m_StyleInfo
->m_fg_valid
?
347 &m_StyleInfo
->m_fg
: NULL
,
348 m_StyleInfo
->m_bg_valid
?
349 &m_StyleInfo
->m_bg
: NULL
);
350 obj
->SetUserData(m_UserData
);
355 wxLayoutObjectCmd::~wxLayoutObjectCmd()
361 wxLayoutObjectCmd::GetStyle(void) const
367 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
368 wxLayoutList
*wxllist
,
369 CoordType begin
, CoordType
/* len */)
371 wxASSERT(m_StyleInfo
);
372 wxllist
->ApplyStyle(m_StyleInfo
, dc
);
376 wxLayoutObjectCmd::Layout(wxDC
&dc
, class wxLayoutList
* llist
)
378 // this get called, so that recalculation uses right font sizes
379 Draw(dc
, wxPoint(0,0), llist
);
383 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
385 The wxLayoutLine object
387 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
389 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
392 m_Width
= m_Height
= 0;
397 RecalculatePosition(llist
);
400 m_LineNumber
= m_Previous
->GetLineNumber()+1;
401 m_Next
= m_Previous
->GetNextLine();
402 m_Previous
->m_Next
= this;
406 m_Next
->m_Previous
= this;
407 m_Next
->MoveLines(+1);
408 m_Next
->RecalculatePositions(1,llist
);
412 wxLayoutLine::~wxLayoutLine()
414 // kbList cleans itself
418 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
420 wxASSERT(m_Previous
|| GetLineNumber() == 0);
424 m_Position
= m_Previous
->GetPosition();
425 m_Position
.y
+= m_Previous
->GetHeight();
428 m_Position
= wxPoint(0,0);
429 llist
->SetUpdateRect(m_Position
);
434 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
436 wxASSERT(recurse
>= 0);
437 wxPoint pos
= m_Position
;
438 CoordType height
= m_Height
;
440 // WXLO_TRACE("RecalculatePositions()");
441 RecalculatePosition(llist
);
445 m_Next
->RecalculatePositions(--recurse
, llist
);
446 else if(pos
!= m_Position
|| m_Height
!= height
)
447 m_Next
->RecalculatePositions(0, llist
);
451 wxLayoutObjectList::iterator
452 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
456 wxLayoutObjectList::iterator
459 CoordType x
= 0, len
;
461 /* We search through the objects. As we don't like returning the
462 object that the cursor is behind, we just remember such an
463 object in "found" so we can return it if there is really no
464 further object following it. */
465 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
467 len
= (**i
).GetLength();
468 if( x
<= xpos
&& xpos
<= x
+ len
)
471 if(xpos
== x
+ len
) // is there another object behind?
473 else // we are really inside this object
476 x
+= (**i
).GetLength();
478 return found
; // ==NULL if really none found
481 wxLayoutObjectList::iterator
482 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
483 CoordType xpos
, CoordType
*cxpos
,
488 wxLayoutObjectList::iterator i
;
489 CoordType x
= 0, cx
= 0, width
;
491 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
493 width
= (**i
).GetWidth();
494 if( x
<= xpos
&& xpos
<= x
+ width
)
496 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
497 if(found
) *found
= true;
500 x
+= (**i
).GetWidth();
501 cx
+= (**i
).GetLength();
503 // behind last object:
505 if(found
) *found
= false;
506 return m_ObjectList
.tail();
509 /** Finds text in this line.
510 @param needle the text to find
511 @param xpos the position where to start the search
512 @return the cursoor coord where it was found or -1
515 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
) const
520 wxString
const *text
;
522 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
524 if(cpos
>= xpos
) // search from here!
526 if((**i
).GetType() == WXLO_TYPE_TEXT
)
528 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
529 relpos
= text
->Find(needle
);
530 if(relpos
>= cpos
-xpos
) // -1 if not found
535 cpos
+= (**i
).GetLength();
538 return -1; // not found
542 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
545 wxASSERT(obj
!= NULL
);
546 //FIXME: this could be optimised, for now be prudent:
549 wxLOiterator i
= FindObject(xpos
, &offset
);
552 if(xpos
== 0 ) // aha, empty line!
554 m_ObjectList
.push_back(obj
);
555 m_Length
+= obj
->GetLength();
562 CoordType len
= (**i
).GetLength();
563 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
564 { // insert before this object
565 m_ObjectList
.insert(i
,obj
);
566 m_Length
+= obj
->GetLength();
571 if( i
== m_ObjectList
.tail()) // last object?
572 m_ObjectList
.push_back(obj
);
574 { // insert after current object
576 m_ObjectList
.insert(i
,obj
);
578 m_Length
+= obj
->GetLength();
581 /* Otherwise we need to split the current object.
582 Fortunately this can only be a text object. */
583 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
584 wxString left
, right
;
585 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
586 left
= tobj
->GetText().substr(0,offset
);
587 right
= tobj
->GetText().substr(offset
,len
-offset
);
588 // current text object gets set to right half
589 tobj
->GetText() = right
; // set new text
590 // before it we insert the new object
591 m_ObjectList
.insert(i
,obj
);
592 m_Length
+= obj
->GetLength();
593 // and before that we insert the left half
594 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
599 wxLayoutLine::Insert(CoordType xpos
, wxString text
)
602 //FIXME: this could be optimised, for now be prudent:
605 wxLOiterator i
= FindObject(xpos
, &offset
);
606 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
608 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
609 tobj
->GetText().insert(offset
, text
);
610 m_Length
+= text
.Length();
615 return Insert(xpos
, new wxLayoutObjectText(text
));
619 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
621 CoordType offset
, len
;
625 //FIXME: this could be optimised, for now be prudent:
627 wxLOiterator i
= FindObject(xpos
, &offset
);
630 if(i
== NULLIT
) return npos
;
631 // now delete from that object:
632 if((**i
).GetType() != WXLO_TYPE_TEXT
)
634 if(offset
!= 0) // at end of line after a non-text object
637 len
= (**i
).GetLength();
640 m_ObjectList
.erase(i
);
644 // tidy up: remove empty text objects
645 if((**i
).GetLength() == 0)
647 m_ObjectList
.erase(i
);
651 CoordType max
= (**i
).GetLength() - offset
;
652 if(npos
< max
) max
= npos
;
655 if(xpos
== GetLength())
658 { // at the end of an object
659 // move to begin of next object:
661 continue; // start over
666 if(offset
== 0 && max
== (**i
).GetLength())
667 m_ObjectList
.erase(i
); // remove the whole object
669 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
676 wxLayoutLine::DeleteWord(CoordType xpos
)
680 //FIXME: this could be optimised, for now be prudent:
683 wxLOiterator i
= FindObject(xpos
, &offset
);
687 if(i
== NULLIT
) return false;
688 if((**i
).GetType() != WXLO_TYPE_TEXT
)
690 // This should only happen when at end of line, behind a non-text
692 if(offset
== (**i
).GetLength()) return false;
693 m_Length
-= (**i
).GetLength(); // -1
694 m_ObjectList
.erase(i
);
695 return true; // we are done
699 if(offset
== (**i
).GetLength()) // at end of object
704 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
706 wxString str
= tobj
->GetText();
707 str
= str
.substr(offset
,str
.Length()-offset
);
708 // Find out how many positions we need to delete:
709 // 1. eat leading space
710 while(isspace(str
.c_str()[count
])) count
++;
711 // 2. eat the word itself:
712 while(isalnum(str
.c_str()[count
])) count
++;
714 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
715 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
720 wxASSERT(0); // we should never arrive here
724 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
726 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
727 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
730 m_Next
->MoveLines(-1);
731 m_Next
->RecalculatePositions(1, llist
);
733 wxLayoutLine
*next
= m_Next
;
739 wxLayoutLine::Draw(wxDC
&dc
,
741 const wxPoint
& offset
) const
743 wxLayoutObjectList::iterator i
;
744 wxPoint pos
= offset
;
745 pos
= pos
+ GetPosition();
749 CoordType xpos
= 0; // cursorpos, lenght of line
751 CoordType from
, to
, tempto
;
752 //FIXME This doesn't work yet, needs updating afterr default
753 //settings for list or a wxLayoutObjectCmd have changed:
754 //llist->ApplyStyle(&((wxLayoutLine *)this)->m_StyleInfo, dc);
755 int highlight
= llist
->IsSelected(this, &from
, &to
);
756 // WXLO_DEBUG(("highlight=%d", highlight ));
757 if(highlight
== 1) // we need to draw the whole line inverted!
758 llist
->StartHighlighting(dc
);
760 llist
->EndHighlighting(dc
);
762 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
764 if(highlight
== -1) // partially highlight line
766 // parts of the line need highlighting
767 tempto
= xpos
+(**i
).GetLength();
768 if(tempto
>= from
&& xpos
<= to
)
771 if(tempto
> (**i
).GetLength())
772 tempto
= (**i
).GetLength();
773 CoordType tmp
= from
-xpos
;
775 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, tempto
);
779 llist
->EndHighlighting(dc
); // FIXME! inefficient
780 (**i
).Draw(dc
, pos
, llist
);
784 (**i
).Draw(dc
, pos
, llist
);
785 pos
.x
+= (**i
).GetWidth();
786 xpos
+= (**i
).GetLength();
791 wxLayoutLine::Layout(wxDC
&dc
,
797 wxLayoutObjectList::iterator i
;
800 oldHeight
= m_Height
;
802 topHeight
, bottomHeight
; // above and below baseline
805 objTopHeight
, objBottomHeight
;
808 m_Height
= 0; m_BaseLine
= 0;
810 topHeight
= 0; bottomHeight
= 0;
812 bool cursorFound
= false;
818 *cursorPos
= m_Position
;
819 if(cursorSize
) *cursorSize
= wxPoint(0,0);
822 //FIXME This doesn't work yet, needs updating afterr default
823 //settings for list or a wxLayoutObjectCmd have changed:
824 //llist->ApplyStyle(&m_StyleInfo, dc);
825 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
827 (**i
).Layout(dc
, llist
);
828 size
= (**i
).GetSize(&objTopHeight
, &objBottomHeight
);
830 if(cursorPos
&& ! cursorFound
)
831 { // we need to check whether the text cursor is here
832 len
= (**i
).GetLength();
833 if(count
<= cx
&& count
+len
> cx
)
835 if((**i
).GetType() == WXLO_TYPE_TEXT
)
837 len
= cx
- count
; // pos in object
838 CoordType width
, height
, descent
;
839 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
840 &width
, &height
, &descent
);
841 cursorPos
->x
+= width
;
842 cursorPos
->y
= m_Position
.y
;
844 if(len
< (**i
).GetLength())
845 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
847 str
= WXLO_CURSORCHAR
;
848 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
849 wxASSERT(cursorSize
);
850 // Just in case some joker inserted an empty string object:
851 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
852 if(height
== 0) height
= objHeight
;
853 cursorSize
->x
= width
;
854 cursorSize
->y
= height
;
855 cursorFound
= true; // no more checks
858 { // on some other object
859 CoordType top
, bottom
; // unused
860 *cursorSize
= (**i
).GetSize(&top
,&bottom
);
861 cursorPos
->y
= m_Position
.y
;
862 cursorFound
= true; // no more checks
868 cursorPos
->x
+= (**i
).GetWidth();
873 if(objHeight
> m_Height
) m_Height
= objHeight
;
874 if(objTopHeight
> topHeight
) topHeight
= objTopHeight
;
875 if(objBottomHeight
> bottomHeight
) bottomHeight
= objBottomHeight
;
877 if(topHeight
+ bottomHeight
> m_Height
) m_Height
=
878 topHeight
+bottomHeight
;
879 m_BaseLine
= topHeight
;
883 CoordType width
, height
, descent
;
884 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
886 m_BaseLine
= m_Height
- descent
;
890 // tell next line about coordinate change
891 if(m_Next
&& objHeight
!= oldHeight
)
892 m_Next
->RecalculatePositions(0, llist
);
894 // We need to check whether we found a valid cursor size:
897 // this might be the case if the cursor is at the end of the
898 // line or on a command object:
899 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
901 CoordType width
, height
, descent
;
902 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
903 cursorSize
->x
= width
;
904 cursorSize
->y
= height
;
906 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
907 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
909 RecalculatePositions(1, llist
);
914 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
917 //FIXME: this could be optimised, for now be prudent:
921 { // insert an empty line before this one
922 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
923 if(m_Previous
== NULL
)
924 { // We were in first line, need to link in new empty line
928 m_Previous
->m_Height
= GetHeight(); // this is a wild guess
932 m_Next
->RecalculatePositions(1, llist
);
937 wxLOiterator i
= FindObject(xpos
, &offset
);
939 // must be at the end of the line then
940 return new wxLayoutLine(this, llist
);
943 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
944 // split object at i:
945 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
947 wxString left
, right
;
948 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
949 left
= tobj
->GetText().substr(0,offset
);
950 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
951 // current text object gets set to left half
952 tobj
->GetText() = left
; // set new text
953 newLine
->Append(new wxLayoutObjectText(right
));
954 m_Length
-= right
.Length();
955 i
++; // don't move this object to the new list
959 i
++; // move objects from here to new list
961 while(i
!= m_ObjectList
.end())
964 m_Length
-= (**i
).GetLength();
965 m_ObjectList
.remove(i
); // remove without deleting it
968 m_Next
->RecalculatePositions(2, llist
);
974 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
976 wxASSERT(GetNextLine());
977 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
979 //FIXME: this could be optimised, for now be prudent:
982 for(i
= list
.begin(); i
!= list
.end();)
985 list
.remove(i
); // remove without deleting it
987 wxASSERT(list
.empty());
988 wxLayoutLine
*oldnext
= GetNextLine();
989 SetNext(GetNextLine()->GetNextLine());
991 RecalculatePositions(1, llist
);
995 wxLayoutLine::GetWrapPosition(CoordType column
)
998 wxLOiterator i
= FindObject(column
, &offset
);
999 if(i
== NULLIT
) return -1; // cannot wrap
1001 // go backwards through the list and look for space in text objects
1004 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1008 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1015 }while(offset
!= -1);
1016 i
--; // move on to previous object
1020 column
-= (**i
).GetLength();
1024 offset
= (**i
).GetLength();
1025 }while(i
!= NULLIT
);
1026 /* If we reached the begin of the list and have more than one
1027 object, that one is longer than the margin, so break behind
1030 i
= m_ObjectList
.begin();
1031 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1033 pos
+= (**i
).GetLength();
1036 if(i
== NULLIT
) return -1; //why should this happen?
1037 pos
+= (**i
).GetLength();
1039 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1041 pos
+= (**i
).GetLength();
1044 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1045 // now we are at the second text object:
1046 pos
-= (**i
).GetLength();
1047 return pos
; // in front of it
1051 #ifdef WXLAYOUT_DEBUG
1053 wxLayoutLine::Debug(void)
1056 wxPoint pos
= GetPosition();
1057 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld",
1058 (long int) GetLineNumber(),
1059 (long int) pos
.x
, (long int) pos
.y
,
1060 (long int) GetHeight()));
1061 if(m_ObjectList
.begin() != NULLIT
)
1062 (**m_ObjectList
.begin()).Debug();
1068 wxLayoutLine::Copy(wxLayoutList
*llist
,
1072 CoordType firstOffset
, lastOffset
;
1074 if(to
== -1) to
= GetLength();
1076 wxLOiterator first
= FindObject(from
, &firstOffset
);
1077 wxLOiterator last
= FindObject(to
, &lastOffset
);
1079 // Common special case: only one object
1080 if( *first
== *last
)
1082 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1084 llist
->Insert(new wxLayoutObjectText(
1085 ((wxLayoutObjectText
1086 *)*first
)->GetText().substr(firstOffset
,
1087 lastOffset
-firstOffset
))
1091 else // what can we do?
1093 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1094 llist
->Insert( (**first
).Copy() );
1099 // If we reach here, we can safely copy the whole first object from
1100 // the firstOffset position on:
1101 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1103 llist
->Insert(new wxLayoutObjectText(
1104 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1107 else if(firstOffset
== 0)
1108 llist
->Insert( (**first
).Copy() );
1109 // else nothing to copy :-(
1111 // Now we copy all objects before the last one:
1112 wxLOiterator i
= first
; i
++;
1113 for( ; i
!= last
; i
++)
1114 llist
->Insert( (**i
).Copy() );
1116 // And now the last object:
1119 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1121 llist
->Insert(new wxLayoutObjectText(
1122 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1126 llist
->Insert( (**last
).Copy() );
1130 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1132 The wxLayoutList object
1134 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1136 wxLayoutList::wxLayoutList()
1139 InvalidateUpdateRect();
1143 wxLayoutList::~wxLayoutList()
1146 m_FirstLine
->DeleteLine(false, this);
1150 wxLayoutList::Empty(void)
1153 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1155 m_CursorPos
= wxPoint(0,0);
1156 m_CursorScreenPos
= wxPoint(0,0);
1157 m_CursorSize
= wxPoint(0,0);
1158 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1159 m_CursorLine
= m_FirstLine
;
1160 InvalidateUpdateRect();
1165 wxLayoutList::InternalClear(void)
1168 m_Selection
.m_selecting
= false;
1169 m_Selection
.m_valid
= false;
1171 m_DefaultSetting
.family
= wxSWISS
;
1172 m_DefaultSetting
.size
= WXLO_DEFAULTFONTSIZE
;
1173 m_DefaultSetting
.style
= wxNORMAL
;
1174 m_DefaultSetting
.weight
= wxNORMAL
;
1175 m_DefaultSetting
.underline
= 0;
1176 m_DefaultSetting
.m_fg_valid
= TRUE
;
1177 m_DefaultSetting
.m_fg
= *wxBLACK
;
1178 m_DefaultSetting
.m_bg_valid
= TRUE
;
1179 m_DefaultSetting
.m_bg
= *wxWHITE
;
1181 m_CurrentSetting
= m_DefaultSetting
;
1185 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1186 int underline
, wxColour
*fg
,
1189 if(family
!= -1) m_CurrentSetting
.family
= family
;
1190 if(size
!= -1) m_CurrentSetting
.size
= size
;
1191 if(style
!= -1) m_CurrentSetting
.style
= style
;
1192 if(weight
!= -1) m_CurrentSetting
.weight
= weight
;
1193 if(underline
!= -1) m_CurrentSetting
.underline
= underline
!= 0;
1194 if(fg
) m_CurrentSetting
.m_fg
= *fg
;
1195 if(bg
) m_CurrentSetting
.m_bg
= *bg
;
1197 new wxLayoutObjectCmd(
1198 m_CurrentSetting
.family
,
1199 m_CurrentSetting
.size
,
1200 m_CurrentSetting
.style
,
1201 m_CurrentSetting
.weight
,
1202 m_CurrentSetting
.underline
,
1207 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1208 int underline
, char const *fg
, char const *bg
)
1216 cfg
= wxTheColourDatabase
->FindColour(fg
);
1218 cbg
= wxTheColourDatabase
->FindColour(bg
);
1220 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
1224 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1225 int underline
, wxColour
*fg
, wxColour
*bg
)
1228 m_DefaultSetting
= wxLayoutStyleInfo(family
, size
, style
, weight
,
1230 m_CurrentSetting
= m_DefaultSetting
;
1234 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1239 for(line
= m_FirstLine
;
1241 line
= line
->GetNextLine())
1243 if(line
->GetLineNumber() >= cpos
.y
)
1245 xpos
= line
->FindText(needle
,
1246 (line
->GetLineNumber() == cpos
.y
) ?
1249 return wxPoint(xpos
, line
->GetLineNumber());
1252 return wxPoint(-1,-1);
1257 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1259 SetUpdateRect(m_CursorScreenPos
);
1260 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1261 wxLayoutLine
*line
= m_FirstLine
;
1262 while(line
&& line
->GetLineNumber() != p
.y
)
1263 line
= line
->GetNextLine();
1264 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1266 m_CursorPos
.y
= p
.y
;
1267 m_CursorLine
= line
;
1268 CoordType len
= line
->GetLength();
1271 m_CursorPos
.x
= p
.x
;
1276 m_CursorPos
.x
= len
;
1284 wxLayoutList::MoveCursorVertically(int n
)
1286 SetUpdateRect(m_CursorScreenPos
);
1287 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1289 if(n
< 0) // move up
1291 if(m_CursorLine
== m_FirstLine
) return false;
1292 while(n
< 0 && m_CursorLine
)
1294 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1300 m_CursorLine
= m_FirstLine
;
1306 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1307 m_CursorPos
.x
= m_CursorLine
->GetLength();
1313 wxLayoutLine
*last
= m_CursorLine
;
1314 if(! m_CursorLine
->GetNextLine()) return false;
1315 while(n
> 0 && m_CursorLine
)
1319 m_CursorLine
= m_CursorLine
->GetNextLine();
1323 m_CursorLine
= last
;
1329 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1330 m_CursorPos
.x
= m_CursorLine
->GetLength();
1338 wxLayoutList::MoveCursorHorizontally(int n
)
1340 SetUpdateRect(m_CursorScreenPos
);
1341 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1345 if(m_CursorPos
.x
== 0) // at begin of line
1347 if(! MoveCursorVertically(-1))
1349 MoveCursorToEndOfLine();
1354 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1355 m_CursorPos
.x
-= move
; n
+= move
;
1360 int len
= m_CursorLine
->GetLength();
1361 if(m_CursorPos
.x
== len
) // at end of line
1363 if(! MoveCursorVertically(1))
1365 MoveCursorToBeginOfLine();
1370 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1371 m_CursorPos
.x
+= move
;
1378 wxLayoutList::Insert(wxString
const &text
)
1380 wxASSERT(m_CursorLine
);
1381 SetUpdateRect(m_CursorScreenPos
);
1382 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1383 m_CursorLine
->Insert(m_CursorPos
.x
, text
);
1384 m_CursorPos
.x
+= text
.Length();
1385 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1390 wxLayoutList::Insert(wxLayoutObject
*obj
)
1392 wxASSERT(m_CursorLine
);
1393 SetUpdateRect(m_CursorScreenPos
);
1394 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1395 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1396 m_CursorPos
.x
+= obj
->GetLength();
1397 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1402 wxLayoutList::LineBreak(void)
1404 wxASSERT(m_CursorLine
);
1405 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1406 SetUpdateRect(m_CursorScreenPos
);
1407 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1408 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1409 if(setFirst
) // we were at beginning of first line
1410 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1413 // doesn't help m_CursorLine.MarkDirty();
1414 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1419 wxLayoutList::WrapLine(CoordType column
)
1421 if(m_CursorPos
.x
<= column
|| column
< 1)
1422 return false; // do nothing yet
1425 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1427 return false; // cannot break line
1429 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1430 m_CursorPos
.x
= xpos
;
1431 SetUpdateRect(m_CursorScreenPos
);
1432 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1434 Delete(1); // delete the space
1435 m_CursorPos
.x
= newpos
;
1436 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1442 wxLayoutList::Delete(CoordType npos
)
1444 wxASSERT(m_CursorLine
);
1445 SetUpdateRect(m_CursorScreenPos
);
1446 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1450 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1453 // More to delete, continue on next line.
1454 // First, check if line is empty:
1455 if(m_CursorLine
->GetLength() == 0)
1456 { // in this case, updating could probably be optimised
1458 wxASSERT(DeleteLines(1) == 0);
1467 // Need to join next line
1468 if(! m_CursorLine
->GetNextLine())
1472 m_CursorLine
->MergeNextLine(this);
1478 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1483 wxLayoutList::DeleteLines(int n
)
1485 wxASSERT(m_CursorLine
);
1487 SetUpdateRect(m_CursorScreenPos
);
1488 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1491 if(!m_CursorLine
->GetNextLine())
1492 { // we cannot delete this line, but we can clear it
1493 MoveCursorToBeginOfLine();
1494 DeleteToEndOfLine();
1495 m_CursorLine
->RecalculatePositions(2, this);
1499 line
= m_CursorLine
;
1500 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
1502 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
1503 wxASSERT(m_FirstLine
);
1504 wxASSERT(m_CursorLine
);
1506 m_CursorLine
->RecalculatePositions(2, this);
1511 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
1513 wxLayoutLine
*line
= m_FirstLine
;
1515 // first, make sure everything is calculated - this might not be
1516 // needed, optimise it later
1517 ApplyStyle(&m_DefaultSetting
, dc
);
1520 line
->RecalculatePosition(this); // so we don't need to do it all the time
1521 // little condition to speed up redrawing:
1522 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1523 line
= line
->GetNextLine();
1528 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
)
1530 wxASSERT(m_CursorLine
);
1531 m_CursorLine
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1535 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
1537 UpdateCursorScreenPos(dc
);
1538 return m_CursorScreenPos
;
1542 Is called before each Draw(). Now, it will re-layout all lines which
1546 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
, bool forceAll
)
1548 wxLayoutLine
*line
= m_FirstLine
;
1550 // first, make sure everything is calculated - this might not be
1551 // needed, optimise it later
1552 ApplyStyle(&m_DefaultSetting
, dc
);
1555 if(forceAll
|| line
->IsDirty())
1557 line
->GetStyleInfo() = m_CurrentSetting
;
1558 if(line
== m_CursorLine
)
1559 line
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
,
1560 (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1562 line
->Layout(dc
, this);
1563 line
->RecalculatePosition(this);
1564 // little condition to speed up redrawing:
1565 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1567 line
= line
->GetNextLine();
1570 ///FIXME: disabled for now
1572 // can only be 0 if we are on the first line and have no next line
1573 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1574 m_CursorLine
->GetNextLine() == NULL
&&
1575 m_CursorLine
== m_FirstLine
));
1577 SetUpdateRect(m_CursorScreenPos
);
1578 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1582 wxLayoutList::Draw(wxDC
&dc
,
1583 wxPoint
const &offset
,
1587 wxLayoutLine
*line
= m_FirstLine
;
1590 ApplyStyle(&m_DefaultSetting
, dc
);
1591 wxBrush
brush(m_CurrentSetting
.m_bg
, wxSOLID
);
1596 // only draw if between top and bottom:
1597 if((top
== -1 || line
->GetPosition().y
+ line
->GetHeight() >= top
))
1598 line
->Draw(dc
, this, offset
);
1599 // little condition to speed up redrawing:
1600 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1601 line
= line
->GetNextLine();
1603 InvalidateUpdateRect();
1605 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
1606 m_Selection
.m_valid
? "valid" : "invalid",
1607 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
1608 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
1612 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
1616 // First, find the right line:
1617 wxLayoutLine
*line
= m_FirstLine
;
1620 // we need to run a layout here to get font sizes right :-(
1621 ApplyStyle(&m_DefaultSetting
, dc
);
1624 p
= line
->GetPosition();
1625 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
1627 line
->Layout(dc
, this);
1628 line
= line
->GetNextLine();
1632 if(found
) *found
= false;
1633 return NULL
; // not found
1635 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
1636 // Now, find the object in the line:
1637 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
1638 cursorPos
? & cursorPos
->x
: NULL
,
1640 return (i
== NULLIT
) ? NULL
: *i
;
1645 wxLayoutList::GetSize(void) const
1648 *line
= m_FirstLine
,
1651 return wxPoint(0,0);
1653 wxPoint
maxPoint(0,0);
1658 if(line
->GetWidth() > maxPoint
.x
)
1659 maxPoint
.x
= line
->GetWidth();
1661 line
= line
->GetNextLine();
1664 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
1670 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
1673 coords
= m_CursorScreenPos
;
1674 coords
.x
+= translate
.x
;
1675 coords
.y
+= translate
.y
;
1677 #ifdef WXLAYOUT_DEBUG
1678 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
1679 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
1680 (long)coords
.x
, (long)coords
.y
,
1681 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
1682 (long)m_CursorLine
->GetLineNumber(),
1683 (long)m_CursorLine
->GetLength()));
1686 dc
.SetBrush(*wxBLACK_BRUSH
);
1687 dc
.SetLogicalFunction(wxXOR
);
1688 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
1691 dc
.DrawRectangle(coords
.x
, coords
.y
,
1692 m_CursorSize
.x
, m_CursorSize
.y
);
1693 SetUpdateRect(coords
.x
, coords
.y
);
1694 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
1698 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
1699 coords
.x
, coords
.y
);
1700 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
1701 SetUpdateRect(coords
.x
, coords
.y
);
1703 dc
.SetLogicalFunction(wxCOPY
);
1704 //dc.SetBrush(wxNullBrush);
1708 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
1710 if(m_UpdateRectValid
)
1711 GrowRect(m_UpdateRect
, x
, y
);
1716 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
1717 m_UpdateRect
.height
= 4;// wxGTK :-)
1718 m_UpdateRectValid
= true;
1723 wxLayoutList::StartSelection(void)
1725 WXLO_DEBUG(("Starting selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1726 m_Selection
.m_CursorA
= m_CursorPos
;
1727 m_Selection
.m_CursorB
= m_CursorPos
;
1728 m_Selection
.m_selecting
= true;
1729 m_Selection
.m_valid
= false;
1733 wxLayoutList::ContinueSelection(void)
1735 wxASSERT(m_Selection
.m_selecting
== true);
1736 wxASSERT(m_Selection
.m_valid
== false);
1737 WXLO_DEBUG(("Continuing selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1738 m_Selection
.m_CursorB
= m_CursorPos
;
1739 // We always want m_CursorA <= m_CursorB!
1740 if(! (m_Selection
.m_CursorA
<= m_Selection
.m_CursorB
))
1742 wxPoint help
= m_Selection
.m_CursorB
;
1743 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
1744 m_Selection
.m_CursorA
= help
;
1749 wxLayoutList::EndSelection(void)
1751 ContinueSelection();
1752 WXLO_DEBUG(("Ending selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1753 m_Selection
.m_selecting
= false;
1754 m_Selection
.m_valid
= true;
1759 wxLayoutList::IsSelecting(void)
1761 return m_Selection
.m_selecting
;
1765 wxLayoutList::IsSelected(const wxPoint
&cursor
)
1767 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1769 return m_Selection
.m_CursorA
<= cursor
1770 && cursor
<= m_Selection
.m_CursorB
;
1774 /** Tests whether this layout line is selected and needs
1776 @param line to test for
1777 @return 0 = not selected, 1 = fully selected, -1 = partially
1781 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
1784 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
1786 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1789 CoordType y
= line
->GetLineNumber();
1790 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
1792 else if(m_Selection
.m_CursorA
.y
== y
)
1794 *from
= m_Selection
.m_CursorA
.x
;
1795 if(m_Selection
.m_CursorB
.y
== y
)
1796 *to
= m_Selection
.m_CursorB
.x
;
1798 *to
= line
->GetLength();
1801 else if(m_Selection
.m_CursorB
.y
== y
)
1803 *to
= m_Selection
.m_CursorB
.x
;
1804 if(m_Selection
.m_CursorA
.y
== y
)
1805 *from
= m_Selection
.m_CursorA
.x
;
1815 wxLayoutList::DeleteSelection(void)
1817 if(! m_Selection
.m_valid
)
1820 m_Selection
.m_valid
= false;
1822 // Only delete part of the current line?
1823 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
1825 MoveCursorTo(m_Selection
.m_CursorA
);
1826 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
1835 for(firstLine
= m_FirstLine
;
1836 firstLine
&& firstLine
->GetLineNumber() < m_Selection
.m_CursorA
.y
;
1837 firstLine
=firstLine
->GetNextLine())
1839 if(!firstLine
|| firstLine
->GetLineNumber() != m_Selection
.m_CursorA
.y
)
1843 for(lastLine
= m_FirstLine
;
1844 lastLine
&& lastLine
->GetLineNumber() < m_Selection
.m_CursorB
.y
;
1845 lastLine
=lastLine
->GetNextLine())
1847 if(!lastLine
|| lastLine
->GetLineNumber() != m_Selection
.m_CursorB
.y
)
1851 // We now know that the two lines are different:
1853 // First, delete what's left of this line:
1854 MoveCursorTo(m_Selection
.m_CursorA
);
1855 DeleteToEndOfLine();
1857 wxLayoutLine
*nextLine
= firstLine
->GetNextLine();
1858 while(nextLine
&& nextLine
!= lastLine
)
1859 nextLine
= nextLine
->DeleteLine(false, this);
1861 // Now nextLine = lastLine;
1862 Delete(1); // This joins firstLine and nextLine
1863 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x
1867 firstLine
->RecalculatePositions(1, this);
1870 /// Starts highlighting the selection
1872 wxLayoutList::StartHighlighting(wxDC
&dc
)
1875 dc
.SetTextForeground(m_CurrentSetting
.m_bg
);
1876 dc
.SetTextBackground(m_CurrentSetting
.m_fg
);
1880 /// Ends highlighting the selection
1882 wxLayoutList::EndHighlighting(wxDC
&dc
)
1885 dc
.SetTextForeground(m_CurrentSetting
.m_fg
);
1886 dc
.SetTextBackground(m_CurrentSetting
.m_bg
);
1892 wxLayoutList::Copy(const wxPoint
&from
,
1899 for(firstLine
= m_FirstLine
;
1900 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
1901 firstLine
=firstLine
->GetNextLine())
1903 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
1906 for(lastLine
= m_FirstLine
;
1907 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
1908 lastLine
=lastLine
->GetNextLine())
1910 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
1915 wxLayoutLine
*tmp
= firstLine
;
1916 firstLine
= lastLine
;
1920 wxLayoutList
*llist
= new wxLayoutList();
1922 if(firstLine
== lastLine
)
1924 firstLine
->Copy(llist
, from
.x
, to
.x
);
1928 // Extract objects from first line
1929 firstLine
->Copy(llist
, from
.x
);
1931 // Extract all lines between
1932 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
1934 line
= line
->GetNextLine())
1939 // Extract objects from last line
1940 lastLine
->Copy(llist
, 0, to
.x
);
1946 wxLayoutList::GetSelection(void)
1948 if(! m_Selection
.m_valid
)
1950 if(m_Selection
.m_selecting
)
1956 m_Selection
.m_valid
= false;
1957 return Copy( m_Selection
.m_CursorA
, m_Selection
.m_CursorB
);
1962 #define COPY_SI(what) if(si->what != -1) { m_CurrentSetting.what = si->what; fontChanged = TRUE; }
1965 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
*si
, wxDC
&dc
)
1967 bool fontChanged
= FALSE
;
1974 dc
.SetFont( m_FontCache
.GetFont(m_CurrentSetting
) );
1978 m_CurrentSetting
.m_fg
= si
->m_fg
;
1979 dc
.SetTextForeground(m_CurrentSetting
.m_fg
);
1983 m_CurrentSetting
.m_bg
= si
->m_bg
;
1984 dc
.SetTextBackground(m_CurrentSetting
.m_bg
);
1989 #ifdef WXLAYOUT_DEBUG
1992 wxLayoutList::Debug(void)
1997 for(line
= m_FirstLine
;
1999 line
= line
->GetNextLine())
2006 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2010 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2013 wxString
const & title
)
2020 wxLayoutPrintout::~wxLayoutPrintout()
2025 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2027 // The following bit is taken from the printing sample, let's see
2028 // whether it works for us.
2030 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2031 * the screen text size. This page also draws lines of actual length 5cm
2034 // Get the logical pixels per inch of screen and printer
2035 int ppiScreenX
, ppiScreenY
;
2036 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2037 int ppiPrinterX
, ppiPrinterY
;
2038 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2040 if(ppiScreenX
== 0) // not yet set, need to guess
2045 if(ppiPrinterX
== 0) // not yet set, need to guess
2051 // This scales the DC so that the printout roughly represents the
2052 // the screen scaling. The text point size _should_ be the right size
2053 // but in fact is too small for some reason. This is a detail that will
2054 // need to be addressed at some point but can be fudged for the
2056 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2058 // Now we have to check in case our real page size is reduced
2059 // (e.g. because we're drawing to a print preview memory DC)
2060 int pageWidth
, pageHeight
;
2062 dc
->GetSize(&w
, &h
);
2063 GetPageSizePixels(&pageWidth
, &pageHeight
);
2064 if(pageWidth
!= 0) // doesn't work always
2066 // If printer pageWidth == current DC width, then this doesn't
2067 // change. But w might be the preview bitmap width, so scale down.
2068 scale
= scale
* (float)(w
/(float)pageWidth
);
2070 dc
->SetUserScale(scale
, scale
);
2074 bool wxLayoutPrintout::OnPrintPage(int page
)
2083 top
= (page
- 1)*m_PrintoutHeight
;
2084 bottom
= top
+ m_PrintoutHeight
;
2085 // SetDeviceOrigin() doesn't work here, so we need to manually
2086 // translate all coordinates.
2087 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2088 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2095 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2097 /* We allocate a temporary wxDC for printing, so that we can
2098 determine the correct paper size and scaling. We don't actually
2099 print anything on it. */
2101 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2103 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2106 float scale
= ScaleDC(&psdc
);
2108 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2109 // This sets a left/top origin of 15% and 20%:
2110 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
2112 // This is the length of the printable area.
2113 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
2114 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2118 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2121 *maxPage
= m_NumOfPages
;
2124 *selPageTo
= m_NumOfPages
;
2125 wxRemoveFile(WXLLIST_TEMPFILE
);
2128 bool wxLayoutPrintout::HasPage(int pageNum
)
2130 return pageNum
<= m_NumOfPages
;
2134 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2135 out. It's a waste of paper anyway.
2139 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2140 wxPoint topleft
, wxPoint bottomright
,
2143 // make backups of all essential parameters
2144 const wxBrush
& brush
= dc
.GetBrush();
2145 const wxPen
& pen
= dc
.GetPen();
2146 const wxFont
& font
= dc
.GetFont();
2148 dc
.SetBrush(*wxWHITE_BRUSH
);
2149 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
2150 dc
.DrawRoundedRectangle(topleft
.x
,
2151 topleft
.y
,bottomright
.x
-topleft
.x
,
2152 bottomright
.y
-topleft
.y
);
2153 dc
.SetBrush(*wxBLACK_BRUSH
);
2154 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
2155 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
2159 page
= "9999/9999 "; // many pages...
2161 dc
.GetTextExtent(page
,&w
,&h
);
2162 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
2163 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
2164 dc
.GetTextExtent("XXXX", &w
,&h
);
2165 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
2176 wxFontCache::GetFont(int family
, int size
, int style
, int weight
,
2179 for(wxFCEList::iterator i
= m_FontList
.begin();
2180 i
!= m_FontList
.end(); i
++)
2181 if( (**i
).Matches(family
, size
, style
, weight
, underline
) )
2182 return (**i
).GetFont();
2184 wxFontCacheEntry
*fce
= new wxFontCacheEntry(family
, size
, style
,
2186 m_FontList
.push_back(fce
);
2187 return fce
->GetFont();