1 /*-*- c++ -*-********************************************************
2 * wxFTCanvas: a canvas for editing formatted text *
4 * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) *
7 *******************************************************************/
10 - each Object knows its size and how to draw itself
11 - the list is responsible for calculating positions
12 - the draw coordinates for each object are the top left corner
13 - coordinates only get calculated when things get redrawn
14 - The cursor position is the position before an object, i.e. if the
15 buffer starts with a text-object, cursor 0,0 is just before the
16 first character. For all non-text objects, the cursor positions
17 are 0==before or 1==behind. So that all non-text objects count as
24 - new cursor movement calculations
25 - moving lines and moving across linebreaks still broken
28 - mouse click positions cursor
29 - selection (SetMark(), GetSelection())
30 - DND acceptance of text
32 - wxlwindow: formatting menu: problem with checked/unchecked consistency gtk bug?
35 #define USE_NEW_CURSORCODE 1
39 - MaxX()/MaxY() don't get set
44 #pragma implementation "wxllist.h"
49 # include "gui/wxllist.h"
55 # include "iostream.h"
57 # include <wx/postscrp.h>
58 # include <wx/print.h>
62 #define BASELINESTRETCH 12
64 // This should never really get created
65 #define WXLLIST_TEMPFILE "__wxllist.tmp"
68 static const char *g_aTypeStrings
[] =
70 "invalid", "text", "cmd", "icon", "linebreak"
73 # define wxLayoutDebug wxLogDebug
74 # define WXL_VAR(x) cerr << #x " = " << x << endl;
75 # define WXL_DBG_POINT(p) wxLogDebug(#p ": (%d, %d)", p.x, p.y)
76 # define WXL_TRACE(f) wxLogDebug(#f ": ")
77 # define TypeString(t) g_aTypeStrings[t]
80 wxLayoutObjectBase::Debug(void)
83 wxLogDebug("%s: size = %dx%d, bl = %d",
84 TypeString(GetType()), GetSize(&bl
).x
, GetSize(&bl
).y
, bl
);
89 # define WXL_DBG_POINT(p)
91 # define ShowCurrentObject()
92 # define TypeString(t) ""
93 inline void wxLayoutDebug(const char *, ...) { }
97 //-------------------------- wxLayoutObjectText
99 wxLayoutObjectText::wxLayoutObjectText(const String
&txt
)
104 m_Position
= wxPoint(-1,-1);
109 wxLayoutObjectText::GetSize(CoordType
*baseLine
) const
111 if(baseLine
) *baseLine
= m_BaseLine
;
112 return wxPoint(m_Width
, m_Height
);
116 wxLayoutObjectText::Draw(wxDC
&dc
, wxPoint
const &translate
)
118 dc
.DrawText(Str(m_Text
), m_Position
.x
+ translate
.x
, m_Position
.y
+translate
.y
);
124 wxLayoutObjectText::Layout(wxDC
&dc
, wxPoint position
, CoordType baseLine
)
128 if(m_Position
.x
!= position
.x
|| m_Position
.y
!= position
.y
)
131 m_Position
= position
;
132 dc
.GetTextExtent(Str(m_Text
),&m_Width
, &m_Height
, &descent
);
133 m_BaseLine
= m_Height
- descent
;
134 if(m_Position
.x
!= position
.x
|| m_Position
.y
!= position
.y
)
138 #ifdef WXLAYOUT_DEBUG
140 wxLayoutObjectText::Debug(void)
142 wxLayoutObjectBase::Debug();
143 wxLogDebug(" `%s`", m_Text
.c_str());
147 //-------------------------- wxLayoutObjectIcon
149 wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon
const &icon
)
151 m_Position
= wxPoint(-1,-1);
152 m_Icon
= new wxIcon(icon
);
155 wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon
*icon
)
161 wxLayoutObjectIcon::Draw(wxDC
&dc
, wxPoint
const &translate
)
163 dc
.DrawIcon(m_Icon
,m_Position
.x
+translate
.x
, m_Position
.y
+translate
.y
);
167 wxLayoutObjectIcon::Layout(wxDC
&dc
, wxPoint position
, CoordType baseLine
)
169 if(m_Position
.x
!= position
.x
|| m_Position
.y
!= position
.y
)
171 m_Position
= position
;
175 wxLayoutObjectIcon::GetSize(CoordType
*baseLine
) const
177 if(baseLine
) *baseLine
= m_Icon
->GetHeight();
178 return wxPoint(m_Icon
->GetWidth(), m_Icon
->GetHeight());
181 //-------------------------- wxLayoutObjectCmd
184 wxLayoutObjectCmd::wxLayoutObjectCmd(int size
, int family
, int style
, int
185 weight
, bool underline
,
186 wxColour
const *fg
, wxColour
const *bg
)
189 m_font
= new wxFont(size
,family
,style
,weight
,underline
);
194 wxLayoutObjectCmd::~wxLayoutObjectCmd()
200 wxLayoutObjectCmd::GetStyle(void) const
202 wxLayoutStyleInfo
*si
= new wxLayoutStyleInfo();
205 si
->size
= m_font
->GetPointSize();
206 si
->family
= m_font
->GetFamily();
207 si
->style
= m_font
->GetStyle();
208 si
->underline
= m_font
->GetUnderlined();
209 si
->weight
= m_font
->GetWeight();
211 si
->fg_red
= m_ColourFG
->Red();
212 si
->fg_green
= m_ColourFG
->Green();
213 si
->fg_blue
= m_ColourFG
->Blue();
214 si
->bg_red
= m_ColourBG
->Red();
215 si
->bg_green
= m_ColourBG
->Green();
216 si
->bg_blue
= m_ColourBG
->Blue();
222 wxLayoutObjectCmd::Draw(wxDC
&dc
, wxPoint
const &translate
)
227 dc
.SetTextForeground(*m_ColourFG
);
229 dc
.SetTextBackground(*m_ColourBG
);
232 wxLayoutObjectCmd::Layout(wxDC
&dc
, wxPoint p
, CoordType baseline
)
234 m_Position
= p
; // required so we can find the right object for cursor
235 // this get called, so that recalculation uses right font sizes
236 Draw(dc
,wxPoint(0,0));
239 //-------------------------- wxLayoutList
241 wxLayoutList::wxLayoutList()
243 m_DefaultSetting
= NULL
;
247 wxLayoutList::~wxLayoutList()
250 delete m_DefaultSetting
;
251 // no deletion of objects, they are owned by the list
255 wxLayoutList::LineBreak(void)
257 Insert(new wxLayoutObjectLineBreak
);
258 m_CursorPos
.x
= 0; m_CursorPos
.y
++;
262 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
263 int underline
, wxColour
const *fg
,
266 if(family
!= -1) m_FontFamily
= family
;
267 if(size
!= -1) m_FontPtSize
= size
;
268 if(style
!= -1) m_FontStyle
= style
;
269 if(weight
!= -1) m_FontWeight
= weight
;
270 if(underline
!= -1) m_FontUnderline
= underline
!= 0;
272 if(fg
!= NULL
) m_ColourFG
= fg
;
273 if(bg
!= NULL
) m_ColourBG
= bg
;
276 new wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,m_FontWeight
,m_FontUnderline
,
277 m_ColourFG
, m_ColourBG
));
281 wxLayoutList::SetFont(int family
, int size
, int style
, int weight
,
282 int underline
, char const *fg
, char const *bg
)
290 cfg
= wxTheColourDatabase
->FindColour(fg
);
292 cbg
= wxTheColourDatabase
->FindColour(bg
);
294 SetFont(family
,size
,style
,weight
,underline
,cfg
,cbg
);
298 /// for access by wxLayoutWindow:
300 wxLayoutList::GetSize(CoordType
*max_x
, CoordType
*max_y
,
301 CoordType
*lineHeight
)
304 if(max_x
) *max_x
= m_MaxX
;
305 if(max_y
) *max_y
= m_MaxY
;
306 if(lineHeight
) *lineHeight
= m_LineHeight
;
310 wxLayoutList::ResetSettings(wxDC
&dc
)
312 // setting up the default:
313 dc
.SetTextForeground( *wxBLACK
);
314 dc
.SetTextBackground( *wxWHITE
);
315 dc
.SetBackgroundMode( wxSOLID
); // to enable setting of text background
316 dc
.SetFont( *wxNORMAL_FONT
);
318 m_DefaultSetting
->Draw(dc
,wxPoint(0,0));
322 wxLayoutList::Layout(wxDC
&dc
, wxLayoutMargins
*margins
)
326 // first object in current line
327 wxLayoutObjectList::iterator headOfLine
;
328 // where we draw next
329 wxPoint position
, position_HeadOfLine
;
330 // size of last object
332 CoordType baseLine
= m_FontPtSize
;
333 CoordType baseLineSkip
= (BASELINESTRETCH
* baseLine
)/10;
334 CoordType objBaseLine
= baseLine
;
335 wxLayoutObjectType type
;
337 // we need to count cursor positions
338 wxPoint cursorPos
= wxPoint(0,0);
340 wxLayoutObjectBase
*cursorObject
= NULL
; // let's find it again
344 position
.y
= margins
->top
;
345 position
.x
= margins
->left
;
357 position_HeadOfLine
= position
;
364 type
= (*i
)->GetType();
365 (*i
)->Layout(dc
, position
, baseLine
);
366 size
= (*i
)->GetSize(&objBaseLine
);
367 // calculate next object's position:
368 position
.x
+= size
.x
;
370 // do we need to increase the line's height?
371 if(size
.y
> baseLineSkip
)
373 baseLineSkip
= size
.y
;
374 i
= headOfLine
; position
= position_HeadOfLine
;
377 if(objBaseLine
> baseLine
)
379 baseLine
= objBaseLine
;
380 i
= headOfLine
; position
= position_HeadOfLine
;
384 // when we reach here, the coordinates are valid, this part of
385 // the loop gets run only once per object
386 if(position
.x
> m_MaxX
)
388 if(type
== WXLO_TYPE_LINEBREAK
)
390 cursorPos
.x
= 0; cursorPos
.y
++;
393 cursorPos
.x
+= (**i
).CountPositions();
395 // now check whether we have finished handling this line:
396 if(type
== WXLO_TYPE_LINEBREAK
&& i
!= tail())
398 position
.x
= margins
? margins
->left
: 0;
399 position
.y
+= baseLineSkip
;
400 baseLine
= m_FontPtSize
;
401 objBaseLine
= baseLine
; // not all objects set it
402 baseLineSkip
= (BASELINESTRETCH
* baseLine
)/10;
405 position_HeadOfLine
= position
;
407 if(cursorObject
== NULL
&& cursorPos
.y
== m_CursorPos
.y
) // look for cursor
409 if(cursorPos
.x
>= m_CursorPos
.x
&&
410 m_CursorPos
.x
-cursorPos
.x
+(**i
).CountPositions()) // cursor is in current object
419 m_MaxY
= position
.y
+ baseLineSkip
;
423 wxLayoutList::Draw(wxDC
&dc
,
424 CoordType fromLine
, CoordType toLine
,
426 wxPoint
const &translate
)
428 Layout(dc
); // FIXME just for now
432 wxLayoutObjectList::iterator i
;
434 if(start
== iterator(NULL
))
436 else // we need to restore font settings
438 for( i
= begin() ; i
!= start
; i
++)
439 if((**i
).GetType() == WXLO_TYPE_CMD
)
440 (**i
).Draw(dc
,translate
); // apply font settings
443 while( start
!= end() && (**start
).GetPosition().y
< fromLine
)
445 if((**start
).GetType() == WXLO_TYPE_CMD
)
446 (**start
).Draw(dc
,translate
); // apply font settings
450 i
!= end() && (toLine
== -1 || (**i
).GetPosition().y
< toLine
) ;
452 (*i
)->Draw(dc
,translate
);
455 /** Erase at least to end of line */
457 wxLayoutList::EraseAndDraw(wxDC
&dc
, iterator start
)
459 //look for begin of line
460 while(start
!= end() && start
!= begin() && (**start
).GetType() !=
463 if(start
== iterator(NULL
))
465 if(start
== iterator(NULL
))
468 wxPoint p
= (**start
).GetPosition();
470 WXL_VAR(p
.x
);WXL_VAR(p
.y
);
471 //FIXME: wxGTK: MaxX()/MaxY() broken
472 //WXL_VAR(dc.MaxX()); WXL_VAR(dc.MaxY());
473 dc
.SetBrush(*wxWHITE_BRUSH
);
474 dc
.SetPen(wxPen(*wxWHITE
,0,wxTRANSPARENT
));
475 dc
.DrawRectangle(p
.x
,p
.y
,2000,2000); //dc.MaxX(),dc.MaxY());
476 Draw(dc
,-1,-1,start
,wxPoint(0,0));
477 //dc.DrawRectangle(p.x,p.y,2000,2000); //dc.MaxX(),dc.MaxY());
482 wxLayoutList::CalculateCursor(wxDC
&dc
)
484 CoordType width
, height
, descent
;
485 CoordType baseLineSkip
= 20; //FIXME
488 if( FindCurrentObject() == iterator(NULL
)) // empty list
490 DrawCursor(dc
,true); // erase it
491 m_CursorCoords
= wxPoint(0,0);
492 m_CursorSize
= wxPoint(2,baseLineSkip
);
493 m_CursorMoved
= false; // coords are valid
496 wxLayoutObjectBase
&obj
= **FindCurrentObject(&offset
);
499 DrawCursor(dc
,true); // erase it
500 m_CursorCoords
= obj
.GetPosition();
501 WXL_VAR(m_CursorCoords
.x
);
502 if(obj
.GetType() == WXLO_TYPE_TEXT
)
504 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)&obj
;
505 String
& str
= tobj
->GetText();
506 String sstr
= str
.substr(0,offset
);
508 dc
.GetTextExtent(sstr
,&width
,&height
,&descent
);
510 m_CursorCoords
= wxPoint(m_CursorCoords
.x
+width
,
512 m_CursorSize
= wxPoint(2,height
);
514 else if(obj
.GetType() == WXLO_TYPE_LINEBREAK
)
516 m_CursorCoords
= wxPoint(0, m_CursorCoords
.y
);
517 m_CursorSize
= wxPoint(2,baseLineSkip
);
521 // this is not necessarily the most "beautiful" solution:
522 //cursorPosition = wxPoint(position.x, position.y);
523 //cursorSize = wxPoint(size.x > 0 ? size.x : 1,size.y > 0 ? size.y : baseLineSkip);
524 m_CursorCoords
= wxPoint(m_CursorCoords
.x
+obj
.GetSize().x
, m_CursorCoords
.y
);
525 m_CursorSize
= wxPoint(2, obj
.GetSize().y
);
526 if(m_CursorSize
.y
< 1) m_CursorSize
.y
= baseLineSkip
;
528 WXL_VAR(m_CursorCoords
.x
);
529 m_CursorMoved
= false; // coords are valid
533 wxLayoutList::DrawCursor(wxDC
&dc
, bool erase
)
540 //dc.SetBrush(*wxWHITE_BRUSH);
541 //dc.SetPen(wxPen(*wxWHITE,1,wxSOLID));
542 //dc.DrawRectangle(m_CursorCoords.x, m_CursorCoords.y, m_CursorSize.x, m_CursorSize.y);
543 dc
.Blit(m_CursorCoords
.x
, m_CursorCoords
.y
, m_CursorSize
.x
,
544 m_CursorSize
.y
, &m_CursorMemDC
,
549 if(IsDirty() || CursorMoved())
555 wxBitmap
bm(m_CursorSize
.x
+1,m_CursorSize
.y
+1);
556 m_CursorMemDC
.SelectObject(bm
);
557 m_CursorMemDC
.Blit(0, 0, m_CursorSize
.x
, m_CursorSize
.y
,
558 &dc
, m_CursorCoords
.x
,
559 m_CursorCoords
.y
, 0, 0);
560 dc
.SetBrush(*wxBLACK_BRUSH
);
561 dc
.SetPen(wxPen(*wxBLACK
,1,wxSOLID
));
562 dc
.DrawRectangle(m_CursorCoords
.x
, m_CursorCoords
.y
,
563 m_CursorSize
.x
, m_CursorSize
.y
);
573 #ifdef WXLAYOUT_DEBUG
575 wxLayoutList::Debug(void)
578 wxLayoutObjectList::iterator i
;
580 wxLogDebug("------------------------debug start-------------------------");
581 for(i
= begin(); i
!= end(); i
++)
583 wxLogDebug("-----------------------debug end----------------------------");
585 // show current object:
587 i
= FindCurrentObject(&offs
);
588 wxLogDebug(" line length: %l", (long int) GetLineLength(i
,offs
));
591 wxLogDebug("<<no object found>>");
592 return; // FIXME we should set cursor position to maximum allowed
595 if((*i
)->GetType() == WXLO_TYPE_TEXT
)
596 wxLogDebug(" \"%s\", offs=%d",((wxLayoutObjectText
*)(*i
))->GetText().c_str(), (int) offs
);
598 wxLogDebug(g_aTypeStrings
[(*i
)->GetType()]);
603 wxLayoutList::ShowCurrentObject()
606 wxLayoutObjectList::iterator i
= FindCurrentObject(&offs
);
608 i
= FindCurrentObject(&offs
);
609 wxLogDebug(" Line length: %d", GetLineLength(i
));
613 wxLogDebug("<<no object found>>");
614 return; // FIXME we should set cursor position to maximum allowed
617 if((*i
)->GetType() == WXLO_TYPE_TEXT
)
618 wxLogDebug(" \"%s\", offs: %d",
619 ((wxLayoutObjectText
*)(*i
))->GetText().c_str(), offs
);
621 wxLogDebug(" %s", TypeString((*i
)->GetType()));
622 wxLayoutDebug("CursorPos (%d, %d)", (int) m_CursorPos
.x
, (int) m_CursorPos
.y
);
623 wxLayoutDebug("CursorOffset = %d", (int) m_CursorOffset
);
624 wxLayoutDebug("CursorObject = %p", m_CursorObject
);
630 /******************** editing stuff ********************/
632 // don't change this, I know how to optimise this and will do it real
637 * Finds the object belonging to a given cursor position cpos and
638 * returns an iterator to that object and stores the relative cursor
639 * position in offset.
641 * For linebreaks, the offset can be 0=before or 1=after.
643 * If the cpos coordinates don't exist, they are modified.
646 wxLayoutObjectList::iterator
647 wxLayoutList::FindObjectCursor(wxPoint
*cpos
, CoordType
*offset
)
649 wxPoint object
= wxPoint(0,0); // runs along the objects
651 wxLayoutObjectList::iterator i
, begin_it
;
654 //#ifdef WXLAYOUT_DEBUG
655 // wxLayoutDebug("Looking for object at (%d, %d)", cpos->x, cpos->y);
658 // optimisation: compare to last looked at object:
659 if(cpos
->y
> m_FoundCursor
.y
|| (cpos
->y
== m_FoundCursor
.y
&&
660 cpos
->x
>= m_FoundCursor
.x
))
665 //broken at the moment
666 //begin_it = m_FoundIterator;
667 //m_FoundCursor = *cpos;
670 for(i
= begin_it
; i
!= end() && object
.y
<= cpos
->y
; )
672 width
= (**i
).CountPositions();
673 if(cpos
->y
== object
.y
) // a possible candidate
675 if((**i
).GetType() ==WXLO_TYPE_LINEBREAK
)
677 if(cpos
->x
== object
.x
)
679 if(offset
) *offset
= 0;
680 return m_FoundIterator
= i
;
682 if(offset
) *offset
=1;
684 return m_FoundIterator
= i
;
686 if(cpos
->x
>= object
.x
&& cpos
->x
<= object
.x
+width
) // overlap
688 if(offset
) *offset
= cpos
->x
-object
.x
;
689 //#ifdef WXLAYOUT_DEBUG
690 // wxLayoutDebug(" found object at (%d, %d), type: %s",
691 // object.x, object.y, TypeString((*i)->GetType()));
693 return m_FoundIterator
= i
;
696 // no overlap, increment coordinates
698 if((**i
).GetType() == WXLO_TYPE_LINEBREAK
)
708 //#ifdef WXLAYOUT_DEBUG
709 // wxLayoutDebug(" not found");
711 // return last object, coordinates of that one:
714 return m_FoundIterator
= i
;
715 if((**i
).GetType()==WXLO_TYPE_LINEBREAK
)
719 return m_FoundIterator
= i
;
721 cpos
->x
= object
.x
; // would be the coordinate of next object
723 cpos
->x
+= width
; // last object's width
724 if(*offset
) *offset
= cpos
->x
-object
.x
;
725 return m_FoundIterator
= i
; // not found
728 wxLayoutObjectList::iterator
729 wxLayoutList::FindCurrentObject(CoordType
*offset
)
731 #if ! defined( USE_NEW_CURSORCODE )
732 wxLayoutObjectList::iterator obj
= end();
734 obj
= FindObjectCursor(&m_CursorPos
, offset
);
735 if(obj
== end()) // not ideal yet
738 if(obj
!= end()) // tail really exists
739 *offset
= (*obj
)->CountPositions(); // at the end of it
744 *offset
= m_CursorOffset
;
745 return m_CursorObject
;
749 #if ! defined( USE_NEW_CURSORCODE )
752 wxLayoutList::MoveCursor(int dx
, int dy
)
754 CoordType offs
, lineLength
;
755 wxLayoutObjectList::iterator i
;
757 m_CursorMoved
= true;
759 bool rc
= true; // have we moved?
761 //FIXME calculate cursor object & offset for y movements
762 if(dy
> 0 && m_CursorPos
.y
< m_MaxLine
)
764 else if(dy
< 0 && m_CursorPos
.y
> 0)
765 m_CursorPos
.y
+= dy
; // dy is negative
766 if(m_CursorPos
.y
< 0)
771 else if (m_CursorPos
.y
> m_MaxLine
)
773 m_CursorPos
.y
= m_MaxLine
;
779 i
= FindCurrentObject(&offs
);
780 lineLength
= GetLineLength(i
,offs
);
781 if(m_CursorPos
.x
< lineLength
)
789 if(m_CursorPos
.y
< m_MaxLine
)
798 break; // cannot move there
804 if(m_CursorPos
.x
> 0)
811 if(m_CursorPos
.y
> 0)
815 i
= FindCurrentObject(&offs
);
816 lineLength
= GetLineLength(i
,offs
);
817 m_CursorPos
.x
= lineLength
;
824 break; // cannot move left any more
829 i
= FindCurrentObject(&offs
);
830 lineLength
= GetLineLength(i
,offs
);
831 if(m_CursorPos
.x
> lineLength
)
833 m_CursorPos
.x
= lineLength
;
836 #ifdef WXLAYOUT_DEBUG
845 wxLayoutList::MoveCursor(int dx
, int dy
)
849 m_CursorMoved
= true;
851 enum { up
, down
} direction
;
853 wxPoint newPos
= wxPoint(m_CursorPos
.x
+ dx
,
857 if(newPos
.x
< 0) newPos
.x
= 0;
858 if(newPos
.y
< 0) newPos
.y
= 0;
859 else if(newPos
.y
> m_MaxLine
) newPos
.y
= m_MaxLine
;
861 if(newPos
.y
> m_CursorPos
.y
||
862 newPos
.y
== m_CursorPos
.y
&&
863 newPos
.x
>= m_CursorPos
.x
)
868 // now move cursor forwards until at the new position:
870 // first, go to the right line:
871 while(newPos
.y
!= m_CursorPos
.y
)
876 (**m_CursorObject
).CountPositions() - m_CursorOffset
;
877 if(m_CursorObject
== tail())
878 break; // can't go any further
879 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
880 && m_CursorOffset
== 1)
882 m_CursorPos
.y
++; m_CursorPos
.x
= 0;
884 m_CursorObject
++; m_CursorOffset
= 0;
888 m_CursorPos
.x
-= m_CursorOffset
;
889 if(m_CursorObject
== begin())
890 break; // can't go any further
891 if((**m_CursorObject
).GetType() == WXLO_TYPE_LINEBREAK
&&
895 m_CursorPos
.x
= GetLineLength(m_CursorObject
);
897 m_CursorObject
--; m_CursorOffset
= (**m_CursorObject
).CountPositions();
900 if(newPos
.y
!= m_CursorPos
.y
) // reached begin/end of list,
901 newPos
.y
= m_CursorPos
.y
; // exited by break
903 // now line is right, go to right column:
904 direction
= newPos
.x
>= m_CursorPos
.x
? up
: down
;
905 while(newPos
.x
!= m_CursorPos
.x
)
909 diff
= newPos
.x
- m_CursorPos
.x
;
910 if(diff
>= (**m_CursorObject
).CountPositions())
912 m_CursorPos
.x
+= (**m_CursorObject
).CountPositions();
913 if(m_CursorObject
== tail())
915 m_CursorOffset
= (**m_CursorObject
).CountPositions();
916 break; // cannot go further
918 m_CursorObject
++; m_CursorOffset
= 0;
922 m_CursorPos
.x
+= diff
;
923 m_CursorOffset
+= diff
;
928 diff
= m_CursorPos
.x
- newPos
.x
;
929 if(diff
>= m_CursorOffset
)
931 if(m_CursorObject
== begin())
935 break; // cannot go further
938 m_CursorOffset
= (**m_CursorObject
).CountPositions();
942 m_CursorPos
.x
-= diff
;
943 m_CursorOffset
-= diff
;
947 return true; // FIXME: when return what?
952 wxLayoutList::Delete(CoordType count
)
964 wxLayoutObjectList::iterator i
;
968 i
= FindCurrentObject(&offs
);
969 startover
: // ugly, but easiest way to do it
971 return; // we cannot delete anything more
973 /* Here we need to treat linebreaks differently.
974 If offs==0 we are before the linebreak, otherwise behind. */
975 if((*i
)->GetType() == WXLO_TYPE_LINEBREAK
)
981 m_CursorObject
= i
; // new i!
982 m_CursorOffset
= 0; // Pos unchanged
984 continue; // we're done
986 else // delete the object behind the linebreak
988 i
++; // we increment and continue as normal
993 else if((*i
)->GetType() == WXLO_TYPE_TEXT
)
995 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*)*i
;
996 CoordType len
= tobj
->CountPositions();
997 // If we find the end of a text object, this means that we
998 // have to delete from the object following it.
1005 else if(len
<= count
) // delete this object
1016 tobj
->GetText().erase(offs
,len
);
1018 return; // we are done
1021 else// all other objects: delete the object
1022 // this only works as expected if the non-text object has 0/1
1023 // as offset values. Not tested with "longer" objects.
1025 CoordType len
= (*i
)->CountPositions();
1028 count
= count
> len
? count
-= len
: 0;
1029 erase(i
); // after this, i is the iterator for the
1035 else // delete the following object
1037 i
++; // we increment and continue as normal
1043 while(count
&& i
!= end());
1047 wxLayoutList::Insert(wxLayoutObjectBase
*obj
)
1049 wxCHECK_RET( obj
, "no object to insert" );
1054 wxLayoutObjectList::iterator i
= FindCurrentObject(&offs
);
1056 // WXL_TRACE(Insert(obj));
1061 m_CursorObject
= tail();
1068 // do we have to split a text object?
1069 else if((*i
)->GetType() == WXLO_TYPE_TEXT
&& offs
!= (*i
)->CountPositions())
1071 wxLayoutObjectText
*tobj
= (wxLayoutObjectText
*) *i
;
1072 #ifdef WXLAYOUT_DEBUG
1073 wxLayoutDebug("text: %s", tobj
->GetText().c_str());
1076 String left
= tobj
->GetText().substr(0,offs
); // get part before cursor
1077 WXL_VAR(left
.c_str());
1078 tobj
->GetText() = tobj
->GetText().substr(offs
,(*i
)->CountPositions()-offs
); // keeps the right half
1079 WXL_VAR(tobj
->GetText().c_str());
1081 insert(i
,new wxLayoutObjectText(left
)); // inserts before
1085 // all other cases, append after object:
1086 wxLayoutObjectList::iterator j
= i
; // we want to apend after this object
1096 m_CursorObject
= tail();
1099 m_CursorPos
.x
+= obj
->CountPositions();
1100 m_CursorOffset
= obj
->CountPositions();
1102 if(obj
->GetType() == WXLO_TYPE_LINEBREAK
)
1104 m_CursorMoved
= true;
1108 wxLayoutList::Insert(String
const &text
)
1110 wxLayoutObjectText
*tobj
= NULL
;
1111 wxLayoutObjectList::iterator j
;
1113 // WXL_TRACE(Insert(text));
1121 wxLayoutObjectList::iterator i
= FindCurrentObject(&offs
);
1125 Insert(new wxLayoutObjectText(text
));
1129 switch((**i
).GetType())
1131 case WXLO_TYPE_TEXT
:
1132 // insert into an existing text object:
1133 WXL_TRACE(inserting into existing object
);
1134 tobj
= (wxLayoutObjectText
*)*i
;
1136 tobj
->GetText().insert(offs
,text
);
1138 m_CursorOffset
= offs
+ text
.length();
1139 m_CursorPos
.x
+= text
.length();
1141 case WXLO_TYPE_LINEBREAK
:
1144 if(offs
== 0) // try to append to previous object
1147 if(j
!= end() && (**j
).GetType() == WXLO_TYPE_TEXT
)
1149 tobj
= (wxLayoutObjectText
*)*j
;
1150 tobj
->GetText()+=text
;
1152 m_CursorOffset
= (**j
).CountPositions();
1153 m_CursorPos
.x
+= text
.length();
1157 insert(i
,new wxLayoutObjectText(text
));
1159 m_CursorOffset
= (**i
).CountPositions();
1160 m_CursorPos
.x
+= m_CursorOffset
;
1163 else // offset == 1 : cursor after linebreak
1169 if(j
!= end() && (**j
).GetType() == WXLO_TYPE_TEXT
)
1171 tobj
= (wxLayoutObjectText
*)*j
;
1172 tobj
->GetText()=text
+tobj
->GetText();
1173 m_CursorOffset
= text
.length();
1174 m_CursorPos
.x
+= m_CursorOffset
;
1180 push_back(new wxLayoutObjectText(text
));
1181 m_CursorObject
= tail();
1182 m_CursorOffset
= (**m_CursorObject
).CountPositions();
1183 m_CursorPos
.x
+= text
.length();
1187 insert(j
,new wxLayoutObjectText(text
));
1189 m_CursorOffset
= (**j
).CountPositions();
1190 m_CursorPos
.x
+= text
.length();
1196 m_CursorMoved
= true;
1200 wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i
, CoordType offs
)
1207 if(offs
== 0 && (**i
).GetType() == WXLO_TYPE_LINEBREAK
)
1208 // we are before a linebrak
1210 // search backwards for beginning of line:
1211 while(i
!= begin() && (*i
)->GetType() != WXLO_TYPE_LINEBREAK
)
1213 if((*i
)->GetType() == WXLO_TYPE_LINEBREAK
)
1215 // now we can start counting:
1216 while(i
!= end() && (*i
)->GetType() != WXLO_TYPE_LINEBREAK
)
1218 len
+= (*i
)->CountPositions();
1225 wxLayoutList::Clear(int family
, int size
, int style
, int weight
,
1226 int underline
, char const *fg
, char const *bg
)
1229 m_CursorMoved
= true;
1230 m_dirty
= true; // force redraw/recalc
1231 wxLayoutObjectList::iterator i
= begin();
1234 m_CursorMemDC
.SelectObject(bm
);
1236 while(i
!= end()) // == while valid
1240 m_FontPtSize
= size
;
1241 m_FontUnderline
= false;
1242 m_FontFamily
= family
;
1243 m_FontStyle
= style
;
1244 m_FontWeight
= weight
;
1245 m_ColourFG
= wxTheColourDatabase
->FindColour(fg
);
1246 m_ColourBG
= wxTheColourDatabase
->FindColour(bg
);
1248 if(! m_ColourFG
) m_ColourFG
= wxBLACK
;
1249 if(! m_ColourBG
) m_ColourBG
= wxWHITE
;
1251 m_Position
= wxPoint(0,0);
1252 m_CursorPos
= wxPoint(0,0);
1253 m_CursorObject
= iterator(NULL
);
1257 m_LineHeight
= (BASELINESTRETCH
*m_FontPtSize
)/10;
1258 m_MaxX
= 0; m_MaxY
= 0;
1261 m_FoundCursor
= wxPoint(0,0);
1262 m_FoundIterator
= begin();
1264 if(m_DefaultSetting
)
1265 delete m_DefaultSetting
;
1267 m_DefaultSetting
= new
1268 wxLayoutObjectCmd(m_FontPtSize
,m_FontFamily
,m_FontStyle
,
1269 m_FontWeight
,m_FontUnderline
,
1270 m_ColourFG
, m_ColourBG
);
1274 wxLayoutObjectBase
*
1275 wxLayoutList::Find(wxPoint coords
) const
1277 wxLayoutObjectList::iterator i
= begin();
1279 wxPoint topleft
, bottomright
;
1281 while(i
!= end()) // == while valid
1283 wxLayoutObjectBase
*object
= *i
;
1284 topleft
= object
->GetPosition();
1285 if(coords
.y
>= topleft
.y
&& coords
.x
>= topleft
.x
)
1287 bottomright
= topleft
;
1288 bottomright
.x
+= object
->GetSize().x
;
1289 bottomright
.y
+= object
->GetSize().y
;
1290 if(coords
.x
<= bottomright
.x
&& coords
.y
<= bottomright
.y
)
1299 /******************** printing stuff ********************/
1301 wxLayoutPrintout::wxLayoutPrintout(wxLayoutList
&llist
,
1302 wxString
const & title
)
1309 bool wxLayoutPrintout::OnPrintPage(int page
)
1314 DrawHeader(*dc
,wxPoint(m_Margins
.left
,m_Margins
.top
/2),wxPoint(m_Margins
.right
,m_Margins
.top
),page
);
1316 top
= (page
- 1)*m_PrintoutHeight
;
1317 bottom
= top
+ m_PrintoutHeight
;
1318 // SetDeviceOrigin() doesn't work here, so we need to manually
1319 // translate all coordinates.
1320 wxPoint
translate(m_Margins
.left
,-top
+m_Margins
.top
);
1321 m_llist
->Draw(*dc
,top
,bottom
,wxLayoutObjectList::iterator(NULL
),translate
);
1328 bool wxLayoutPrintout::OnBeginDocument(int startPage
, int endPage
)
1330 if (!wxPrintout::OnBeginDocument(startPage
, endPage
))
1337 wxLayoutPrintout::OnPreparePrinting(void)
1343 void wxLayoutPrintout::GetPageInfo(int *minPage
, int *maxPage
, int *selPageFrom
, int *selPageTo
)
1345 // ugly hack to get number of pages
1347 wxPrinterDC
psdc("", "", WXLLIST_TEMPFILE
,false);
1349 wxPostScriptDC
psdc(WXLLIST_TEMPFILE
,false);
1351 psdc
.GetSize(&m_PageWidth
, &m_PageHeight
); // that's all we need it for
1353 // We do 5% margins on top and bottom, and a 5% high header line.
1354 m_Margins
.top
= m_PageHeight
/ 10 ; // 10%, half of it header
1355 m_Margins
.bottom
= m_PageHeight
- m_PageHeight
/ 20; // 95%
1356 // On the sides we reserve 10% each for the margins.
1357 m_Margins
.left
= m_PageWidth
/ 10;
1358 m_Margins
.right
= m_PageWidth
- m_PageWidth
/ 10;
1360 // This is the length of the printable area.
1361 m_PrintoutHeight
= m_PageHeight
- (int) (m_PageHeight
* 0.15);
1363 //FIXME this is wrong but not used at the moment
1364 m_PageWidth
= m_Margins
.right
- m_Margins
.left
;
1366 m_NumOfPages
= (int)( m_llist
->GetSize().y
/ (float)(m_PrintoutHeight
) + 0.5);
1368 *maxPage
= m_NumOfPages
;
1371 *selPageTo
= m_NumOfPages
;
1372 wxRemoveFile(WXLLIST_TEMPFILE
);
1375 bool wxLayoutPrintout::HasPage(int pageNum
)
1377 return pageNum
< m_NumOfPages
;
1382 wxLayoutPrintout::DrawHeader(wxDC
&dc
,
1383 wxPoint topleft
, wxPoint bottomright
,
1386 // make backups of all essential parameters
1387 wxBrush
*brush
= dc
.GetBrush();
1388 wxPen
*pen
= dc
.GetPen();
1389 wxFont
*font
= dc
.GetFont(),
1392 dc
.SetBrush(*wxWHITE_BRUSH
);
1393 dc
.SetPen(wxPen(*wxBLACK
,0,wxSOLID
));
1394 dc
.DrawRoundedRectangle(topleft
.x
,
1395 topleft
.y
,bottomright
.x
-topleft
.x
,
1396 bottomright
.y
-topleft
.y
);
1397 dc
.SetBrush(*wxBLACK_BRUSH
);
1398 myfont
= new wxFont((WXLO_DEFAULTFONTSIZE
*12)/10,wxSWISS
,wxNORMAL
,wxBOLD
,false,"Helvetica");
1399 dc
.SetFont(*myfont
);
1402 page
= "9999/9999 "; // many pages...
1404 dc
.GetTextExtent(page
,&w
,&h
);
1405 page
.Printf("%d/%d", pageno
, (int) m_NumOfPages
);
1406 dc
.DrawText(page
,bottomright
.x
-w
,topleft
.y
+h
/2);
1407 dc
.GetTextExtent("XXXX", &w
,&h
);
1408 dc
.DrawText(m_title
, topleft
.x
+w
,topleft
.y
+h
/2);
1412 dc
.SetBrush(*brush
);
1420 wxLayoutList::MakePrintout(wxString
const &name
)
1422 return new wxLayoutPrintout(*this,name
);