]> git.saurik.com Git - wxWidgets.git/blob - user/wxLayout/wxllist.cpp
938d91670d1dff79b2b171c7da8b9f365c4f6183
[wxWidgets.git] / user / wxLayout / wxllist.cpp
1 /*-*- c++ -*-********************************************************
2 * wxFTCanvas: a canvas for editing formatted text *
3 * *
4 * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) *
5 * *
6 * $Id$ *
7 *******************************************************************/
8
9 /*
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 - during redraw each line gets iterated over twice, first just
15 calculating baselines and positions, second to actually draw it
16 - the cursor position is the position before an object, i.e. if the
17 buffer starts with a text-object, cursor 0,0 is just before the
18 first character
19 */
20
21 #ifdef __GNUG__
22 #pragma implementation "wxllist.h"
23 #endif
24
25 // these two lines are for use in M:
26 //#include "Mpch.h"
27 //#include "gui/wxllist.h"
28
29 #include "wxllist.h"
30
31 #ifndef USE_PCH
32 # include "iostream.h"
33
34 # include <wx/dc.h>
35 # include <wx/postscrp.h>
36 # include <wx/print.h>
37 #endif
38
39 #define BASELINESTRETCH 12
40
41 #ifdef WXLAYOUT_DEBUG
42 static const char *_t[] = { "invalid", "text", "cmd", "icon",
43 "linebreak"};
44
45 void
46 wxLayoutObjectBase::Debug(void)
47 {
48 CoordType bl = 0;
49 cerr << _t[GetType()] << ": size=" << GetSize(&bl).x << ","
50 << GetSize(&bl).y << " bl=" << bl;
51 }
52
53 # define WXL_VAR(x) cerr << #x"=" << x << endl
54 # define WXL_DBG_POINT(p) cerr << #p << ": " << p.x << ',' << p.y << endl
55 # define WXL_TRACE(f) cerr << #f":" << endl
56 #else
57 # define WXL_VAR(x)
58 # define WXL_DBG_POINT(p)
59 # define WXL_TRACE(f)
60 #endif
61
62 //-------------------------- wxLayoutObjectText
63
64 wxLayoutObjectText::wxLayoutObjectText(const String &txt)
65 {
66 m_Text = txt;
67 m_Width = 0;
68 m_Height = 0;
69 }
70
71
72 wxPoint
73 wxLayoutObjectText::GetSize(CoordType *baseLine) const
74 {
75 if(baseLine) *baseLine = m_BaseLine;
76 return wxPoint(m_Width, m_Height);
77 }
78
79 void
80 wxLayoutObjectText::Draw(wxDC &dc, wxPoint position, CoordType baseLine,
81 bool draw)
82 {
83 long descent = 0l;
84 dc.GetTextExtent(Str(m_Text),&m_Width, &m_Height, &descent);
85 //FIXME: wxGTK does not set descent to a descent value yet.
86 if(descent == 0)
87 descent = (2*m_Height)/10; // crude fix
88 m_BaseLine = m_Height - descent;
89 position.y += baseLine-m_BaseLine;
90 if(draw)
91 dc.DrawText(Str(m_Text),position.x,position.y);
92 # ifdef WXLAYOUT_DEBUG
93 // dc.DrawRectangle(position.x, position.y, m_Width, m_Height);
94 # endif
95 }
96
97 #ifdef WXLAYOUT_DEBUG
98 void
99 wxLayoutObjectText::Debug(void)
100 {
101 wxLayoutObjectBase::Debug();
102 cerr << " `" << m_Text << '\'';
103 }
104 #endif
105
106 //-------------------------- wxLayoutObjectIcon
107
108 wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon *icon)
109 : m_Icon(icon)
110 {
111 }
112
113 void
114 wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint position, CoordType baseLine,
115 bool draw)
116 {
117 position.y += baseLine - m_Icon->GetHeight();
118 if(draw)
119 dc.DrawIcon(m_Icon,position.x,position.y);
120 }
121
122 wxPoint
123 wxLayoutObjectIcon::GetSize(CoordType *baseLine) const
124 {
125 wxASSERT(baseLine);
126 *baseLine = m_Icon->GetHeight();
127 return wxPoint(m_Icon->GetWidth(), m_Icon->GetHeight());
128 }
129
130 //-------------------------- wxLayoutObjectCmd
131
132
133 wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int
134 weight, bool underline,
135 wxColour const *fg, wxColour const *bg)
136
137 {
138 m_font = new wxFont(size,family,style,weight,underline);
139 m_ColourFG = fg;
140 m_ColourBG = bg;
141 }
142
143 wxLayoutObjectCmd::~wxLayoutObjectCmd()
144 {
145 delete m_font;
146 }
147
148 wxLayoutStyleInfo *
149 wxLayoutObjectCmd::GetStyle(void) const
150 {
151 wxLayoutStyleInfo *si = new wxLayoutStyleInfo();
152
153
154 si->size = m_font->GetPointSize();
155 si->family = m_font->GetFamily();
156 si->style = m_font->GetStyle();
157 si->underline = m_font->GetUnderlined();
158 si->weight = m_font->GetWeight();
159
160 si->fg_red = m_ColourFG->Red();
161 si->fg_green = m_ColourFG->Green();
162 si->fg_blue = m_ColourFG->Blue();
163 si->bg_red = m_ColourBG->Red();
164 si->bg_green = m_ColourBG->Green();
165 si->bg_blue = m_ColourBG->Blue();
166
167 return si;
168 }
169
170 void
171 wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint position, CoordType lineHeight,
172 bool draw)
173 {
174 wxASSERT(m_font);
175 // this get called even when draw==false, so that recalculation
176 // uses right font sizes
177 dc.SetFont(m_font);
178 if(m_ColourFG)
179 dc.SetTextForeground(*m_ColourFG);
180 if(m_ColourBG)
181 dc.SetTextBackground(*m_ColourBG);
182 }
183
184 //-------------------------- wxwxLayoutList
185
186 wxLayoutList::wxLayoutList()
187 {
188 m_DefaultSetting = NULL;
189 Clear();
190 }
191
192 wxLayoutList::~wxLayoutList()
193 {
194 if(m_DefaultSetting)
195 delete m_DefaultSetting;
196 }
197
198
199 void
200 wxLayoutList::LineBreak(void)
201 {
202 Insert(new wxLayoutObjectLineBreak);
203 m_CursorPosition.x = 0; m_CursorPosition.y++;
204 }
205
206 void
207 wxLayoutList::SetFont(int family, int size, int style, int weight,
208 int underline, wxColour const *fg,
209 wxColour const *bg)
210 {
211 if(family != -1) m_FontFamily = family;
212 if(size != -1) m_FontPtSize = size;
213 if(style != -1) m_FontStyle = style;
214 if(weight != -1) m_FontWeight = weight;
215 if(underline != -1) m_FontUnderline = underline != 0;
216
217 if(fg != NULL) m_ColourFG = fg;
218 if(bg != NULL) m_ColourBG = bg;
219
220 Insert(
221 new wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,m_FontWeight,m_FontUnderline,
222 m_ColourFG, m_ColourBG));
223 }
224
225 void
226 wxLayoutList::SetFont(int family, int size, int style, int weight,
227 int underline, char const *fg, char const *bg)
228 {
229 wxColour const
230 * cfg = NULL,
231 * cbg = NULL;
232
233 if( fg )
234 cfg = wxTheColourDatabase->FindColour(fg);
235 if( bg )
236 cbg = wxTheColourDatabase->FindColour(bg);
237
238 SetFont(family,size,style,weight,underline,cfg,cbg);
239 }
240
241
242 /// for access by wxLayoutWindow:
243 void
244 wxLayoutList::GetSize(CoordType *max_x, CoordType *max_y,
245 CoordType *lineHeight)
246 {
247 wxASSERT(max_x); wxASSERT(max_y); wxASSERT(lineHeight);
248 *max_x = m_MaxX;
249 *max_y = m_MaxY;
250 *lineHeight = m_LineHeight;
251 }
252
253 wxLayoutObjectBase *
254 wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const &findCoords)
255 {
256 wxLayoutObjectList::iterator i;
257
258 // in case we need to look for an object
259 wxLayoutObjectBase *foundObject = NULL;
260
261 // first object in current line
262 wxLayoutObjectList::iterator headOfLine;
263
264 // do we need to recalculate current line?
265 bool recalculate = false;
266
267 // do we calculate or draw? Either true or false.
268 bool draw = false;
269 // drawing parameters:
270 wxPoint position = wxPoint(0,0);
271 wxPoint position_HeadOfLine;
272 CoordType baseLine = m_FontPtSize;
273 CoordType baseLineSkip = (BASELINESTRETCH * baseLine)/10;
274
275 // where to draw the cursor
276 wxPoint
277 cursorPosition = wxPoint(0,0),
278 cursorSize = wxPoint(1,baseLineSkip);
279
280 // the cursor position inside the object
281 CoordType cursorOffset = 0;
282 // object under cursor
283 wxLayoutObjectList::iterator cursorObject = FindCurrentObject(&cursorOffset);
284
285 // queried from each object:
286 wxPoint size = wxPoint(0,0);
287 CoordType objBaseLine = baseLine;
288 wxLayoutObjectType type;
289
290 // used temporarily
291 wxLayoutObjectText *tobj = NULL;
292
293
294 // this is needed for printing to a printer:
295 // only interesting for printer/PS output
296 int pageWidth, pageHeight; //GetSize() still needs int at the moment
297 struct
298 {
299 int top, bottom, left, right;
300 } margins;
301
302 if(
303 #ifdef __WXMSW__
304 dc.IsKindOf(CLASSINFO(wxPrinterDC)) ||
305 #endif
306 dc.IsKindOf(CLASSINFO(wxPostScriptDC)))
307 {
308 dc.GetSize(&pageWidth, &pageHeight);
309 dc.StartDoc(_("Printing..."));
310 dc.StartPage();
311 margins.top = (1*pageHeight)/10; // 10%
312 margins.bottom = (9*pageHeight)/10; // 90%
313 margins.left = (1*pageWidth)/10;
314 margins.right = (9*pageWidth)/10;
315 }
316 else
317 {
318 margins.top = 0; margins.left = 0;
319 margins.right = -1;
320 margins.bottom = -1;
321 }
322 position.y = margins.right;
323 position.x = margins.left;
324
325 // if the cursorobject is a cmd, we need to find the first
326 // printable object:
327 while(cursorObject != end()
328 && (*cursorObject)->GetType() == WXLO_TYPE_CMD)
329 cursorObject++;
330
331 headOfLine = begin();
332 position_HeadOfLine = position;
333
334 // setting up the default:
335 dc.SetTextForeground( *wxBLACK );
336 dc.SetTextBackground( *wxWHITE );
337 dc.SetBackgroundMode( wxSOLID ); // to enable setting of text background
338 dc.SetFont( *wxNORMAL_FONT );
339
340
341 //FIXME: who frees the brush, how long does it need to exist?
342 if(m_DefaultSetting)
343 m_DefaultSetting->Draw(dc,wxPoint(0,0),0,true);
344
345 // we calculate everything for drawing a line, then rewind to the
346 // begin of line and actually draw it
347 i = begin();
348 for(;;)
349 {
350 recalculate = false;
351
352 if(i == end())
353 break;
354 type = (*i)->GetType();
355
356 // to initialise sizes of objects, we need to call Draw
357 (*i)->Draw(dc, position, baseLine, draw);
358
359 // update coordinates for next object:
360 size = (*i)->GetSize(&objBaseLine);
361 if(findObject && draw) // we need to look for an object
362 {
363 if(findCoords.y >= position.y
364 && findCoords.y <= position.y+size.y
365 && findCoords.x >= position.x
366 && findCoords.x <= position.x+size.x)
367 {
368 foundObject = *i;
369 findObject = false; // speeds things up
370 }
371 }
372 // draw the cursor
373 if(m_Editable && draw && i == cursorObject)
374 {
375 WXL_VAR((**cursorObject).GetType());
376 WXL_VAR(m_CursorPosition.x); WXL_VAR(m_CursorPosition.y);
377 if(type == WXLO_TYPE_TEXT) // special treatment
378 {
379 long descent = 0l; long width, height;
380 tobj = (wxLayoutObjectText *)*i;
381 String str = tobj->GetText();
382 WXL_VAR(m_CursorPosition.x);
383 str = str.substr(0, cursorOffset);
384 dc.GetTextExtent(Str(str), &width,&height, &descent);
385 cursorPosition = wxPoint(position.x+width,
386 position.y+(baseLineSkip-height));
387 cursorSize = wxPoint(1, height);
388 }
389 else if(type == WXLO_TYPE_LINEBREAK)
390 {
391 WXL_VAR(cursorOffset);
392 if(cursorOffset)
393 cursorPosition = wxPoint(0, position.y+baseLineSkip);
394 else
395 cursorPosition = wxPoint(0, position.y);
396 cursorSize = wxPoint(1,baseLineSkip);
397
398 }
399 else
400 {
401 cursorPosition = wxPoint(position.x, position.y);
402 cursorSize = wxPoint(size.x > 0 ? size.x : 1,size.y > 0 ? size.y : baseLineSkip);
403 }
404 }
405
406 // calculate next object's position:
407 position.x += size.x;
408 if(position.x > m_MaxX)
409 m_MaxX = position.x;
410
411 // do we need to increase the line's height?
412 if(size.y > baseLineSkip)
413 {
414 baseLineSkip = size.y;
415 recalculate = true;
416 }
417 if(objBaseLine > baseLine)
418 {
419 baseLine = objBaseLine;
420 recalculate = true;
421 }
422
423 // now check whether we have finished handling this line:
424 if(type == WXLO_TYPE_LINEBREAK || i == tail())
425 {
426 if(recalculate) // do this line again
427 {
428 position.x = position_HeadOfLine.x;
429 i = headOfLine;
430 continue;
431 }
432
433 if(! draw) // finished calculating sizes
434 {
435 // if the this line needs to go onto a new page, we need
436 // to change pages before drawing it:
437 if(margins.bottom != -1 && position.y > margins.bottom)
438 {
439 dc.EndPage();
440 position_HeadOfLine.y = margins.top;
441 dc.StartPage();
442 }
443 // do this line again, this time drawing it
444 position = position_HeadOfLine;
445 draw = true;
446 i = headOfLine;
447 continue;
448 }
449 else // we have drawn a line, so continue calculating next one
450 draw = false;
451 }
452
453 // is it a linebreak?
454 if(type == WXLO_TYPE_LINEBREAK || i == tail())
455 {
456 position.x = margins.left;
457 position.y += baseLineSkip;
458 baseLine = m_FontPtSize;
459 objBaseLine = baseLine; // not all objects set it
460 baseLineSkip = (BASELINESTRETCH * baseLine)/10;
461 headOfLine = i;
462 headOfLine++;
463 position_HeadOfLine = position;
464 }
465 i++;
466 }
467 dc.EndDoc();
468 // draw the cursor
469 if(m_Editable)
470 {
471 dc.DrawRectangle(cursorPosition.x, cursorPosition.y,
472 cursorSize.x, cursorSize.y);
473 }
474 m_MaxY = position.y;
475 return foundObject;
476 }
477
478 #ifdef WXLAYOUT_DEBUG
479 void
480 wxLayoutList::Debug(void)
481 {
482 CoordType offs;
483 wxLayoutObjectList::iterator i;
484
485 cerr <<
486 "------------------------debug start-------------------------" << endl;
487 for(i = begin(); i != end(); i++)
488 {
489 (*i)->Debug();
490 cerr << endl;
491 }
492 cerr <<
493 "-----------------------debug end----------------------------"
494 << endl;
495 // show current object:
496 cerr << "Cursor: "
497 << m_CursorPosition.x << ','
498 << m_CursorPosition.y;
499
500 i = FindCurrentObject(&offs);
501 cerr << " line length: " << GetLineLength(i,offs) << " ";
502 if(i == end())
503 {
504 cerr << "<<no object found>>" << endl;
505 return; // FIXME we should set cursor position to maximum allowed
506 // value then
507 }
508 if((*i)->GetType() == WXLO_TYPE_TEXT)
509 {
510 cerr << " \"" << ((wxLayoutObjectText *)(*i))->GetText() << "\", offs: "
511 << offs << endl;
512 }
513 else
514 cerr << ' ' << _t[(*i)->GetType()] << endl;
515
516 }
517 #endif
518
519 /******************** editing stuff ********************/
520
521 // don't change this, I know how to optimise this and will do it real
522 // soon (KB)
523
524 /*
525 * FindObjectCursor:
526 * Finds the object belonging to a given cursor position cpos and
527 * returns an iterator to that object and stores the relative cursor
528 * position in offset.
529 *
530 * For linebreaks, the offset can be 0=before or 1=after.
531 *
532 * If the cpos coordinates don't exist, they are modified.
533 */
534
535 wxLayoutObjectList::iterator
536 wxLayoutList::FindObjectCursor(wxPoint *cpos, CoordType *offset)
537 {
538 wxPoint object = wxPoint(0,0); // runs along the objects
539 CoordType width;
540 wxLayoutObjectList::iterator i;
541
542 #ifdef WXLAYOUT_DEBUG
543 cerr << "Looking for object at " << cpos->x << ',' << cpos->y <<
544 endl;
545 #endif
546 for(i = begin(); i != end() && object.y <= cpos->y; i++)
547 {
548 width = (**i).CountPositions();
549 if(cpos->y == object.y) // a possible candidate
550 {
551 if((**i).GetType() ==WXLO_TYPE_LINEBREAK)
552 {
553 if(cpos->x == object.x)
554 {
555 if(offset) *offset = 0;
556 return i;
557 }
558 if(offset) *offset=1;
559 cpos->x = object.x;
560 return i;
561 }
562 if(cpos->x >= object.x && cpos->x <= object.x+width) // overlap
563 {
564 if(offset) *offset = cpos->x-object.x;
565 #ifdef WXLAYOUT_DEBUG
566 cerr << " found object at " << object.x << ',' <<
567 object.y << ", type:" << _t[(*i)->GetType()] <<endl;
568 #endif
569 return i;
570 }
571 }
572 // no overlap, increment coordinates
573 object.x += width;
574 if((**i).GetType() == WXLO_TYPE_LINEBREAK)
575 {
576 object.x = 0;
577 object.y++;
578 }
579 }
580 #ifdef WXLAYOUT_DEBUG
581 cerr << " not found" << endl;
582 #endif
583 // return last object, coordinates of that one:
584 i = tail();
585 if(i == end())
586 return i;
587 if((**i).GetType()==WXLO_TYPE_LINEBREAK)
588 {
589 if(offset)
590 *offset = 1;
591 return i;
592 }
593 cpos->x = object.x; // would be the coordinate of next object
594 cpos->y = object.y;
595 cpos->x += width; // last object's width
596 if(*offset) *offset = cpos->x-object.x;
597 return i; // not found
598 }
599
600 wxLayoutObjectList::iterator
601 wxLayoutList::FindCurrentObject(CoordType *offset)
602 {
603 wxLayoutObjectList::iterator obj = end();
604
605 obj = FindObjectCursor(&m_CursorPosition, offset);
606 if(obj == end()) // not ideal yet
607 {
608 obj = tail();
609 if(obj != end()) // tail really exists
610 *offset = (*obj)->CountPositions(); // at the end of it
611 }
612 return obj;
613 }
614
615 bool
616 wxLayoutList::MoveCursor(int dx, int dy)
617 {
618 CoordType offs, lineLength;
619 wxLayoutObjectList::iterator i;
620
621 bool rc = true; // have we moved?
622
623 if(dy > 0 && m_CursorPosition.y < m_MaxLine)
624 m_CursorPosition.y += dy;
625 else if(dy < 0 && m_CursorPosition.y > 0)
626 m_CursorPosition.y += dy; // dy is negative
627 if(m_CursorPosition.y < 0)
628 {
629 m_CursorPosition.y = 0;
630 rc = false;
631 }
632 else if (m_CursorPosition.y > m_MaxLine)
633 {
634 m_CursorPosition.y = m_MaxLine;
635 rc = false;
636 }
637
638 while(dx > 0)
639 {
640 i = FindCurrentObject(&offs);
641 lineLength = GetLineLength(i,offs);
642 if(m_CursorPosition.x < lineLength)
643 {
644 m_CursorPosition.x ++;
645 dx--;
646 continue;
647 }
648 else
649 {
650 if(m_CursorPosition.y < m_MaxLine)
651 {
652 m_CursorPosition.y++;
653 m_CursorPosition.x = 0;
654 dx--;
655 }
656 else
657 {
658 rc = false;
659 break; // cannot move there
660 }
661 }
662 }
663 while(dx < 0)
664 {
665 if(m_CursorPosition.x > 0)
666 {
667 m_CursorPosition.x --;
668 dx++;
669 }
670 else
671 {
672 if(m_CursorPosition.y > 0)
673 {
674 m_CursorPosition.y --;
675 m_CursorPosition.x = 0;
676 i = FindCurrentObject(&offs);
677 lineLength = GetLineLength(i,offs);
678 m_CursorPosition.x = lineLength;
679 dx++;
680 continue;
681 }
682 else
683 {
684 rc = false;
685 break; // cannot move left any more
686 }
687 }
688 }
689 // final adjustment:
690 i = FindCurrentObject(&offs);
691 lineLength = GetLineLength(i,offs);
692 if(m_CursorPosition.x > lineLength)
693 {
694 m_CursorPosition.x = lineLength;
695 rc = false;
696 }
697 #ifdef WXLAYOUT_DEBUG
698 i = FindCurrentObject(&offs);
699 cerr << "Cursor: "
700 << m_CursorPosition.x << ','
701 << m_CursorPosition.y;
702
703 if(i == end())
704 {
705 cerr << "<<no object found>>" << endl;
706 return rc; // FIXME we should set cursor position to maximum allowed
707 // value then
708 }
709 if((*i)->GetType() == WXLO_TYPE_TEXT)
710 {
711 cerr << " \"" << ((wxLayoutObjectText *)(*i))->GetText() << "\", offs: "
712 << offs << endl;
713 }
714 else
715 cerr << ' ' << _t[(*i)->GetType()] << endl;
716 #endif
717 return rc;
718 }
719
720 void
721 wxLayoutList::Delete(CoordType count)
722 {
723 WXL_TRACE(Delete);
724
725 if(!m_Editable)
726 return;
727
728 WXL_VAR(count);
729
730 CoordType offs;
731 wxLayoutObjectList::iterator i;
732
733 do
734 {
735 i = FindCurrentObject(&offs);
736 startover: // ugly, but easiest way to do it
737 if(i == end())
738 return; // we cannot delete anything more
739
740 /* Here we need to treat linebreaks differently.
741 If offs==0 we are before the linebreak, otherwise behind. */
742 if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
743 {
744 if(offs == 0)
745 {
746 m_MaxLine--;
747 erase(i);
748 count--;
749 continue; // we're done
750 }
751 else // delete the object behind the linebreak
752 {
753 i++; // we increment and continue as normal
754 offs=0;
755 goto startover;
756 }
757 }
758 else if((*i)->GetType() == WXLO_TYPE_TEXT)
759 {
760 wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
761 CoordType len = tobj->CountPositions();
762 // If we find the end of a text object, this means that we
763 // have to delete from the object following it.
764 if(len == offs)
765 {
766 i++;
767 offs = 0;
768 goto startover;
769 }
770 else if(len <= count) // delete this object
771 {
772 count -= len;
773 erase(i);
774 continue;
775 }
776 else
777 {
778 len = count;
779 tobj->GetText().erase(offs,len);
780 return; // we are done
781 }
782 }
783 else // all other objects: delete the object
784 {
785 CoordType len = (*i)->CountPositions();
786 erase(i); // after this, i is the iterator for the following object
787 count = count > len ? count -= len : 0;
788 }
789 }
790 while(count && i != end());
791 }
792
793 void
794 wxLayoutList::Insert(wxLayoutObjectBase *obj)
795 {
796 wxASSERT(obj);
797 CoordType offs;
798 wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
799
800 WXL_TRACE(Insert(obj));
801
802 if(i == end())
803 push_back(obj);
804 else if(offs == 0)
805 insert(i,obj);
806 // do we have to split a text object?
807 else if((*i)->GetType() == WXLO_TYPE_TEXT && offs != (*i)->CountPositions())
808 {
809 wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
810 #ifdef WXLAYOUT_DEBUG
811 cerr << "text: '" << tobj->GetText() << "'" << endl;
812 WXL_VAR(offs);
813 #endif
814 String left = tobj->GetText().substr(0,offs); // get part before cursor
815 WXL_VAR(left);
816 tobj->GetText() = tobj->GetText().substr(offs,(*i)->CountPositions()-offs); // keeps the right half
817 WXL_VAR(tobj->GetText());
818 insert(i,obj);
819 insert(i,new wxLayoutObjectText(left)); // inserts before
820 }
821 else
822 {
823 // all other cases, append after object:
824 wxLayoutObjectList::iterator j = i; // we want to apend after this object
825 j++;
826 if(j != end())
827 insert(j, obj);
828 else
829 push_back(obj);
830 }
831
832 m_CursorPosition.x += obj->CountPositions();
833 if(obj->GetType() == WXLO_TYPE_LINEBREAK)
834 m_MaxLine++;
835 }
836
837 void
838 wxLayoutList::Insert(String const &text)
839 {
840 wxLayoutObjectText *tobj = NULL;
841 wxLayoutObjectList::iterator j;
842
843 WXL_TRACE(Insert(text));
844
845 if(! m_Editable)
846 return;
847
848 CoordType offs;
849 wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
850
851 if(i == end())
852 {
853 Insert(new wxLayoutObjectText(text));
854 return;
855 }
856
857 switch((**i).GetType())
858 {
859 case WXLO_TYPE_TEXT:
860 // insert into an existing text object:
861 WXL_TRACE(inserting into existing object);
862 tobj = (wxLayoutObjectText *)*i ;
863 wxASSERT(tobj);
864 tobj->GetText().insert(offs,text);
865 break;
866 case WXLO_TYPE_LINEBREAK:
867 j = i;
868 if(offs == 0) // try to append to previous object
869 {
870 j--;
871 if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT)
872 {
873 tobj = (wxLayoutObjectText *)*j;
874 tobj->GetText()+=text;
875 }
876 else
877 insert(i,new wxLayoutObjectText(text));
878 }
879 else // cursor after linebreak
880 {
881 j++;
882 if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT)
883 {
884 tobj = (wxLayoutObjectText *)*j;
885 tobj->GetText()=text+tobj->GetText();
886 }
887 else
888 {
889 if(j == end())
890 push_back(new wxLayoutObjectText(text));
891 else
892 insert(j,new wxLayoutObjectText(text));
893 }
894 }
895 break;
896 default:
897 j = i; j--;
898 WXL_TRACE(checking previous object);
899 if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT)
900 {
901 tobj = (wxLayoutObjectText *)*j;
902 tobj->GetText()+=text;
903 }
904 else // insert a new text object
905 {
906 WXL_TRACE(creating new object);
907 Insert(new wxLayoutObjectText(text)); //FIXME not too optimal, slow
908 return; // position gets incremented in Insert(obj)
909 }
910 }
911 m_CursorPosition.x += strlen(text.c_str());
912 }
913
914 CoordType
915 wxLayoutList::GetLineLength(wxLayoutObjectList::iterator i, CoordType offs)
916 {
917 if(i == end())
918 return 0;
919
920 CoordType len = 0;
921
922 if(offs == 0 && (**i).GetType() == WXLO_TYPE_LINEBREAK)
923 // we are before a linebrak
924 return 0;
925 // search backwards for beginning of line:
926 while(i != begin() && (*i)->GetType() != WXLO_TYPE_LINEBREAK)
927 i--;
928 if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
929 i++;
930 // now we can start counting:
931 while(i != end() && (*i)->GetType() != WXLO_TYPE_LINEBREAK)
932 {
933 len += (*i)->CountPositions();
934 i++;
935 }
936 return len;
937 }
938
939 void
940 wxLayoutList::Clear(int family, int size, int style, int weight,
941 int underline, char const *fg, char const *bg)
942 {
943 wxLayoutObjectList::iterator i = begin();
944
945 while(i != end()) // == while valid
946 erase(i);
947
948 // set defaults
949 m_FontPtSize = size;
950 m_FontUnderline = false;
951 m_FontFamily = family;
952 m_FontStyle = style;
953 m_FontWeight = weight;
954 m_ColourFG = wxTheColourDatabase->FindColour(fg);
955 m_ColourBG = wxTheColourDatabase->FindColour(bg);
956
957 if(! m_ColourFG) m_ColourFG = wxBLACK;
958 if(! m_ColourBG) m_ColourBG = wxWHITE;
959
960 m_Position = wxPoint(0,0);
961 m_CursorPosition = wxPoint(0,0);
962 m_MaxLine = 0;
963 m_LineHeight = (BASELINESTRETCH*m_FontPtSize)/10;
964 m_MaxX = 0; m_MaxY = 0;
965
966
967 if(m_DefaultSetting)
968 delete m_DefaultSetting;
969 m_DefaultSetting = new
970 wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,
971 m_FontWeight,m_FontUnderline,
972 m_ColourFG, m_ColourBG);
973 }