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
;
302 fg_blue
= fg
->Blue();
303 fg_green
= fg
->Green();
311 bg_blue
= bg
->Blue();
312 bg_green
= bg
->Green();
318 #define SET_SI(what) tmp.what = (what != -1) ? what : ( si ? si->what : wxNORMAL);
322 wxLayoutStyleInfo::GetFont(wxLayoutStyleInfo
*si
)
324 wxLayoutStyleInfo tmp
;
332 return new wxFont(tmp
.size
,tmp
.family
,tmp
.style
,tmp
.weight
,tmp
.underline
);
336 wxLayoutObjectCmd::wxLayoutObjectCmd(int size
, int family
, int style
, int
337 weight
, int underline
,
338 wxColour
*fg
, wxColour
*bg
)
342 wxLayoutStyleInfo(size
,family
,style
,weight
,underline
,fg
,bg
);
343 m_font
= m_StyleInfo
->GetFont(NULL
);
347 wxLayoutObjectCmd::Copy(void)
352 if(m_StyleInfo
->fg_valid
)
354 wxColour(m_StyleInfo
->fg_red
,m_StyleInfo
->fg_green
,m_StyleInfo
->fg_blue
);
355 if(m_StyleInfo
->bg_valid
)
357 wxColour(m_StyleInfo
->bg_red
,m_StyleInfo
->bg_green
,m_StyleInfo
->bg_blue
);
359 wxLayoutObjectCmd
*obj
= new wxLayoutObjectCmd(
364 m_StyleInfo
->underline
,
366 obj
->SetUserData(m_UserData
);
374 wxLayoutObjectCmd::~wxLayoutObjectCmd()
381 wxLayoutObjectCmd::GetStyle(void) const
387 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const & /* coords */,
388 wxLayoutList
*wxllist
,
389 CoordType begin
, CoordType
/* len */)
391 wxASSERT(m_StyleInfo
);
393 wxllist
->ApplyStyle(m_StyleInfo
, dc
);
397 wxLayoutObjectCmd::Layout(wxDC
&dc
, class wxLayoutList
* llist
)
399 // this get called, so that recalculation uses right font sizes
400 Draw(dc
, wxPoint(0,0), llist
);
404 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
406 The wxLayoutLine object
408 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
410 wxLayoutLine::wxLayoutLine(wxLayoutLine
*prev
, wxLayoutList
*llist
)
413 m_Width
= m_Height
= 0;
418 RecalculatePosition(llist
);
421 m_LineNumber
= m_Previous
->GetLineNumber()+1;
422 m_Next
= m_Previous
->GetNextLine();
423 m_Previous
->m_Next
= this;
424 m_Height
= m_Previous
->GetHeight();
428 m_Next
->m_Previous
= this;
429 m_Next
->MoveLines(+1);
430 m_Next
->RecalculatePositions(1,llist
);
434 wxLayoutLine::~wxLayoutLine()
436 // kbList cleans itself
440 wxLayoutLine::RecalculatePosition(wxLayoutList
*llist
)
442 wxASSERT(m_Previous
|| GetLineNumber() == 0);
446 m_Position
= m_Previous
->GetPosition();
447 m_Position
.y
+= m_Previous
->GetHeight();
450 m_Position
= wxPoint(0,0);
451 llist
->SetUpdateRect(m_Position
);
456 wxLayoutLine::RecalculatePositions(int recurse
, wxLayoutList
*llist
)
458 wxASSERT(recurse
>= 0);
459 wxPoint pos
= m_Position
;
460 CoordType height
= m_Height
;
462 // WXLO_TRACE("RecalculatePositions()");
463 RecalculatePosition(llist
);
467 m_Next
->RecalculatePositions(--recurse
, llist
);
468 else if(pos
!= m_Position
|| m_Height
!= height
)
469 m_Next
->RecalculatePositions(0, llist
);
473 wxLayoutObjectList::iterator
474 wxLayoutLine::FindObject(CoordType xpos
, CoordType
*offset
) const
478 wxLayoutObjectList::iterator
481 CoordType x
= 0, len
;
483 /* We search through the objects. As we don't like returning the
484 object that the cursor is behind, we just remember such an
485 object in "found" so we can return it if there is really no
486 further object following it. */
487 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
489 len
= (**i
).GetLength();
490 if( x
<= xpos
&& xpos
<= x
+ len
)
493 if(xpos
== x
+ len
) // is there another object behind?
495 else // we are really inside this object
498 x
+= (**i
).GetLength();
500 return found
; // ==NULL if really none found
503 wxLayoutObjectList::iterator
504 wxLayoutLine::FindObjectScreen(wxDC
&dc
,
505 CoordType xpos
, CoordType
*cxpos
,
510 wxLayoutObjectList::iterator i
;
511 CoordType x
= 0, cx
= 0, width
;
513 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
515 //FIXME! (**i).Layout(dc, NULL);
516 width
= (**i
).GetWidth();
517 if( x
<= xpos
&& xpos
<= x
+ width
)
519 *cxpos
= cx
+ (**i
).GetOffsetScreen(dc
, xpos
-x
);
520 // WXLO_DEBUG(("wxLayoutLine::FindObjectScreen: cursor xpos = %ld", *cxpos));
521 if(found
) *found
= true;
524 x
+= (**i
).GetWidth();
525 cx
+= (**i
).GetLength();
527 // behind last object:
529 if(found
) *found
= false;
530 return m_ObjectList
.tail();
533 /** Finds text in this line.
534 @param needle the text to find
535 @param xpos the position where to start the search
536 @return the cursoor coord where it was found or -1
539 wxLayoutLine::FindText(const wxString
&needle
, CoordType xpos
= 0) const
544 wxString
const *text
;
546 for(wxLOiterator i
= m_ObjectList
.begin(); i
!= m_ObjectList
.end(); i
++)
548 if(cpos
>= xpos
) // search from here!
550 if((**i
).GetType() == WXLO_TYPE_TEXT
)
552 text
= & ((wxLayoutObjectText
*)(*i
))->GetText();
553 relpos
= text
->Find(needle
);
554 if(relpos
>= cpos
-xpos
) // -1 if not found
559 cpos
+= (**i
).GetLength();
562 return -1; // not found
566 wxLayoutLine::Insert(CoordType xpos
, wxLayoutObject
*obj
)
569 wxASSERT(obj
!= NULL
);
571 wxLOiterator i
= FindObject(xpos
, &offset
);
574 if(xpos
== 0 ) // aha, empty line!
576 m_ObjectList
.push_back(obj
);
577 m_Length
+= obj
->GetLength();
584 CoordType len
= (**i
).GetLength();
585 if(offset
== 0 /*&& i != m_ObjectList.begin()*/) // why?
586 { // insert before this object
587 m_ObjectList
.insert(i
,obj
);
588 m_Length
+= obj
->GetLength();
593 if( i
== m_ObjectList
.tail()) // last object?
594 m_ObjectList
.push_back(obj
);
596 { // insert after current object
598 m_ObjectList
.insert(i
,obj
);
600 m_Length
+= obj
->GetLength();
603 /* Otherwise we need to split the current object.
604 Fortunately this can only be a text object. */
605 wxASSERT((**i
).GetType() == WXLO_TYPE_TEXT
);
606 wxString left
, right
;
607 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
608 left
= tobj
->GetText().substr(0,offset
);
609 right
= tobj
->GetText().substr(offset
,len
-offset
);
610 // current text object gets set to right half
611 tobj
->GetText() = right
; // set new text
612 // before it we insert the new object
613 m_ObjectList
.insert(i
,obj
);
614 m_Length
+= obj
->GetLength();
615 // and before that we insert the left half
616 m_ObjectList
.insert(i
,new wxLayoutObjectText(left
));
621 wxLayoutLine::Insert(CoordType xpos
, wxString text
)
625 wxLOiterator i
= FindObject(xpos
, &offset
);
626 if(i
!= NULLIT
&& (**i
).GetType() == WXLO_TYPE_TEXT
)
628 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
629 tobj
->GetText().insert(offset
, text
);
630 m_Length
+= text
.Length();
635 return Insert(xpos
, new wxLayoutObjectText(text
));
639 wxLayoutLine::Delete(CoordType xpos
, CoordType npos
)
641 CoordType offset
, len
;
645 wxLOiterator i
= FindObject(xpos
, &offset
);
648 if(i
== NULLIT
) return npos
;
649 // now delete from that object:
650 if((**i
).GetType() != WXLO_TYPE_TEXT
)
652 if(offset
!= 0) // at end of line after a non-text object
655 len
= (**i
).GetLength();
658 m_ObjectList
.erase(i
);
662 // tidy up: remove empty text objects
663 if((**i
).GetLength() == 0)
665 m_ObjectList
.erase(i
);
669 CoordType max
= (**i
).GetLength() - offset
;
670 if(npos
< max
) max
= npos
;
673 if(xpos
== GetLength())
676 { // at the end of an object
677 // move to begin of next object:
679 continue; // start over
684 if(offset
== 0 && max
== (**i
).GetLength())
685 m_ObjectList
.erase(i
); // remove the whole object
687 ((wxLayoutObjectText
*)(*i
))->GetText().Remove(offset
,max
);
694 wxLayoutLine::DeleteWord(CoordType xpos
)
699 wxLOiterator i
= FindObject(xpos
, &offset
);
703 if(i
== NULLIT
) return false;
704 if((**i
).GetType() != WXLO_TYPE_TEXT
)
706 // This should only happen when at end of line, behind a non-text
708 if(offset
== (**i
).GetLength()) return false;
709 m_Length
-= (**i
).GetLength(); // -1
710 m_ObjectList
.erase(i
);
711 return true; // we are done
715 if(offset
== (**i
).GetLength()) // at end of object
720 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
722 wxString str
= tobj
->GetText();
723 str
= str
.substr(offset
,str
.Length()-offset
);
724 // Find out how many positions we need to delete:
725 // 1. eat leading space
726 while(isspace(str
.c_str()[count
])) count
++;
727 // 2. eat the word itself:
728 while(isalnum(str
.c_str()[count
])) count
++;
730 wxASSERT(count
+offset
<= (size_t) (**i
).GetLength());
731 ((wxLayoutObjectText
*)*i
)->GetText().erase(offset
,count
);
736 wxASSERT(0); // we should never arrive here
740 wxLayoutLine::DeleteLine(bool update
, wxLayoutList
*llist
)
742 if(m_Next
) m_Next
->m_Previous
= m_Previous
;
743 if(m_Previous
) m_Previous
->m_Next
= m_Next
;
746 m_Next
->MoveLines(-1);
747 m_Next
->RecalculatePositions(1, llist
);
749 wxLayoutLine
*next
= m_Next
;
755 wxLayoutLine::Draw(wxDC
&dc
,
757 const wxPoint
& offset
) const
759 wxLayoutObjectList::iterator i
;
760 wxPoint pos
= offset
;
761 pos
= pos
+ GetPosition();
765 CoordType xpos
= 0; // cursorpos, lenght of line
767 CoordType from
, to
, tempto
;
768 int highlight
= llist
->IsSelected(this, &from
, &to
);
769 // WXLO_DEBUG(("highlight=%d", highlight ));
770 if(highlight
== 1) // we need to draw the whole line inverted!
771 llist
->StartHighlighting(dc
);
773 llist
->EndHighlighting(dc
);
775 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
777 if(highlight
== -1) // partially highlight line
779 // parts of the line need highlighting
780 tempto
= xpos
+(**i
).GetLength();
781 if(tempto
>= from
&& xpos
<= to
)
784 if(tempto
> (**i
).GetLength())
785 tempto
= (**i
).GetLength();
786 CoordType tmp
= from
-xpos
;
788 (**i
).Draw(dc
, pos
, llist
, from
-xpos
, tempto
);
792 llist
->EndHighlighting(dc
); // FIXME! inefficient
793 (**i
).Draw(dc
, pos
, llist
);
797 (**i
).Draw(dc
, pos
, llist
);
798 pos
.x
+= (**i
).GetWidth();
799 xpos
+= (**i
).GetLength();
804 wxLayoutLine::Layout(wxDC
&dc
,
810 wxLayoutObjectList::iterator i
;
813 oldHeight
= m_Height
;
815 topHeight
, bottomHeight
; // above and below baseline
818 objTopHeight
, objBottomHeight
;
821 m_Height
= 0; m_BaseLine
= 0;
823 topHeight
= 0; bottomHeight
= 0;
825 bool cursorFound
= false;
829 *cursorPos
= m_Position
;
830 if(cursorSize
) *cursorSize
= wxPoint(0,0);
833 for(i
= m_ObjectList
.begin(); i
!= NULLIT
; i
++)
835 (**i
).Layout(dc
, llist
);
836 size
= (**i
).GetSize(&objTopHeight
, &objBottomHeight
);
838 if(cursorPos
&& ! cursorFound
)
839 { // we need to check whether the text cursor is here
840 len
= (**i
).GetLength();
841 if(count
<= cx
&& count
+len
> cx
)
843 if((**i
).GetType() == WXLO_TYPE_TEXT
)
845 len
= cx
- count
; // pos in object
846 CoordType width
, height
, descent
;
847 dc
.GetTextExtent((*(wxLayoutObjectText
*)*i
).GetText().substr(0,len
),
848 &width
, &height
, &descent
);
849 cursorPos
->x
+= width
;
850 cursorPos
->y
= m_Position
.y
;
852 if(len
< (**i
).GetLength())
853 str
= (*(wxLayoutObjectText
*)*i
).GetText().substr(len
,1);
855 str
= WXLO_CURSORCHAR
;
856 dc
.GetTextExtent(str
, &width
, &height
, &descent
);
857 wxASSERT(cursorSize
);
858 // Just in case some joker inserted an empty string object:
859 if(width
== 0) width
= WXLO_MINIMUM_CURSOR_WIDTH
;
860 if(height
== 0) height
= objHeight
;
861 cursorSize
->x
= width
;
862 cursorSize
->y
= height
;
863 cursorFound
= true; // no more checks
866 { // on some other object
867 CoordType top
, bottom
; // unused
868 *cursorSize
= (**i
).GetSize(&top
,&bottom
);
869 cursorPos
->y
= m_Position
.y
;
870 cursorFound
= true; // no more checks
876 cursorPos
->x
+= (**i
).GetWidth();
881 if(objHeight
> m_Height
) m_Height
= objHeight
;
882 if(objTopHeight
> topHeight
) topHeight
= objTopHeight
;
883 if(objBottomHeight
> bottomHeight
) bottomHeight
= objBottomHeight
;
885 if(topHeight
+ bottomHeight
> m_Height
) m_Height
=
886 topHeight
+bottomHeight
;
887 m_BaseLine
= topHeight
;
891 if(GetPreviousLine()) // empty line
893 m_Height
= GetPreviousLine()->GetHeight();
894 m_BaseLine
= GetPreviousLine()->m_BaseLine
;
898 CoordType width
, height
, descent
;
899 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
901 m_BaseLine
= m_Height
- descent
;
906 // tell next line about coordinate change
907 if(m_Next
&& objHeight
!= oldHeight
)
908 m_Next
->RecalculatePositions(0, llist
);
910 // We need to check whether we found a valid cursor size:
913 // this might be the case if the cursor is at the end of the
914 // line or on a command object:
915 if(cursorSize
->y
< WXLO_MINIMUM_CURSOR_WIDTH
)
917 CoordType width
, height
, descent
;
918 dc
.GetTextExtent(WXLO_CURSORCHAR
, &width
, &height
, &descent
);
919 cursorSize
->x
= width
;
920 cursorSize
->y
= height
;
922 if(m_BaseLine
>= cursorSize
->y
) // the normal case anyway
923 cursorPos
->y
+= m_BaseLine
-cursorSize
->y
;
929 wxLayoutLine::Break(CoordType xpos
, wxLayoutList
*llist
)
934 { // insert an empty line before this one
935 wxLayoutLine
*prev
= new wxLayoutLine(m_Previous
, llist
);
936 if(m_Previous
== NULL
)
937 { // We were in first line, need to link in new empty line
941 m_Previous
->m_Height
= GetHeight(); // this is a wild guess
945 m_Next
->RecalculatePositions(1, llist
);
950 wxLOiterator i
= FindObject(xpos
, &offset
);
952 // must be at the end of the line then
953 return new wxLayoutLine(this, llist
);
956 wxLayoutLine
*newLine
= new wxLayoutLine(this, llist
);
957 // split object at i:
958 if((**i
).GetType() == WXLO_TYPE_TEXT
&& offset
!= 0)
960 wxString left
, right
;
961 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
962 left
= tobj
->GetText().substr(0,offset
);
963 right
= tobj
->GetText().substr(offset
,tobj
->GetLength()-offset
);
964 // current text object gets set to left half
965 tobj
->GetText() = left
; // set new text
966 newLine
->Append(new wxLayoutObjectText(right
));
967 m_Length
-= right
.Length();
968 i
++; // don't move this object to the new list
972 i
++; // move objects from here to new list
974 while(i
!= m_ObjectList
.end())
977 m_Length
-= (**i
).GetLength();
978 m_ObjectList
.remove(i
); // remove without deleting it
981 m_Next
->RecalculatePositions(2, llist
);
987 wxLayoutLine::MergeNextLine(wxLayoutList
*llist
)
989 wxASSERT(GetNextLine());
990 wxLayoutObjectList
&list
= GetNextLine()->m_ObjectList
;
993 for(i
= list
.begin(); i
!= list
.end();)
996 list
.remove(i
); // remove without deleting it
998 wxASSERT(list
.empty());
999 wxLayoutLine
*oldnext
= GetNextLine();
1000 SetNext(GetNextLine()->GetNextLine());
1002 RecalculatePositions(1, llist
);
1006 wxLayoutLine::GetWrapPosition(CoordType column
)
1009 wxLOiterator i
= FindObject(column
, &offset
);
1010 if(i
== NULLIT
) return -1; // cannot wrap
1012 // go backwards through the list and look for space in text objects
1015 if((**i
).GetType() == WXLO_TYPE_TEXT
)
1019 if( isspace(((wxLayoutObjectText
*)*i
)->GetText().c_str()[(size_t)offset
]))
1026 }while(offset
!= -1);
1027 i
--; // move on to previous object
1031 column
-= (**i
).GetLength();
1035 offset
= (**i
).GetLength();
1036 }while(i
!= NULLIT
);
1037 /* If we reached the begin of the list and have more than one
1038 object, that one is longer than the margin, so break behind
1041 i
= m_ObjectList
.begin();
1042 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1044 pos
+= (**i
).GetLength();
1047 if(i
== NULLIT
) return -1; //why should this happen?
1048 pos
+= (**i
).GetLength();
1050 while(i
!= NULLIT
&& (**i
).GetType() != WXLO_TYPE_TEXT
)
1052 pos
+= (**i
).GetLength();
1055 if(i
== NULLIT
) return -1; //this is possible, if there is only one text object
1056 // now we are at the second text object:
1057 pos
-= (**i
).GetLength();
1058 return pos
; // in front of it
1062 #ifdef WXLAYOUT_DEBUG
1064 wxLayoutLine::Debug(void)
1067 wxPoint pos
= GetPosition();
1068 WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld",
1069 (long int) GetLineNumber(),
1070 (long int) pos
.x
, (long int) pos
.y
,
1071 (long int) GetHeight()));
1072 if(m_ObjectList
.begin() != NULLIT
)
1073 (**m_ObjectList
.begin()).Debug();
1079 wxLayoutLine::Copy(wxLayoutList
*llist
,
1083 CoordType firstOffset
, lastOffset
;
1085 if(to
== -1) to
= GetLength();
1087 wxLOiterator first
= FindObject(from
, &firstOffset
);
1088 wxLOiterator last
= FindObject(to
, &lastOffset
);
1090 // Common special case: only one object
1091 if( *first
== *last
)
1093 if( (**first
).GetType() == WXLO_TYPE_TEXT
)
1095 llist
->Insert(new wxLayoutObjectText(
1096 ((wxLayoutObjectText
1097 *)*first
)->GetText().substr(firstOffset
,
1098 lastOffset
-firstOffset
))
1102 else // what can we do?
1104 if(lastOffset
> firstOffset
) // i.e. +1 :-)
1105 llist
->Insert( (**first
).Copy() );
1110 // If we reach here, we can safely copy the whole first object from
1111 // the firstOffset position on:
1112 if((**first
).GetType() == WXLO_TYPE_TEXT
&& firstOffset
!= 0)
1114 llist
->Insert(new wxLayoutObjectText(
1115 ((wxLayoutObjectText
*)*first
)->GetText().substr(firstOffset
))
1118 else if(firstOffset
== 0)
1119 llist
->Insert( (**first
).Copy() );
1120 // else nothing to copy :-(
1122 // Now we copy all objects before the last one:
1123 wxLOiterator i
= first
; i
++;
1124 for( ; i
!= last
; i
++)
1125 llist
->Insert( (**i
).Copy() );
1127 // And now the last object:
1130 if( (**last
).GetType() == WXLO_TYPE_TEXT
)
1132 llist
->Insert(new wxLayoutObjectText(
1133 ((wxLayoutObjectText
*)*last
)->GetText().substr(0,lastOffset
))
1137 llist
->Insert( (**last
).Copy() );
1141 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1143 The wxLayoutList object
1145 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1147 wxLayoutList::wxLayoutList()
1149 m_DefaultSetting
= NULL
;
1151 m_ColourFG
= *wxBLACK
;
1152 m_ColourBG
= *wxWHITE
;
1153 InvalidateUpdateRect();
1157 wxLayoutList::~wxLayoutList()
1160 m_FirstLine
->DeleteLine(false, this);
1164 wxLayoutList::Empty(void)
1167 m_FirstLine
= m_FirstLine
->DeleteLine(false, this);
1169 m_CursorPos
= wxPoint(0,0);
1170 m_CursorScreenPos
= wxPoint(0,0);
1171 m_CursorSize
= wxPoint(0,0);
1172 m_FirstLine
= new wxLayoutLine(NULL
, this); // empty first line
1173 m_CursorLine
= m_FirstLine
;
1174 InvalidateUpdateRect();
1179 wxLayoutList::InternalClear(void)
1182 if(m_DefaultSetting
)
1184 delete m_DefaultSetting
;
1185 m_DefaultSetting
= NULL
;
1187 m_Selection
.m_selecting
= false;
1188 m_Selection
.m_valid
= false;
1190 m_CurrentSetting
.family
= wxSWISS
;
1191 m_CurrentSetting
.size
= WXLO_DEFAULTFONTSIZE
;
1192 m_CurrentSetting
.style
= wxNORMAL
;
1193 m_CurrentSetting
.weight
= wxNORMAL
;
1194 m_CurrentSetting
.underline
= 0;
1198 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1199 int underline
, wxColour
*fg
,
1202 if(family
!= -1) m_FontFamily
= family
;
1203 if(size
!= -1) m_FontPtSize
= size
;
1204 if(style
!= -1) m_FontStyle
= style
;
1205 if(weight
!= -1) m_FontWeight
= weight
;
1206 if(underline
!= -1) m_FontUnderline
= underline
!= 0;
1208 new wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,m_FontWeight
,m_FontUnderline
,
1213 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
1214 int underline
, char const *fg
, char const *bg
)
1222 cfg
= wxTheColourDatabase
->FindColour(fg
);
1224 cbg
= wxTheColourDatabase
->FindColour(bg
);
1226 SetFont(size
,family
,style
,weight
,underline
,cfg
,cbg
);
1230 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1231 int underline
, wxColour
*fg
, wxColour
*bg
)
1235 if(m_DefaultSetting
)
1236 delete m_DefaultSetting
;
1238 m_DefaultSetting
= new
1239 wxLayoutStyleInfo(family
,size
,style
,weight
,underline
,fg
,bg
);
1243 wxLayoutList::FindText(const wxString
&needle
, const wxPoint
&cpos
) const
1248 for(line
= m_FirstLine
;
1250 line
= line
->GetNextLine())
1252 if(line
->GetLineNumber() >= cpos
.y
)
1254 xpos
= line
->FindText(needle
,
1255 (line
->GetLineNumber() == cpos
.y
) ?
1258 return wxPoint(xpos
, line
->GetLineNumber());
1261 return wxPoint(-1,-1);
1266 wxLayoutList::MoveCursorTo(wxPoint
const &p
)
1268 SetUpdateRect(m_CursorScreenPos
);
1269 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1270 wxLayoutLine
*line
= m_FirstLine
;
1271 while(line
&& line
->GetLineNumber() != p
.y
)
1272 line
= line
->GetNextLine();
1273 if(line
&& line
->GetLineNumber() == p
.y
) // found it
1275 m_CursorPos
.y
= p
.y
;
1276 m_CursorLine
= line
;
1277 CoordType len
= line
->GetLength();
1280 m_CursorPos
.x
= p
.x
;
1285 m_CursorPos
.x
= len
;
1293 wxLayoutList::MoveCursorVertically(int n
)
1295 SetUpdateRect(m_CursorScreenPos
);
1296 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1298 if(n
< 0) // move up
1300 if(m_CursorLine
== m_FirstLine
) return false;
1301 while(n
< 0 && m_CursorLine
)
1303 m_CursorLine
= m_CursorLine
->GetPreviousLine();
1309 m_CursorLine
= m_FirstLine
;
1315 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1316 m_CursorPos
.x
= m_CursorLine
->GetLength();
1322 wxLayoutLine
*last
= m_CursorLine
;
1323 if(! m_CursorLine
->GetNextLine()) return false;
1324 while(n
> 0 && m_CursorLine
)
1328 m_CursorLine
= m_CursorLine
->GetNextLine();
1332 m_CursorLine
= last
;
1338 if(m_CursorPos
.x
> m_CursorLine
->GetLength())
1339 m_CursorPos
.x
= m_CursorLine
->GetLength();
1347 wxLayoutList::MoveCursorHorizontally(int n
)
1349 SetUpdateRect(m_CursorScreenPos
);
1350 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1354 if(m_CursorPos
.x
== 0) // at begin of line
1356 if(! MoveCursorVertically(-1))
1358 MoveCursorToEndOfLine();
1363 if(move
> m_CursorPos
.x
) move
= m_CursorPos
.x
;
1364 m_CursorPos
.x
-= move
; n
+= move
;
1369 int len
= m_CursorLine
->GetLength();
1370 if(m_CursorPos
.x
== len
) // at end of line
1372 if(! MoveCursorVertically(1))
1374 MoveCursorToBeginOfLine();
1379 if( move
>= len
-m_CursorPos
.x
) move
= len
-m_CursorPos
.x
;
1380 m_CursorPos
.x
+= move
;
1387 wxLayoutList::Insert(wxString
const &text
)
1389 wxASSERT(m_CursorLine
);
1390 SetUpdateRect(m_CursorScreenPos
);
1391 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1392 m_CursorLine
->Insert(m_CursorPos
.x
, text
);
1393 m_CursorPos
.x
+= text
.Length();
1394 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1399 wxLayoutList::Insert(wxLayoutObject
*obj
)
1401 wxASSERT(m_CursorLine
);
1402 SetUpdateRect(m_CursorScreenPos
);
1403 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1404 m_CursorLine
->Insert(m_CursorPos
.x
, obj
);
1405 m_CursorPos
.x
+= obj
->GetLength();
1406 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1411 wxLayoutList::LineBreak(void)
1413 wxASSERT(m_CursorLine
);
1414 bool setFirst
= (m_CursorLine
== m_FirstLine
&& m_CursorPos
.x
== 0);
1415 SetUpdateRect(m_CursorScreenPos
);
1416 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1417 m_CursorLine
= m_CursorLine
->Break(m_CursorPos
.x
, this);
1418 if(setFirst
) // we were at beginning of first line
1419 m_FirstLine
= m_CursorLine
->GetPreviousLine();
1422 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1427 wxLayoutList::WrapLine(CoordType column
)
1429 if(m_CursorPos
.x
<= column
|| column
< 1)
1430 return false; // do nothing yet
1433 CoordType xpos
= m_CursorLine
->GetWrapPosition(column
);
1435 return false; // cannot break line
1437 CoordType newpos
= m_CursorPos
.x
- xpos
- 1;
1438 m_CursorPos
.x
= xpos
;
1439 SetUpdateRect(m_CursorScreenPos
);
1440 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1442 Delete(1); // delete the space
1443 m_CursorPos
.x
= newpos
;
1444 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1450 wxLayoutList::Delete(CoordType npos
)
1452 wxASSERT(m_CursorLine
);
1453 SetUpdateRect(m_CursorScreenPos
);
1454 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1458 left
= m_CursorLine
->Delete(m_CursorPos
.x
, npos
);
1461 // More to delete, continue on next line.
1462 // First, check if line is empty:
1463 if(m_CursorLine
->GetLength() == 0)
1464 { // in this case, updating could probably be optimised
1466 wxASSERT(DeleteLines(1) == 0);
1475 // Need to join next line
1476 if(! m_CursorLine
->GetNextLine())
1480 m_CursorLine
->MergeNextLine(this);
1486 m_CursorLine
->RecalculatePositions(true, this); //FIXME needed?
1491 wxLayoutList::DeleteLines(int n
)
1493 wxASSERT(m_CursorLine
);
1495 SetUpdateRect(m_CursorScreenPos
);
1496 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1499 if(!m_CursorLine
->GetNextLine())
1500 { // we cannot delete this line, but we can clear it
1501 MoveCursorToBeginOfLine();
1502 DeleteToEndOfLine();
1503 m_CursorLine
->RecalculatePositions(2, this);
1507 line
= m_CursorLine
;
1508 m_CursorLine
= m_CursorLine
->DeleteLine(true, this);
1510 if(line
== m_FirstLine
) m_FirstLine
= m_CursorLine
;
1511 wxASSERT(m_FirstLine
);
1512 wxASSERT(m_CursorLine
);
1514 m_CursorLine
->RecalculatePositions(2, this);
1519 wxLayoutList::Recalculate(wxDC
&dc
, CoordType bottom
)
1521 wxLayoutLine
*line
= m_FirstLine
;
1523 // first, make sure everything is calculated - this might not be
1524 // needed, optimise it later
1525 ApplyStyle(m_DefaultSetting
, dc
);
1528 line
->RecalculatePosition(this); // so we don't need to do it all the time
1529 // little condition to speed up redrawing:
1530 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1531 line
= line
->GetNextLine();
1536 wxLayoutList::UpdateCursorScreenPos(wxDC
&dc
)
1538 wxASSERT(m_CursorLine
);
1539 m_CursorLine
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1543 wxLayoutList::GetCursorScreenPos(wxDC
&dc
)
1545 UpdateCursorScreenPos(dc
);
1546 return m_CursorScreenPos
;
1550 wxLayoutList::Layout(wxDC
&dc
, CoordType bottom
)
1552 wxLayoutLine
*line
= m_FirstLine
;
1554 // first, make sure everything is calculated - this might not be
1555 // needed, optimise it later
1556 ApplyStyle(m_DefaultSetting
, dc
);
1559 if(line
== m_CursorLine
)
1560 line
->Layout(dc
, this, (wxPoint
*)&m_CursorScreenPos
, (wxPoint
*)&m_CursorSize
, m_CursorPos
.x
);
1562 line
->Layout(dc
, this);
1563 // little condition to speed up redrawing:
1564 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1565 line
= line
->GetNextLine();
1568 ///FIXME: disabled for now
1570 // can only be 0 if we are on the first line and have no next line
1571 wxASSERT(m_CursorSize
.x
!= 0 || (m_CursorLine
&&
1572 m_CursorLine
->GetNextLine() == NULL
&&
1573 m_CursorLine
== m_FirstLine
));
1575 SetUpdateRect(m_CursorScreenPos
);
1576 SetUpdateRect(m_CursorScreenPos
+m_CursorSize
);
1580 wxLayoutList::Draw(wxDC
&dc
,
1581 wxPoint
const &offset
,
1585 wxLayoutLine
*line
= m_FirstLine
;
1588 ApplyStyle(m_DefaultSetting
, dc
);
1589 wxBrush
brush(m_ColourBG
, wxSOLID
);
1594 // only draw if between top and bottom:
1595 if((top
== -1 || line
->GetPosition().y
+ line
->GetHeight() >= top
))
1596 line
->Draw(dc
, this, offset
);
1597 // little condition to speed up redrawing:
1598 if(bottom
!= -1 && line
->GetPosition().y
> bottom
) break;
1599 line
= line
->GetNextLine();
1601 InvalidateUpdateRect();
1603 WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
1604 m_Selection
.m_valid
? "valid" : "invalid",
1605 m_Selection
.m_CursorA
.x
, m_Selection
.m_CursorA
.y
,
1606 m_Selection
.m_CursorB
.x
, m_Selection
.m_CursorB
.y
));
1610 wxLayoutList::FindObjectScreen(wxDC
&dc
, wxPoint
const pos
,
1614 // First, find the right line:
1615 wxLayoutLine
*line
= m_FirstLine
;
1618 // we need to run a layout here to get font sizes right :-(
1619 ApplyStyle(m_DefaultSetting
, dc
);
1622 p
= line
->GetPosition();
1623 if(p
.y
<= pos
.y
&& p
.y
+line
->GetHeight() >= pos
.y
)
1625 line
->Layout(dc
, this);
1626 line
= line
->GetNextLine();
1630 if(found
) *found
= false;
1631 return NULL
; // not found
1633 if(cursorPos
) cursorPos
->y
= line
->GetLineNumber();
1634 // Now, find the object in the line:
1635 wxLOiterator i
= line
->FindObjectScreen(dc
, pos
.x
,
1636 cursorPos
? & cursorPos
->x
: NULL
,
1638 return (i
== NULLIT
) ? NULL
: *i
;
1643 wxLayoutList::GetSize(void) const
1646 *line
= m_FirstLine
,
1649 return wxPoint(0,0);
1651 wxPoint
maxPoint(0,0);
1656 if(line
->GetWidth() > maxPoint
.x
)
1657 maxPoint
.x
= line
->GetWidth();
1659 line
= line
->GetNextLine();
1662 maxPoint
.y
= last
->GetPosition().y
+ last
->GetHeight();
1668 wxLayoutList::DrawCursor(wxDC
&dc
, bool active
, wxPoint
const &translate
)
1671 coords
= m_CursorScreenPos
;
1672 coords
.x
+= translate
.x
;
1673 coords
.y
+= translate
.y
;
1675 #ifdef WXLAYOUT_DEBUG
1676 WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
1677 (long)m_CursorPos
.x
, (long)m_CursorPos
.y
,
1678 (long)coords
.x
, (long)coords
.y
,
1679 (long)m_CursorSize
.x
, (long)m_CursorSize
.y
,
1680 (long)m_CursorLine
->GetLineNumber(),
1681 (long)m_CursorLine
->GetLength()));
1684 dc
.SetBrush(*wxBLACK_BRUSH
);
1685 dc
.SetLogicalFunction(wxXOR
);
1686 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
1689 dc
.DrawRectangle(coords
.x
, coords
.y
,
1690 m_CursorSize
.x
, m_CursorSize
.y
);
1691 SetUpdateRect(coords
.x
, coords
.y
);
1692 SetUpdateRect(coords
.x
+m_CursorSize
.x
, coords
.y
+m_CursorSize
.y
);
1696 dc
.DrawLine(coords
.x
, coords
.y
+m_CursorSize
.y
-1,
1697 coords
.x
, coords
.y
);
1698 SetUpdateRect(coords
.x
, coords
.y
+m_CursorSize
.y
-1);
1699 SetUpdateRect(coords
.x
, coords
.y
);
1701 dc
.SetLogicalFunction(wxCOPY
);
1702 //dc.SetBrush(wxNullBrush);
1706 wxLayoutList::SetUpdateRect(CoordType x
, CoordType y
)
1708 if(m_UpdateRectValid
)
1709 GrowRect(m_UpdateRect
, x
, y
);
1714 m_UpdateRect
.width
= 4; // large enough to avoid surprises from
1715 m_UpdateRect
.height
= 4;// wxGTK :-)
1716 m_UpdateRectValid
= true;
1721 wxLayoutList::StartSelection(void)
1723 WXLO_DEBUG(("Starting selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1724 m_Selection
.m_CursorA
= m_CursorPos
;
1725 m_Selection
.m_CursorB
= m_CursorPos
;
1726 m_Selection
.m_selecting
= true;
1727 m_Selection
.m_valid
= false;
1731 wxLayoutList::ContinueSelection(void)
1733 wxASSERT(m_Selection
.m_selecting
== true);
1734 wxASSERT(m_Selection
.m_valid
== false);
1735 WXLO_DEBUG(("Continuing selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1736 m_Selection
.m_CursorB
= m_CursorPos
;
1737 // We always want m_CursorA <= m_CursorB!
1738 if(! (m_Selection
.m_CursorA
<= m_Selection
.m_CursorB
))
1740 wxPoint help
= m_Selection
.m_CursorB
;
1741 m_Selection
.m_CursorB
= m_Selection
.m_CursorA
;
1742 m_Selection
.m_CursorA
= help
;
1747 wxLayoutList::EndSelection(void)
1749 ContinueSelection();
1750 WXLO_DEBUG(("Ending selection at %ld/%ld", m_CursorPos
.x
, m_CursorPos
.y
));
1751 m_Selection
.m_selecting
= false;
1752 m_Selection
.m_valid
= true;
1757 wxLayoutList::IsSelecting(void)
1759 return m_Selection
.m_selecting
;
1763 wxLayoutList::IsSelected(const wxPoint
&cursor
)
1765 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1767 return m_Selection
.m_CursorA
<= cursor
1768 && cursor
<= m_Selection
.m_CursorB
;
1772 /** Tests whether this layout line is selected and needs
1774 @param line to test for
1775 @return 0 = not selected, 1 = fully selected, -1 = partially
1779 wxLayoutList::IsSelected(const wxLayoutLine
*line
, CoordType
*from
,
1782 wxASSERT(line
); wxASSERT(to
); wxASSERT(from
);
1784 if(! m_Selection
.m_valid
&& ! m_Selection
.m_selecting
)
1787 CoordType y
= line
->GetLineNumber();
1788 if(m_Selection
.m_CursorA
.y
< y
&& m_Selection
.m_CursorB
.y
> y
)
1790 else if(m_Selection
.m_CursorA
.y
== y
)
1792 *from
= m_Selection
.m_CursorA
.x
;
1793 if(m_Selection
.m_CursorB
.y
== y
)
1794 *to
= m_Selection
.m_CursorB
.x
;
1796 *to
= line
->GetLength();
1799 else if(m_Selection
.m_CursorB
.y
== y
)
1801 *to
= m_Selection
.m_CursorB
.x
;
1802 if(m_Selection
.m_CursorA
.y
== y
)
1803 *from
= m_Selection
.m_CursorA
.x
;
1813 wxLayoutList::DeleteSelection(void)
1815 if(! m_Selection
.m_valid
)
1818 m_Selection
.m_valid
= false;
1820 // Only delete part of the current line?
1821 if(m_Selection
.m_CursorA
.y
== m_Selection
.m_CursorB
.y
)
1823 MoveCursorTo(m_Selection
.m_CursorA
);
1824 Delete(m_Selection
.m_CursorB
.x
- m_Selection
.m_CursorA
.x
);
1833 for(firstLine
= m_FirstLine
;
1834 firstLine
&& firstLine
->GetLineNumber() < m_Selection
.m_CursorA
.y
;
1835 firstLine
=firstLine
->GetNextLine())
1837 if(!firstLine
|| firstLine
->GetLineNumber() != m_Selection
.m_CursorA
.y
)
1841 for(lastLine
= m_FirstLine
;
1842 lastLine
&& lastLine
->GetLineNumber() < m_Selection
.m_CursorB
.y
;
1843 lastLine
=lastLine
->GetNextLine())
1845 if(!lastLine
|| lastLine
->GetLineNumber() != m_Selection
.m_CursorB
.y
)
1849 // We now know that the two lines are different:
1851 // First, delete what's left of this line:
1852 MoveCursorTo(m_Selection
.m_CursorA
);
1853 DeleteToEndOfLine();
1855 wxLayoutLine
*nextLine
= firstLine
->GetNextLine();
1856 while(nextLine
&& nextLine
!= lastLine
)
1857 nextLine
= nextLine
->DeleteLine(false, this);
1859 // Now nextLine = lastLine;
1860 Delete(1); // This joins firstLine and nextLine
1861 Delete(m_Selection
.m_CursorB
.x
); // This deletes the first x
1865 firstLine
->RecalculatePositions(1, this);
1868 /// Starts highlighting the selection
1870 wxLayoutList::StartHighlighting(wxDC
&dc
)
1873 dc
.SetTextForeground(m_ColourBG
);
1874 dc
.SetTextBackground(m_ColourFG
);
1878 /// Ends highlighting the selection
1880 wxLayoutList::EndHighlighting(wxDC
&dc
)
1883 dc
.SetTextForeground(m_ColourFG
);
1884 dc
.SetTextBackground(m_ColourBG
);
1890 wxLayoutList::Copy(const wxPoint
&from
,
1897 for(firstLine
= m_FirstLine
;
1898 firstLine
&& firstLine
->GetLineNumber() < from
.y
;
1899 firstLine
=firstLine
->GetNextLine())
1901 if(!firstLine
|| firstLine
->GetLineNumber() != from
.y
)
1904 for(lastLine
= m_FirstLine
;
1905 lastLine
&& lastLine
->GetLineNumber() < to
.y
;
1906 lastLine
=lastLine
->GetNextLine())
1908 if(!lastLine
|| lastLine
->GetLineNumber() != to
.y
)
1913 wxLayoutLine
*tmp
= firstLine
;
1914 firstLine
= lastLine
;
1918 wxLayoutList
*llist
= new wxLayoutList();
1920 if(firstLine
== lastLine
)
1922 firstLine
->Copy(llist
, from
.x
, to
.x
);
1926 // Extract objects from first line
1927 firstLine
->Copy(llist
, from
.x
);
1929 // Extract all lines between
1930 for(wxLayoutLine
*line
= firstLine
->GetNextLine();
1932 line
= line
->GetNextLine())
1937 // Extract objects from last line
1938 lastLine
->Copy(llist
, 0, to
.x
);
1944 wxLayoutList::GetSelection(void)
1946 if(! m_Selection
.m_valid
)
1948 if(m_Selection
.m_selecting
)
1954 m_Selection
.m_valid
= false;
1955 return Copy( m_Selection
.m_CursorA
, m_Selection
.m_CursorB
);
1960 #define COPY_SI(what) if(si->what != -1) m_CurrentSetting.what = si->what;
1963 wxLayoutList::ApplyStyle(wxLayoutStyleInfo
*si
, wxDC
&dc
)
1974 m_CurrentSetting
.fg_valid
= true;
1975 m_CurrentSetting
.fg_red
= si
->fg_red
;
1976 m_CurrentSetting
.fg_green
= si
->fg_green
;
1977 m_CurrentSetting
.fg_blue
= si
->fg_blue
;
1981 m_CurrentSetting
.bg_valid
= true;
1982 m_CurrentSetting
.bg_red
= si
->bg_red
;
1983 m_CurrentSetting
.bg_green
= si
->bg_green
;
1984 m_CurrentSetting
.bg_blue
= si
->bg_blue
;
1987 m_ColourFG
= wxColour(m_CurrentSetting
.fg_red
,
1988 m_CurrentSetting
.fg_green
,
1989 m_CurrentSetting
.fg_blue
);
1990 m_ColourBG
= wxColour(m_CurrentSetting
.bg_red
,
1991 m_CurrentSetting
.bg_green
,
1992 m_CurrentSetting
.bg_blue
);
1993 dc
.SetTextForeground(m_ColourFG
);
1994 dc
.SetTextBackground(m_ColourBG
);
1998 #ifdef WXLAYOUT_DEBUG
2001 wxLayoutList::Debug(void)
2006 for(line
= m_FirstLine
;
2008 line
= line
->GetNextLine())
2015 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2019 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
*llist
,
2022 wxString
const & title
)
2029 wxLayoutPrintout::~wxLayoutPrintout()
2034 wxLayoutPrintout::ScaleDC(wxDC
*dc
)
2036 // The following bit is taken from the printing sample, let's see
2037 // whether it works for us.
2039 /* You might use THIS code to set the printer DC to ROUGHLY reflect
2040 * the screen text size. This page also draws lines of actual length 5cm
2043 // Get the logical pixels per inch of screen and printer
2044 int ppiScreenX
, ppiScreenY
;
2045 GetPPIScreen(&ppiScreenX
, &ppiScreenY
);
2046 int ppiPrinterX
, ppiPrinterY
;
2047 GetPPIPrinter(&ppiPrinterX
, &ppiPrinterY
);
2049 if(ppiScreenX
== 0) // not yet set, need to guess
2054 if(ppiPrinterX
== 0) // not yet set, need to guess
2060 // This scales the DC so that the printout roughly represents the
2061 // the screen scaling. The text point size _should_ be the right size
2062 // but in fact is too small for some reason. This is a detail that will
2063 // need to be addressed at some point but can be fudged for the
2065 float scale
= (float)((float)ppiPrinterX
/(float)ppiScreenX
);
2067 // Now we have to check in case our real page size is reduced
2068 // (e.g. because we're drawing to a print preview memory DC)
2069 int pageWidth
, pageHeight
;
2071 dc
->GetSize(&w
, &h
);
2072 GetPageSizePixels(&pageWidth
, &pageHeight
);
2073 if(pageWidth
!= 0) // doesn't work always
2075 // If printer pageWidth == current DC width, then this doesn't
2076 // change. But w might be the preview bitmap width, so scale down.
2077 scale
= scale
* (float)(w
/(float)pageWidth
);
2079 dc
->SetUserScale(scale
, scale
);
2083 bool wxLayoutPrintout::OnPrintPage(int page
)
2092 top
= (page
- 1)*m_PrintoutHeight
;
2093 bottom
= top
+ m_PrintoutHeight
;
2094 // SetDeviceOrigin() doesn't work here, so we need to manually
2095 // translate all coordinates.
2096 wxPoint
translate(m_Offset
.x
,m_Offset
.y
-top
);
2097 m_llist
->Draw(*dc
, translate
, top
, bottom
);
2104 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
2106 /* We allocate a temporary wxDC for printing, so that we can
2107 determine the correct paper size and scaling. We don't actually
2108 print anything on it. */
2110 wxPrinterDC
psdc("","",WXLLIST_TEMPFILE
,false);
2112 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
2115 float scale
= ScaleDC(&psdc
);
2117 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
);
2118 // This sets a left/top origin of 15% and 20%:
2119 m_Offset
= wxPoint((15*m_PageWidth
)/100, m_PageHeight
/20);
2121 // This is the length of the printable area.
2122 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
2123 m_PrintoutHeight
= (int)( m_PrintoutHeight
/ scale
); // we want to use the real paper height
2127 (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
));
2130 *maxPage
= m_NumOfPages
;
2133 *selPageTo
= m_NumOfPages
;
2134 wxRemoveFile(WXLLIST_TEMPFILE
);
2137 bool wxLayoutPrintout::HasPage(int pageNum
)
2139 return pageNum
<= m_NumOfPages
;
2143 Stupid wxWindows doesn't draw proper ellipses, so we comment this
2144 out. It's a waste of paper anyway.
2148 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
2149 wxPoint topleft
, wxPoint bottomright
,
2152 // make backups of all essential parameters
2153 const wxBrush
& brush
= dc
.GetBrush();
2154 const wxPen
& pen
= dc
.GetPen();
2155 const wxFont
& font
= dc
.GetFont();
2157 dc
.SetBrush(*wxWHITE_BRUSH
);
2158 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
2159 dc
.DrawRoundedRectangle(topleft
.x
,
2160 topleft
.y
,bottomright
.x
-topleft
.x
,
2161 bottomright
.y
-topleft
.y
);
2162 dc
.SetBrush(*wxBLACK_BRUSH
);
2163 wxFont myfont
= wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,
2164 wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
2168 page
= "9999/9999 "; // many pages...
2170 dc
.GetTextExtent(page
,&w
,&h
);
2171 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
2172 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
2173 dc
.GetTextExtent("XXXX", &w
,&h
);
2174 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);