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