]> git.saurik.com Git - wxWidgets.git/blame - src/html/htmlcell.cpp
Store HTML "id" parameter value in wxHtmlCell.
[wxWidgets.git] / src / html / htmlcell.cpp
CommitLineData
5526e819 1/////////////////////////////////////////////////////////////////////////////
93763ad5 2// Name: src/html/htmlcell.cpp
5526e819
VS
3// Purpose: wxHtmlCell - basic element of HTML output
4// Author: Vaclav Slavik
5// Copyright: (c) 1999 Vaclav Slavik
65571936 6// Licence: wxWindows licence
5526e819
VS
7/////////////////////////////////////////////////////////////////////////////
8
4dcaf11a 9#include "wx/wxprec.h"
5526e819 10
2b5f62a0 11#ifdef __BORLANDC__
93763ad5 12 #pragma hdrstop
5526e819
VS
13#endif
14
93763ad5
WS
15#if wxUSE_HTML && wxUSE_STREAMS
16
b4f4d3dd 17#ifndef WX_PRECOMP
ad9835c9 18 #include "wx/dynarray.h"
04dbb646
VZ
19 #include "wx/brush.h"
20 #include "wx/colour.h"
21 #include "wx/dc.h"
9eddec69 22 #include "wx/settings.h"
02761f6c 23 #include "wx/module.h"
193d0c93 24 #include "wx/wxcrtvararg.h"
5526e819
VS
25#endif
26
4dcaf11a
RR
27#include "wx/html/htmlcell.h"
28#include "wx/html/htmlwin.h"
77bae5e2 29
5526e819
VS
30#include <stdlib.h>
31
e3774124
VS
32//-----------------------------------------------------------------------------
33// Helper classes
34//-----------------------------------------------------------------------------
35
1338c59a
VS
36void wxHtmlSelection::Set(const wxPoint& fromPos, const wxHtmlCell *fromCell,
37 const wxPoint& toPos, const wxHtmlCell *toCell)
e3774124
VS
38{
39 m_fromCell = fromCell;
40 m_toCell = toCell;
41 m_fromPos = fromPos;
42 m_toPos = toPos;
43}
44
1338c59a 45void wxHtmlSelection::Set(const wxHtmlCell *fromCell, const wxHtmlCell *toCell)
e3774124
VS
46{
47 wxPoint p1 = fromCell ? fromCell->GetAbsPos() : wxDefaultPosition;
48 wxPoint p2 = toCell ? toCell->GetAbsPos() : wxDefaultPosition;
49 if ( toCell )
50 {
afcc5de1
VS
51 p2.x += toCell->GetWidth();
52 p2.y += toCell->GetHeight();
e3774124
VS
53 }
54 Set(p1, fromCell, p2, toCell);
55}
5526e819 56
fc7a2a60
VZ
57wxColour
58wxDefaultHtmlRenderingStyle::
59GetSelectedTextColour(const wxColour& WXUNUSED(clr))
f30e67db
VS
60{
61 return wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
62}
63
fc7a2a60
VZ
64wxColour
65wxDefaultHtmlRenderingStyle::
66GetSelectedTextBgColour(const wxColour& WXUNUSED(clr))
f30e67db
VS
67{
68 return wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
69}
70
71
5526e819
VS
72//-----------------------------------------------------------------------------
73// wxHtmlCell
74//-----------------------------------------------------------------------------
75
4f44ea36
MB
76IMPLEMENT_ABSTRACT_CLASS(wxHtmlCell, wxObject)
77
04dbb646 78wxHtmlCell::wxHtmlCell() : wxObject()
846914d1 79{
04dbb646
VZ
80 m_Next = NULL;
81 m_Parent = NULL;
82 m_Width = m_Height = m_Descent = 0;
3c115835
VS
83 m_ScriptMode = wxHTML_SCRIPT_NORMAL; // <sub> or <sup> mode
84 m_ScriptBaseline = 0; // <sub> or <sup> baseline
49f6740f 85 m_CanLiveOnPagebreak = true;
846914d1
VS
86 m_Link = NULL;
87}
88
04dbb646 89wxHtmlCell::~wxHtmlCell()
846914d1 90{
0cb9cfb2 91 delete m_Link;
846914d1
VS
92}
93
3c115835
VS
94// Update the descent value when whe are in a <sub> or <sup>.
95// prevbase is the parent base
96void wxHtmlCell::SetScriptMode(wxHtmlScriptMode mode, long previousBase)
97{
98 m_ScriptMode = mode;
99
100 if (mode == wxHTML_SCRIPT_SUP)
101 m_ScriptBaseline = previousBase - (m_Height + 1) / 2;
102 else if (mode == wxHTML_SCRIPT_SUB)
103 m_ScriptBaseline = previousBase + (m_Height + 1) / 6;
104 else
105 m_ScriptBaseline = 0;
106
107 m_Descent += m_ScriptBaseline;
108}
5526e819 109
bc55e31b
VS
110#if WXWIN_COMPATIBILITY_2_6
111
112struct wxHtmlCellOnMouseClickCompatHelper;
113
114static wxHtmlCellOnMouseClickCompatHelper *gs_helperOnMouseClick = NULL;
115
116// helper for routing calls to new ProcessMouseClick() method to deprecated
117// OnMouseClick() method
118struct wxHtmlCellOnMouseClickCompatHelper
5526e819 119{
bc55e31b
VS
120 wxHtmlCellOnMouseClickCompatHelper(wxHtmlWindowInterface *window_,
121 const wxPoint& pos_,
122 const wxMouseEvent& event_)
123 : window(window_), pos(pos_), event(event_), retval(false)
124 {
125 }
126
127 bool CallOnMouseClick(wxHtmlCell *cell)
128 {
129 wxHtmlCellOnMouseClickCompatHelper *oldHelper = gs_helperOnMouseClick;
130 gs_helperOnMouseClick = this;
131 cell->OnMouseClick
132 (
133 window ? window->GetHTMLWindow() : NULL,
134 pos.x, pos.y,
135 event
136 );
137 gs_helperOnMouseClick = oldHelper;
138 return retval;
139 }
140
141 wxHtmlWindowInterface *window;
142 const wxPoint& pos;
143 const wxMouseEvent& event;
144 bool retval;
145};
146#endif // WXWIN_COMPATIBILITY_2_6
147
148bool wxHtmlCell::ProcessMouseClick(wxHtmlWindowInterface *window,
149 const wxPoint& pos,
150 const wxMouseEvent& event)
151{
9a83f860 152 wxCHECK_MSG( window, false, wxT("window interface must be provided") );
bc55e31b
VS
153
154#if WXWIN_COMPATIBILITY_2_6
155 // NB: this hack puts the body of ProcessMouseClick() into OnMouseClick()
156 // (for which it has to pass the arguments and return value via a
157 // helper variable because these two methods have different
158 // signatures), so that old code overriding OnMouseClick will continue
159 // to work
160 wxHtmlCellOnMouseClickCompatHelper compat(window, pos, event);
161 return compat.CallOnMouseClick(this);
162}
163
164void wxHtmlCell::OnMouseClick(wxWindow *, int, int, const wxMouseEvent& event)
165{
9a83f860 166 wxCHECK_RET( gs_helperOnMouseClick, wxT("unexpected call to OnMouseClick") );
bc55e31b
VS
167 wxHtmlWindowInterface *window = gs_helperOnMouseClick->window;
168 const wxPoint& pos = gs_helperOnMouseClick->pos;
169#endif // WXWIN_COMPATIBILITY_2_6
170
171 wxHtmlLinkInfo *lnk = GetLink(pos.x, pos.y);
172 bool retval = false;
173
174 if (lnk)
0b2dadd3
VS
175 {
176 wxHtmlLinkInfo lnk2(*lnk);
177 lnk2.SetEvent(&event);
9bc8fded 178 lnk2.SetHtmlCell(this);
0cb9cfb2 179
bc55e31b
VS
180 window->OnHTMLLinkClicked(lnk2);
181 retval = true;
0b2dadd3 182 }
bc55e31b
VS
183
184#if WXWIN_COMPATIBILITY_2_6
185 gs_helperOnMouseClick->retval = retval;
186#else
187 return retval;
188#endif // WXWIN_COMPATIBILITY_2_6
5526e819
VS
189}
190
88a1b648 191#if WXWIN_COMPATIBILITY_2_6
77bae5e2
VS
192wxCursor wxHtmlCell::GetCursor() const
193{
88a1b648
VS
194 return wxNullCursor;
195}
196#endif // WXWIN_COMPATIBILITY_2_6
197
e24c4e12
VZ
198wxCursor
199wxHtmlCell::GetMouseCursor(wxHtmlWindowInterface* WXUNUSED(window)) const
200{
201 // This is never called directly, only from GetMouseCursorAt() and we
202 // return an invalid cursor by default to let it delegate to the window.
203 return wxNullCursor;
204}
205
206wxCursor
207wxHtmlCell::GetMouseCursorAt(wxHtmlWindowInterface *window,
208 const wxPoint& relPos) const
88a1b648
VS
209{
210#if WXWIN_COMPATIBILITY_2_6
211 // NB: Older versions of wx used GetCursor() virtual method in place of
212 // GetMouseCursor(interface). This code ensures that user code that
4c51a665 213 // overridden GetCursor() continues to work. The trick is that the base
88a1b648 214 // wxHtmlCell::GetCursor() method simply returns wxNullCursor, so we
4c51a665 215 // know that GetCursor() was overridden iff it returns valid cursor.
88a1b648 216 wxCursor cur = GetCursor();
a1b806b9 217 if (cur.IsOk())
88a1b648
VS
218 return cur;
219#endif // WXWIN_COMPATIBILITY_2_6
220
e24c4e12
VZ
221 const wxCursor curCell = GetMouseCursor(window);
222 if ( curCell.IsOk() )
223 return curCell;
224
225 if ( GetLink(relPos.x, relPos.y) )
77bae5e2 226 {
88a1b648 227 return window->GetHTMLCursor(wxHtmlWindowInterface::HTMLCursor_Link);
77bae5e2
VS
228 }
229 else
88a1b648
VS
230 {
231 return window->GetHTMLCursor(wxHtmlWindowInterface::HTMLCursor_Default);
232 }
77bae5e2
VS
233}
234
5526e819 235
846f4568
VZ
236bool
237wxHtmlCell::AdjustPagebreak(int *pagebreak,
238 const wxArrayInt& WXUNUSED(known_pagebreaks),
239 int pageHeight) const
240{
241 // Notice that we always break the cells bigger than the page height here
242 // as otherwise we wouldn't be able to break them at all.
243 if ( m_Height <= pageHeight &&
244 (!m_CanLiveOnPagebreak &&
245 m_PosY < *pagebreak && m_PosY + m_Height > *pagebreak) )
0cb9cfb2 246 {
db98870d 247 *pagebreak = m_PosY;
49f6740f 248 return true;
db98870d 249 }
0cb9cfb2 250
49f6740f 251 return false;
db98870d
VS
252}
253
254
255
04dbb646 256void wxHtmlCell::SetLink(const wxHtmlLinkInfo& link)
846914d1 257{
5276b0a5 258 wxDELETE(m_Link);
af1ed0c1
VS
259 if (link.GetHref() != wxEmptyString)
260 m_Link = new wxHtmlLinkInfo(link);
846914d1
VS
261}
262
263
d699f48b 264void wxHtmlCell::Layout(int WXUNUSED(w))
721ab905 265{
04dbb646 266 SetPos(0, 0);
721ab905
VS
267}
268
269
79d6c018 270
d699f48b 271const wxHtmlCell* wxHtmlCell::Find(int WXUNUSED(condition), const void* WXUNUSED(param)) const
721ab905 272{
bf7d7ee7 273 return NULL;
721ab905
VS
274}
275
276
36c4ff4d
VS
277wxHtmlCell *wxHtmlCell::FindCellByPos(wxCoord x, wxCoord y,
278 unsigned flags) const
f6010d8f 279{
adf2eb2d 280 if ( x >= 0 && x < m_Width && y >= 0 && y < m_Height )
36c4ff4d 281 {
f6010d8f 282 return wxConstCast(this, wxHtmlCell);
36c4ff4d 283 }
adf2eb2d
VS
284 else
285 {
286 if ((flags & wxHTML_FIND_NEAREST_AFTER) &&
03693319 287 (y < 0 || (y < 0+m_Height && x < 0+m_Width)))
adf2eb2d
VS
288 return wxConstCast(this, wxHtmlCell);
289 else if ((flags & wxHTML_FIND_NEAREST_BEFORE) &&
03693319 290 (y >= 0+m_Height || (y >= 0 && x >= 0)))
adf2eb2d
VS
291 return wxConstCast(this, wxHtmlCell);
292 else
293 return NULL;
294 }
295}
296
297
bc55e31b 298wxPoint wxHtmlCell::GetAbsPos(wxHtmlCell *rootCell) const
adf2eb2d
VS
299{
300 wxPoint p(m_PosX, m_PosY);
bc55e31b
VS
301 for (wxHtmlCell *parent = m_Parent; parent && parent != rootCell;
302 parent = parent->m_Parent)
adf2eb2d
VS
303 {
304 p.x += parent->m_PosX;
305 p.y += parent->m_PosY;
306 }
307 return p;
f6010d8f 308}
86ff9b45 309
bc55e31b
VS
310wxHtmlCell *wxHtmlCell::GetRootCell() const
311{
312 wxHtmlCell *c = wxConstCast(this, wxHtmlCell);
313 while ( c->m_Parent )
314 c = c->m_Parent;
315 return c;
316}
317
e3774124
VS
318unsigned wxHtmlCell::GetDepth() const
319{
320 unsigned d = 0;
321 for (wxHtmlCell *p = m_Parent; p; p = p->m_Parent)
322 d++;
323 return d;
324}
86ff9b45 325
e3774124
VS
326bool wxHtmlCell::IsBefore(wxHtmlCell *cell) const
327{
328 const wxHtmlCell *c1 = this;
329 const wxHtmlCell *c2 = cell;
330 unsigned d1 = GetDepth();
331 unsigned d2 = cell->GetDepth();
332
333 if ( d1 > d2 )
334 for (; d1 != d2; d1-- )
335 c1 = c1->m_Parent;
336 else if ( d1 < d2 )
337 for (; d1 != d2; d2-- )
338 c2 = c2->m_Parent;
339
340 if ( cell == this )
341 return true;
342
343 while ( c1 && c2 )
344 {
345 if ( c1->m_Parent == c2->m_Parent )
346 {
347 while ( c1 )
348 {
349 if ( c1 == c2 )
350 return true;
351 c1 = c1->GetNext();
86ff9b45 352 }
e3774124
VS
353 return false;
354 }
355 else
356 {
357 c1 = c1->m_Parent;
358 c2 = c2->m_Parent;
359 }
360 }
361
9a83f860 362 wxFAIL_MSG(wxT("Cells are in different trees"));
e3774124
VS
363 return false;
364}
f6010d8f 365
721ab905 366
5526e819
VS
367//-----------------------------------------------------------------------------
368// wxHtmlWordCell
369//-----------------------------------------------------------------------------
370
4f44ea36
MB
371IMPLEMENT_ABSTRACT_CLASS(wxHtmlWordCell, wxHtmlCell)
372
fbfb8bcc 373wxHtmlWordCell::wxHtmlWordCell(const wxString& word, const wxDC& dc) : wxHtmlCell()
5526e819
VS
374{
375 m_Word = word;
091e74e7
RR
376 wxCoord w, h, d;
377 dc.GetTextExtent(m_Word, &w, &h, &d);
378 m_Width = w;
379 m_Height = h;
380 m_Descent = d;
49f6740f 381 SetCanLiveOnPagebreak(false);
b6d93b26 382 m_allowLinebreak = true;
5526e819
VS
383}
384
b6d93b26
VS
385void wxHtmlWordCell::SetPreviousWord(wxHtmlWordCell *cell)
386{
387 if ( cell && m_Parent == cell->m_Parent &&
388 !wxIsspace(cell->m_Word.Last()) && !wxIsspace(m_Word[0u]) )
389 {
390 m_allowLinebreak = false;
391 }
392}
5526e819 393
5a1597e9
VS
394// Splits m_Word into up to three parts according to selection, returns
395// substring before, in and after selection and the points (in relative coords)
396// where s2 and s3 start:
fbfb8bcc 397void wxHtmlWordCell::Split(const wxDC& dc,
5a1597e9 398 const wxPoint& selFrom, const wxPoint& selTo,
f30e67db 399 unsigned& pos1, unsigned& pos2) const
5a1597e9
VS
400{
401 wxPoint pt1 = (selFrom == wxDefaultPosition) ?
402 wxDefaultPosition : selFrom - GetAbsPos();
403 wxPoint pt2 = (selTo == wxDefaultPosition) ?
422d0ff0 404 wxPoint(m_Width, wxDefaultCoord) : selTo - GetAbsPos();
5a1597e9 405
117f4046
VS
406 // if the selection is entirely within this cell, make sure pt1 < pt2 in
407 // order to make the rest of this function simpler:
408 if ( selFrom != wxDefaultPosition && selTo != wxDefaultPosition &&
409 selFrom.x > selTo.x )
410 {
411 wxPoint tmp = pt1;
412 pt1 = pt2;
413 pt2 = tmp;
414 }
415
5a1597e9
VS
416 unsigned len = m_Word.length();
417 unsigned i = 0;
418 pos1 = 0;
5a1597e9 419
03693319
VS
420 // adjust for cases when the start/end position is completely
421 // outside the cell:
422 if ( pt1.y < 0 )
423 pt1.x = 0;
424 if ( pt2.y >= m_Height )
425 pt2.x = m_Width;
95af070a
VZ
426
427 // before selection:
8eb3a3a9 428 // (include character under caret only if in first half of width)
95af070a 429#ifdef __WXMAC__
89e94a4b
SC
430 // implementation using PartialExtents to support fractional widths
431 wxArrayInt widths ;
432 dc.GetPartialTextExtents(m_Word,widths) ;
89e94a4b
SC
433 while( i < len && pt1.x >= widths[i] )
434 i++ ;
8eb3a3a9
VS
435 if ( i < len )
436 {
437 int charW = (i > 0) ? widths[i] - widths[i-1] : widths[i];
438 if ( widths[i] - pt1.x < charW/2 )
439 i++;
440 }
441#else // !__WXMAC__
95af070a 442 wxCoord charW, charH;
5a1597e9
VS
443 while ( pt1.x > 0 && i < len )
444 {
445 dc.GetTextExtent(m_Word[i], &charW, &charH);
446 pt1.x -= charW;
8eb3a3a9 447 if ( pt1.x >= -charW/2 )
5a1597e9
VS
448 {
449 pos1 += charW;
450 i++;
451 }
452 }
95af070a 453#endif // __WXMAC__/!__WXMAC__
5526e819 454
5a1597e9 455 // in selection:
8eb3a3a9 456 // (include character under caret only if in first half of width)
5a1597e9 457 unsigned j = i;
95af070a 458#ifdef __WXMAC__
89e94a4b
SC
459 while( j < len && pt2.x >= widths[j] )
460 j++ ;
8eb3a3a9
VS
461 if ( j < len )
462 {
463 int charW = (j > 0) ? widths[j] - widths[j-1] : widths[j];
464 if ( widths[j] - pt2.x < charW/2 )
465 j++;
466 }
467#else // !__WXMAC__
5a1597e9 468 pos2 = pos1;
f30e67db 469 pt2.x -= pos2;
5a1597e9
VS
470 while ( pt2.x > 0 && j < len )
471 {
472 dc.GetTextExtent(m_Word[j], &charW, &charH);
473 pt2.x -= charW;
8eb3a3a9 474 if ( pt2.x >= -charW/2 )
5a1597e9
VS
475 {
476 pos2 += charW;
477 j++;
478 }
479 }
95af070a 480#endif // __WXMAC__/!__WXMAC__
f30e67db
VS
481
482 pos1 = i;
483 pos2 = j;
6a603a10
VS
484
485 wxASSERT( pos2 >= pos1 );
f30e67db
VS
486}
487
fbfb8bcc 488void wxHtmlWordCell::SetSelectionPrivPos(const wxDC& dc, wxHtmlSelection *s) const
f30e67db
VS
489{
490 unsigned p1, p2;
86ff9b45
VZ
491
492 Split(dc,
f30e67db
VS
493 this == s->GetFromCell() ? s->GetFromPos() : wxDefaultPosition,
494 this == s->GetToCell() ? s->GetToPos() : wxDefaultPosition,
495 p1, p2);
496
f30e67db 497 if ( this == s->GetFromCell() )
2f0bebe6 498 s->SetFromCharacterPos (p1); // selection starts here
f30e67db 499 if ( this == s->GetToCell() )
2f0bebe6 500 s->SetToCharacterPos (p2); // selection ends here
5a1597e9
VS
501}
502
503
f30e67db 504static void SwitchSelState(wxDC& dc, wxHtmlRenderingInfo& info,
5a1597e9 505 bool toSelection)
5526e819 506{
f30e67db
VS
507 wxColour fg = info.GetState().GetFgColour();
508 wxColour bg = info.GetState().GetBgColour();
86ff9b45 509
5a1597e9 510 if ( toSelection )
36c4ff4d 511 {
3ee9771b 512 dc.SetBackgroundMode(wxSOLID);
f30e67db
VS
513 dc.SetTextForeground(info.GetStyle().GetSelectedTextColour(fg));
514 dc.SetTextBackground(info.GetStyle().GetSelectedTextBgColour(bg));
b87dd6f5 515 dc.SetBackground(wxBrush(info.GetStyle().GetSelectedTextBgColour(bg),
04ee05f9 516 wxBRUSHSTYLE_SOLID));
36c4ff4d 517 }
5a1597e9 518 else
36c4ff4d 519 {
f5413b87
VZ
520 const int mode = info.GetState().GetBgMode();
521 dc.SetBackgroundMode(mode);
f30e67db
VS
522 dc.SetTextForeground(fg);
523 dc.SetTextBackground(bg);
f5413b87
VZ
524 if ( mode != wxTRANSPARENT )
525 dc.SetBackground(wxBrush(bg, mode));
36c4ff4d 526 }
5a1597e9 527}
36c4ff4d 528
5a1597e9
VS
529
530void wxHtmlWordCell::Draw(wxDC& dc, int x, int y,
2a2e4f4a 531 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
f30e67db 532 wxHtmlRenderingInfo& info)
5a1597e9
VS
533{
534#if 0 // useful for debugging
ace0fab4 535 dc.SetPen(*wxBLACK_PEN);
4dd9ae57 536 dc.DrawRectangle(x+m_PosX,y+m_PosY,m_Width /* VZ: +1? */ ,m_Height);
5a1597e9
VS
537#endif
538
b87dd6f5 539 bool drawSelectionAfterCell = false;
d1da8872 540
f30e67db 541 if ( info.GetState().GetSelectionState() == wxHTML_SEL_CHANGING )
5a1597e9
VS
542 {
543 // Selection changing, we must draw the word piecewise:
f30e67db
VS
544 wxHtmlSelection *s = info.GetSelection();
545 wxString txt;
546 int w, h;
547 int ofs = 0;
86ff9b45 548
1338c59a
VS
549 // NB: this is quite a hack: in order to compute selection boundaries
550 // (in word's characters) we must know current font, which is only
551 // possible inside rendering code. Therefore we update the
552 // information here and store it in wxHtmlSelection so that
553 // ConvertToText can use it later:
2f0bebe6 554 if ( !s->AreFromToCharacterPosSet () )
1338c59a
VS
555 {
556 SetSelectionPrivPos(dc, s);
1338c59a 557 }
86ff9b45 558
2f0bebe6
VZ
559 int part1 = s->GetFromCell()==this ? s->GetFromCharacterPos() : 0;
560 int part2 = s->GetToCell()==this ? s->GetToCharacterPos() : m_Word.Length();
f30e67db
VS
561
562 if ( part1 > 0 )
5a1597e9 563 {
f30e67db
VS
564 txt = m_Word.Mid(0, part1);
565 dc.DrawText(txt, x + m_PosX, y + m_PosY);
566 dc.GetTextExtent(txt, &w, &h);
567 ofs += w;
5a1597e9 568 }
86ff9b45 569
f30e67db 570 SwitchSelState(dc, info, true);
86ff9b45 571
f30e67db
VS
572 txt = m_Word.Mid(part1, part2-part1);
573 dc.DrawText(txt, ofs + x + m_PosX, y + m_PosY);
574
70bae016 575 if ( (size_t)part2 < m_Word.length() )
5a1597e9 576 {
f30e67db
VS
577 dc.GetTextExtent(txt, &w, &h);
578 ofs += w;
579 SwitchSelState(dc, info, false);
580 txt = m_Word.Mid(part2);
581 dc.DrawText(txt, ofs + x + m_PosX, y + m_PosY);
5a1597e9 582 }
b87dd6f5
VS
583 else
584 drawSelectionAfterCell = true;
5a1597e9
VS
585 }
586 else
587 {
b87dd6f5 588 wxHtmlSelectionState selstate = info.GetState().GetSelectionState();
5a1597e9 589 // Not changing selection state, draw the word in single mode:
f5413b87 590 SwitchSelState(dc, info, selstate != wxHTML_SEL_OUT);
5a1597e9 591 dc.DrawText(m_Word, x + m_PosX, y + m_PosY);
b87dd6f5
VS
592 drawSelectionAfterCell = (selstate != wxHTML_SEL_OUT);
593 }
594
595 // NB: If the text is justified then there is usually some free space
596 // between adjacent cells and drawing the selection only onto cells
597 // would result in ugly unselected spaces. The code below detects
598 // this special case and renders the selection *outside* the sell,
599 // too.
600 if ( m_Parent->GetAlignHor() == wxHTML_ALIGN_JUSTIFY &&
601 drawSelectionAfterCell )
602 {
603 wxHtmlCell *nextCell = m_Next;
604 while ( nextCell && nextCell->IsFormattingCell() )
605 nextCell = nextCell->GetNext();
606 if ( nextCell )
607 {
608 int nextX = nextCell->GetPosX();
609 if ( m_PosX + m_Width < nextX )
610 {
611 dc.SetBrush(dc.GetBackground());
612 dc.SetPen(*wxTRANSPARENT_PEN);
613 dc.DrawRectangle(x + m_PosX + m_Width, y + m_PosY,
614 nextX - m_PosX - m_Width, m_Height);
615 }
616 }
5a1597e9 617 }
5526e819 618}
86ff9b45 619
6a603a10
VS
620wxCursor wxHtmlWordCell::GetMouseCursor(wxHtmlWindowInterface *window) const
621{
622 if ( !GetLink() )
623 {
624 return window->GetHTMLCursor(wxHtmlWindowInterface::HTMLCursor_Text);
625 }
626 else
627 {
628 return wxHtmlCell::GetMouseCursor(window);
629 }
630}
e3774124 631
f30e67db 632wxString wxHtmlWordCell::ConvertToText(wxHtmlSelection *s) const
e3774124 633{
f30e67db
VS
634 if ( s && (this == s->GetFromCell() || this == s->GetToCell()) )
635 {
86ff9b45
VZ
636 // VZ: we may be called before we had a chance to re-render ourselves
637 // and in this case GetFrom/ToPrivPos() is not set yet -- assume
638 // that this only happens in case of a double/triple click (which
639 // seems to be the case now) and so it makes sense to select the
640 // entire contents of the cell in this case
641 //
642 // TODO: but this really needs to be fixed in some better way later...
2f0bebe6 643 if ( s->AreFromToCharacterPosSet() )
86ff9b45 644 {
2f0bebe6
VZ
645 const int part1 = s->GetFromCell()==this ? s->GetFromCharacterPos() : 0;
646 const int part2 = s->GetToCell()==this ? s->GetToCharacterPos() : m_Word.Length();
6a603a10
VS
647 if ( part1 == part2 )
648 return wxEmptyString;
649 return GetPartAsText(part1, part2);
86ff9b45
VZ
650 }
651 //else: return the whole word below
f30e67db 652 }
86ff9b45 653
6a603a10 654 return GetAllAsText();
e3774124 655}
5526e819 656
6a603a10 657wxString wxHtmlWordWithTabsCell::GetAllAsText() const
77bae5e2 658{
6a603a10
VS
659 return m_wordOrig;
660}
661
662wxString wxHtmlWordWithTabsCell::GetPartAsText(int begin, int end) const
663{
664 // NB: The 'begin' and 'end' positions are in the _displayed_ text
665 // (stored in m_Word) and not in the text with tabs that should
666 // be copied to clipboard (m_wordOrig).
667 //
668 // NB: Because selection is performed on displayed text, it's possible
669 // to select e.g. "half of TAB character" -- IOW, 'begin' and 'end'
670 // may be in the middle of TAB character expansion into ' 's. In this
671 // case, we copy the TAB character to clipboard once.
672
673 wxASSERT( begin < end );
674
675 const unsigned SPACES_PER_TAB = 8;
676
677 wxString sel;
678
679 int pos = 0;
680 wxString::const_iterator i = m_wordOrig.begin();
681
682 // find the beginning of text to copy:
683 for ( ; pos < begin; ++i )
77bae5e2 684 {
6a603a10
VS
685 if ( *i == '\t' )
686 {
687 pos += 8 - (m_linepos + pos) % SPACES_PER_TAB;
688 if ( pos >= begin )
689 {
690 sel += '\t';
691 }
692 }
693 else
694 {
695 ++pos;
696 }
77bae5e2 697 }
6a603a10
VS
698
699 // copy the content until we reach 'end':
700 for ( ; pos < end; ++i )
88a1b648 701 {
6a603a10
VS
702 const wxChar c = *i;
703 sel += c;
704
705 if ( c == '\t' )
706 pos += 8 - (m_linepos + pos) % SPACES_PER_TAB;
707 else
708 ++pos;
88a1b648 709 }
6a603a10
VS
710
711 return sel;
77bae5e2
VS
712}
713
5526e819 714
6a603a10 715
5526e819
VS
716//-----------------------------------------------------------------------------
717// wxHtmlContainerCell
718//-----------------------------------------------------------------------------
719
4f44ea36 720IMPLEMENT_ABSTRACT_CLASS(wxHtmlContainerCell, wxHtmlCell)
5526e819
VS
721
722wxHtmlContainerCell::wxHtmlContainerCell(wxHtmlContainerCell *parent) : wxHtmlCell()
723{
724 m_Cells = m_LastCell = NULL;
725 m_Parent = parent;
ca16b7a9 726 m_MaxTotalWidth = 0;
4f9297b0 727 if (m_Parent) m_Parent->InsertCell(this);
efba2b89
VS
728 m_AlignHor = wxHTML_ALIGN_LEFT;
729 m_AlignVer = wxHTML_ALIGN_BOTTOM;
5526e819 730 m_IndentLeft = m_IndentRight = m_IndentTop = m_IndentBottom = 0;
efba2b89 731 m_WidthFloat = 100; m_WidthFloatUnits = wxHTML_UNITS_PERCENT;
88343dda 732 m_BkColour = wxNullColour;
3aaaf1aa 733 m_Border = 0;
5c1bfc5d 734 m_MinHeight = 0;
efba2b89 735 m_MinHeightAlign = wxHTML_ALIGN_TOP;
5660c520 736 m_LastLayout = -1;
5526e819
VS
737}
738
04dbb646 739wxHtmlContainerCell::~wxHtmlContainerCell()
721ab905 740{
491c9920
VZ
741 wxHtmlCell *cell = m_Cells;
742 while ( cell )
bf7d7ee7 743 {
491c9920
VZ
744 wxHtmlCell *cellNext = cell->GetNext();
745 delete cell;
746 cell = cellNext;
bf7d7ee7 747 }
721ab905
VS
748}
749
5526e819
VS
750
751
752void wxHtmlContainerCell::SetIndent(int i, int what, int units)
753{
efba2b89
VS
754 int val = (units == wxHTML_UNITS_PIXELS) ? i : -i;
755 if (what & wxHTML_INDENT_LEFT) m_IndentLeft = val;
756 if (what & wxHTML_INDENT_RIGHT) m_IndentRight = val;
757 if (what & wxHTML_INDENT_TOP) m_IndentTop = val;
758 if (what & wxHTML_INDENT_BOTTOM) m_IndentBottom = val;
5660c520 759 m_LastLayout = -1;
5526e819
VS
760}
761
762
763
764int wxHtmlContainerCell::GetIndent(int ind) const
765{
efba2b89
VS
766 if (ind & wxHTML_INDENT_LEFT) return m_IndentLeft;
767 else if (ind & wxHTML_INDENT_RIGHT) return m_IndentRight;
768 else if (ind & wxHTML_INDENT_TOP) return m_IndentTop;
769 else if (ind & wxHTML_INDENT_BOTTOM) return m_IndentBottom;
5526e819
VS
770 else return -1; /* BUG! Should not be called... */
771}
772
773
774
775
776int wxHtmlContainerCell::GetIndentUnits(int ind) const
777{
49f6740f 778 bool p = false;
efba2b89
VS
779 if (ind & wxHTML_INDENT_LEFT) p = m_IndentLeft < 0;
780 else if (ind & wxHTML_INDENT_RIGHT) p = m_IndentRight < 0;
781 else if (ind & wxHTML_INDENT_TOP) p = m_IndentTop < 0;
782 else if (ind & wxHTML_INDENT_BOTTOM) p = m_IndentBottom < 0;
783 if (p) return wxHTML_UNITS_PERCENT;
784 else return wxHTML_UNITS_PIXELS;
5526e819
VS
785}
786
787
846f4568
VZ
788bool
789wxHtmlContainerCell::AdjustPagebreak(int *pagebreak,
790 const wxArrayInt& known_pagebreaks,
791 int pageHeight) const
db98870d 792{
04dbb646 793 if (!m_CanLiveOnPagebreak)
846f4568 794 return wxHtmlCell::AdjustPagebreak(pagebreak, known_pagebreaks, pageHeight);
e52d6dbc 795
fd0bab43
VZ
796 wxHtmlCell *c = GetFirstChild();
797 bool rt = false;
798 int pbrk = *pagebreak - m_PosY;
db98870d 799
fd0bab43
VZ
800 while (c)
801 {
846f4568 802 if (c->AdjustPagebreak(&pbrk, known_pagebreaks, pageHeight))
fd0bab43
VZ
803 rt = true;
804 c = c->GetNext();
db98870d 805 }
fd0bab43
VZ
806 if (rt)
807 *pagebreak = pbrk + m_PosY;
808 return rt;
db98870d
VS
809}
810
811
5526e819
VS
812void wxHtmlContainerCell::Layout(int w)
813{
026d1fac
VS
814 wxHtmlCell::Layout(w);
815
5540b06b
VS
816 if (m_LastLayout == w)
817 return;
818 m_LastLayout = w;
0cb9cfb2 819
026d1fac
VS
820 // VS: Any attempt to layout with negative or zero width leads to hell,
821 // but we can't ignore such attempts completely, since it sometimes
822 // happen (e.g. when trying how small a table can be). The best thing we
823 // can do is to set the width of child cells to zero
0cb9cfb2 824 if (w < 1)
4f9297b0 825 {
026d1fac
VS
826 m_Width = 0;
827 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
828 cell->Layout(0);
2b5f62a0
VZ
829 // this does two things: it recursively calls this code on all
830 // child contrainers and resets children's position to (0,0)
026d1fac 831 return;
04dbb646 832 }
5660c520 833
b6d93b26 834 wxHtmlCell *nextCell;
5526e819
VS
835 long xpos = 0, ypos = m_IndentTop;
836 int xdelta = 0, ybasicpos = 0, ydiff;
b6d93b26 837 int s_width, nextWordWidth, s_indent;
5526e819 838 int ysizeup = 0, ysizedown = 0;
5c1bfc5d 839 int MaxLineWidth = 0;
ca16b7a9
VS
840 int curLineWidth = 0;
841 m_MaxTotalWidth = 0;
5c1bfc5d 842
5526e819
VS
843
844 /*
7e941458 845
5526e819 846 WIDTH ADJUSTING :
7e941458 847
5526e819
VS
848 */
849
04dbb646 850 if (m_WidthFloatUnits == wxHTML_UNITS_PERCENT)
4f9297b0 851 {
5526e819
VS
852 if (m_WidthFloat < 0) m_Width = (100 + m_WidthFloat) * w / 100;
853 else m_Width = m_WidthFloat * w / 100;
854 }
04dbb646 855 else
4f9297b0 856 {
5526e819
VS
857 if (m_WidthFloat < 0) m_Width = w + m_WidthFloat;
858 else m_Width = m_WidthFloat;
859 }
860
04dbb646 861 if (m_Cells)
4f9297b0 862 {
5526e819
VS
863 int l = (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft;
864 int r = (m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight;
bf7d7ee7
VS
865 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
866 cell->Layout(m_Width - (l + r));
5526e819
VS
867 }
868
869 /*
870
d13b34d3 871 LAYOUT :
7e941458 872
5526e819
VS
873 */
874
875 // adjust indentation:
876 s_indent = (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft;
877 s_width = m_Width - s_indent - ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
878
d13b34d3 879 // my own layout:
17a1ebd1
VZ
880 wxHtmlCell *cell = m_Cells,
881 *line = m_Cells;
04dbb646 882 while (cell != NULL)
4f9297b0 883 {
04dbb646 884 switch (m_AlignVer)
0cb9cfb2 885 {
efba2b89 886 case wxHTML_ALIGN_TOP : ybasicpos = 0; break;
4f9297b0
VS
887 case wxHTML_ALIGN_BOTTOM : ybasicpos = - cell->GetHeight(); break;
888 case wxHTML_ALIGN_CENTER : ybasicpos = - cell->GetHeight() / 2; break;
5526e819 889 }
4f9297b0 890 ydiff = cell->GetHeight() + ybasicpos;
5526e819 891
4f9297b0
VS
892 if (cell->GetDescent() + ydiff > ysizedown) ysizedown = cell->GetDescent() + ydiff;
893 if (ybasicpos + cell->GetDescent() < -ysizeup) ysizeup = - (ybasicpos + cell->GetDescent());
5526e819 894
b6d93b26 895 // layout nonbreakable run of cells:
4f9297b0
VS
896 cell->SetPos(xpos, ybasicpos + cell->GetDescent());
897 xpos += cell->GetWidth();
ca16b7a9
VS
898 if (!cell->IsTerminalCell())
899 {
900 // Container cell indicates new line
901 if (curLineWidth > m_MaxTotalWidth)
902 m_MaxTotalWidth = curLineWidth;
903
904 if (wxMax(cell->GetWidth(), cell->GetMaxTotalWidth()) > m_MaxTotalWidth)
905 m_MaxTotalWidth = cell->GetMaxTotalWidth();
906 curLineWidth = 0;
907 }
908 else
909 // Normal cell, add maximum cell width to line width
910 curLineWidth += cell->GetMaxTotalWidth();
911
4f9297b0 912 cell = cell->GetNext();
d1da8872 913
b6d93b26
VS
914 // compute length of the next word that would be added:
915 nextWordWidth = 0;
916 if (cell)
917 {
918 nextCell = cell;
919 do
920 {
921 nextWordWidth += nextCell->GetWidth();
922 nextCell = nextCell->GetNext();
923 } while (nextCell && !nextCell->IsLinebreakAllowed());
924 }
d1da8872 925
3103e8a9 926 // force new line if occurred:
d1da8872 927 if ((cell == NULL) ||
b6d93b26 928 (xpos + nextWordWidth > s_width && cell->IsLinebreakAllowed()))
0cb9cfb2 929 {
5c1bfc5d 930 if (xpos > MaxLineWidth) MaxLineWidth = xpos;
5526e819
VS
931 if (ysizeup < 0) ysizeup = 0;
932 if (ysizedown < 0) ysizedown = 0;
933 switch (m_AlignHor) {
04dbb646
VZ
934 case wxHTML_ALIGN_LEFT :
935 case wxHTML_ALIGN_JUSTIFY :
936 xdelta = 0;
5c1bfc5d 937 break;
04dbb646
VZ
938 case wxHTML_ALIGN_RIGHT :
939 xdelta = 0 + (s_width - xpos);
5c1bfc5d 940 break;
04dbb646
VZ
941 case wxHTML_ALIGN_CENTER :
942 xdelta = 0 + (s_width - xpos) / 2;
5c1bfc5d 943 break;
5526e819
VS
944 }
945 if (xdelta < 0) xdelta = 0;
946 xdelta += s_indent;
947
948 ypos += ysizeup;
04dbb646 949
5c1bfc5d 950 if (m_AlignHor != wxHTML_ALIGN_JUSTIFY || cell == NULL)
a1ae1090 951 {
04dbb646 952 while (line != cell)
0cb9cfb2 953 {
04dbb646 954 line->SetPos(line->GetPosX() + xdelta,
4f9297b0
VS
955 ypos + line->GetPosY());
956 line = line->GetNext();
5c1bfc5d 957 }
a1ae1090
VZ
958 }
959 else // align == justify
04dbb646 960 {
a1ae1090
VZ
961 // we have to distribute the extra horz space between the cells
962 // on this line
963
964 // an added complication is that some cells have fixed size and
965 // shouldn't get any increment (it so happens that these cells
966 // also don't allow line break on them which provides with an
4dd9ae57
VZ
967 // easy way to test for this) -- and neither should the cells
968 // adjacent to them as this could result in a visible space
969 // between two cells separated by, e.g. font change, cell which
970 // is wrong
a1ae1090 971
2d1d813e 972 int step = s_width - xpos;
a1ae1090 973 if ( step > 0 )
0cb9cfb2 974 {
a1ae1090 975 // first count the cells which will get extra space
9076e56d 976 int total = -1;
4dd9ae57 977
1c0ee565
VS
978 const wxHtmlCell *c;
979 if ( line != cell )
a1ae1090 980 {
9076e56d 981 for ( c = line; c != cell; c = c->GetNext() )
4dd9ae57 982 {
1c0ee565
VS
983 if ( c->IsLinebreakAllowed() )
984 {
985 total++;
986 }
4dd9ae57 987 }
a1ae1090
VZ
988 }
989
990 // and now extra space to those cells which merit it
991 if ( total )
992 {
9076e56d
VZ
993 // first visible cell on line is not moved:
994 while (line !=cell && !line->IsLinebreakAllowed())
995 {
996 line->SetPos(line->GetPosX() + s_indent,
997 line->GetPosY() + ypos);
998 line = line->GetNext();
999 }
1000
1001 if (line != cell)
1002 {
1003 line->SetPos(line->GetPosX() + s_indent,
1004 line->GetPosY() + ypos);
1005
1006 line = line->GetNext();
1007 }
d1da8872 1008
1c0ee565 1009 for ( int n = 0; line != cell; line = line->GetNext() )
a1ae1090 1010 {
1c0ee565 1011 if ( line->IsLinebreakAllowed() )
a1ae1090
VZ
1012 {
1013 // offset the next cell relative to this one
1014 // thus increasing our size
1015 n++;
1016 }
d1da8872 1017
1c0ee565
VS
1018 line->SetPos(line->GetPosX() + s_indent +
1019 ((n * step) / total),
1020 line->GetPosY() + ypos);
a1ae1090
VZ
1021 }
1022 }
2d1d813e
VS
1023 else
1024 {
1025 // this will cause the code to enter "else branch" below:
1026 step = 0;
1027 }
a1ae1090 1028 }
2d1d813e
VS
1029 // else branch:
1030 if ( step <= 0 ) // no extra space to distribute
a1ae1090
VZ
1031 {
1032 // just set the indent properly
1033 while (line != cell)
1034 {
1035 line->SetPos(line->GetPosX() + s_indent,
1036 line->GetPosY() + ypos);
1037 line = line->GetNext();
1038 }
5c1bfc5d 1039 }
5526e819
VS
1040 }
1041
1042 ypos += ysizedown;
49f6740f 1043 xpos = 0;
5526e819
VS
1044 ysizeup = ysizedown = 0;
1045 line = cell;
1046 }
1047 }
1048
1049 // setup height & width, depending on container layout:
1050 m_Height = ypos + (ysizedown + ysizeup) + m_IndentBottom;
1051
04dbb646 1052 if (m_Height < m_MinHeight)
4f9297b0 1053 {
04dbb646 1054 if (m_MinHeightAlign != wxHTML_ALIGN_TOP)
0cb9cfb2 1055 {
5526e819 1056 int diff = m_MinHeight - m_Height;
efba2b89 1057 if (m_MinHeightAlign == wxHTML_ALIGN_CENTER) diff /= 2;
5526e819 1058 cell = m_Cells;
04dbb646 1059 while (cell)
0cb9cfb2 1060 {
4f9297b0
VS
1061 cell->SetPos(cell->GetPosX(), cell->GetPosY() + diff);
1062 cell = cell->GetNext();
5526e819
VS
1063 }
1064 }
1065 m_Height = m_MinHeight;
1066 }
1067
ca16b7a9
VS
1068 if (curLineWidth > m_MaxTotalWidth)
1069 m_MaxTotalWidth = curLineWidth;
d1da8872 1070
ca16b7a9 1071 m_MaxTotalWidth += s_indent + ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
5c1bfc5d
VS
1072 MaxLineWidth += s_indent + ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
1073 if (m_Width < MaxLineWidth) m_Width = MaxLineWidth;
5526e819
VS
1074}
1075
f30e67db 1076void wxHtmlContainerCell::UpdateRenderingStatePre(wxHtmlRenderingInfo& info,
36c4ff4d
VS
1077 wxHtmlCell *cell) const
1078{
f30e67db 1079 wxHtmlSelection *s = info.GetSelection();
36c4ff4d 1080 if (!s) return;
cd275246 1081 if (s->GetFromCell() == cell || s->GetToCell() == cell)
36c4ff4d 1082 {
f30e67db 1083 info.GetState().SetSelectionState(wxHTML_SEL_CHANGING);
36c4ff4d
VS
1084 }
1085}
1086
f30e67db 1087void wxHtmlContainerCell::UpdateRenderingStatePost(wxHtmlRenderingInfo& info,
36c4ff4d
VS
1088 wxHtmlCell *cell) const
1089{
f30e67db 1090 wxHtmlSelection *s = info.GetSelection();
36c4ff4d 1091 if (!s) return;
adf2eb2d 1092 if (s->GetToCell() == cell)
f30e67db 1093 info.GetState().SetSelectionState(wxHTML_SEL_OUT);
adf2eb2d 1094 else if (s->GetFromCell() == cell)
f30e67db 1095 info.GetState().SetSelectionState(wxHTML_SEL_IN);
36c4ff4d 1096}
5526e819
VS
1097
1098#define mMin(a, b) (((a) < (b)) ? (a) : (b))
1099#define mMax(a, b) (((a) < (b)) ? (b) : (a))
1100
36c4ff4d 1101void wxHtmlContainerCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2,
f30e67db 1102 wxHtmlRenderingInfo& info)
5526e819 1103{
ace0fab4
VS
1104#if 0 // useful for debugging
1105 dc.SetPen(*wxRED_PEN);
1106 dc.DrawRectangle(x+m_PosX,y+m_PosY,m_Width,m_Height);
1107#endif
95af070a 1108
848c4eb2
VS
1109 int xlocal = x + m_PosX;
1110 int ylocal = y + m_PosY;
1111
88343dda 1112 if (m_BkColour.IsOk())
4f9297b0 1113 {
04ee05f9 1114 wxBrush myb = wxBrush(m_BkColour, wxBRUSHSTYLE_SOLID);
5526e819 1115
848c4eb2
VS
1116 int real_y1 = mMax(ylocal, view_y1);
1117 int real_y2 = mMin(ylocal + m_Height - 1, view_y2);
5526e819 1118
848c4eb2
VS
1119 dc.SetBrush(myb);
1120 dc.SetPen(*wxTRANSPARENT_PEN);
1121 dc.DrawRectangle(xlocal, real_y1, m_Width, real_y2 - real_y1 + 1);
1122 }
5526e819 1123
3aaaf1aa 1124 if (m_Border == 1)
848c4eb2 1125 {
03647350 1126 // draw thin border using lines
04ee05f9
PC
1127 wxPen mypen1(m_BorderColour1, 1, wxPENSTYLE_SOLID);
1128 wxPen mypen2(m_BorderColour2, 1, wxPENSTYLE_SOLID);
848c4eb2
VS
1129
1130 dc.SetPen(mypen1);
1131 dc.DrawLine(xlocal, ylocal, xlocal, ylocal + m_Height - 1);
1132 dc.DrawLine(xlocal, ylocal, xlocal + m_Width, ylocal);
1133 dc.SetPen(mypen2);
1134 dc.DrawLine(xlocal + m_Width - 1, ylocal, xlocal + m_Width - 1, ylocal + m_Height - 1);
1135 dc.DrawLine(xlocal, ylocal + m_Height - 1, xlocal + m_Width, ylocal + m_Height - 1);
1136 }
3aaaf1aa 1137 else if (m_Border> 0)
03647350 1138 {
3aaaf1aa
VZ
1139 wxBrush mybrush1(m_BorderColour1, wxBRUSHSTYLE_SOLID);
1140 wxBrush mybrush2(m_BorderColour2, wxBRUSHSTYLE_SOLID);
03647350 1141
3aaaf1aa
VZ
1142 // draw upper left corner
1143 // 0---------------5
1144 // | /
1145 // | 3-----------4
1146 // | |
1147 // | 2
1148 // |/
03647350 1149 // 1
3aaaf1aa
VZ
1150
1151 wxPoint poly[6];
1152 poly[0].x =m_PosX; poly[0].y = m_PosY ;
1153 poly[1].x =m_PosX; poly[1].y = m_PosY + m_Height;
1154 poly[2].x =m_PosX + m_Border; poly[2].y = poly[1].y - m_Border;
1155 poly[3].x =poly[2].x ; poly[3].y = m_PosY + m_Border;
1156 poly[4].x =m_PosX + m_Width - m_Border; poly[4].y = poly[3].y;
1157 poly[5].x =m_PosX + m_Width; poly[5].y = m_PosY;
1158
1159 dc.SetBrush(mybrush1);
1160 dc.SetPen(*wxTRANSPARENT_PEN);
1161 dc.DrawPolygon(6, poly, x, y);
03647350 1162
3aaaf1aa
VZ
1163 // draw lower right corner reusing point 1,2,4 and 5
1164 // 5
1165 // /|
1166 // 4 |
1167 // | |
1168 // 2-----------3 |
1169 // / |
1170 // 1---------------0
1171 dc.SetBrush(mybrush2);
1172 poly[0].x = poly[5].x; poly[0].y = poly[1].y;
1173 poly[3].x = poly[4].x; poly[3].y = poly[2].y;
1174 dc.DrawPolygon(6, poly, x, y);
1175
03647350 1176 // smooth color transition like firefox
3aaaf1aa
VZ
1177 wxColour borderMediumColour(
1178 (m_BorderColour1.Red() + m_BorderColour2.Red()) /2 ,
1179 (m_BorderColour1.Green() + m_BorderColour2.Green()) /2 ,
03647350 1180 (m_BorderColour1.Blue() + m_BorderColour2.Blue()) /2
3aaaf1aa
VZ
1181 );
1182 wxPen mypen3(borderMediumColour, 1, wxPENSTYLE_SOLID);
1183 dc.SetPen(mypen3);
1184 dc.DrawLines(2, &poly[1], x, y - 1); // between 1 and 2
1185 dc.DrawLines(2, &poly[4], x, y - 1); // between 4 and 5
1186 }
848c4eb2
VS
1187 if (m_Cells)
1188 {
1189 // draw container's contents:
1190 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
bf7d7ee7 1191 {
95af070a 1192
848c4eb2
VS
1193 // optimize drawing: don't render off-screen content:
1194 if ((ylocal + cell->GetPosY() <= view_y2) &&
1195 (ylocal + cell->GetPosY() + cell->GetHeight() > view_y1))
36c4ff4d 1196 {
848c4eb2 1197 // the cell is visible, draw it:
f30e67db 1198 UpdateRenderingStatePre(info, cell);
36c4ff4d 1199 cell->Draw(dc,
848c4eb2 1200 xlocal, ylocal, view_y1, view_y2,
f30e67db
VS
1201 info);
1202 UpdateRenderingStatePost(info, cell);
36c4ff4d 1203 }
848c4eb2
VS
1204 else
1205 {
1206 // the cell is off-screen, proceed with font+color+etc.
1207 // changes only:
1208 cell->DrawInvisible(dc, xlocal, ylocal, info);
1209 }
bf7d7ee7 1210 }
5526e819 1211 }
5526e819
VS
1212}
1213
1214
1215
36c4ff4d 1216void wxHtmlContainerCell::DrawInvisible(wxDC& dc, int x, int y,
f30e67db 1217 wxHtmlRenderingInfo& info)
5526e819 1218{
d699f48b 1219 if (m_Cells)
bf7d7ee7
VS
1220 {
1221 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
36c4ff4d 1222 {
f30e67db
VS
1223 UpdateRenderingStatePre(info, cell);
1224 cell->DrawInvisible(dc, x + m_PosX, y + m_PosY, info);
1225 UpdateRenderingStatePost(info, cell);
36c4ff4d 1226 }
bf7d7ee7 1227 }
5526e819
VS
1228}
1229
1230
2b5f62a0
VZ
1231wxColour wxHtmlContainerCell::GetBackgroundColour()
1232{
88343dda 1233 return m_BkColour;
2b5f62a0
VZ
1234}
1235
1236
5526e819 1237
846914d1 1238wxHtmlLinkInfo *wxHtmlContainerCell::GetLink(int x, int y) const
5526e819 1239{
f6010d8f 1240 wxHtmlCell *cell = FindCellByPos(x, y);
5526e819 1241
f6010d8f
VZ
1242 // VZ: I don't know if we should pass absolute or relative coords to
1243 // wxHtmlCell::GetLink()? As the base class version just ignores them
1244 // anyhow, it hardly matters right now but should still be clarified
1245 return cell ? cell->GetLink(x, y) : NULL;
5526e819
VS
1246}
1247
1248
1249
1250void wxHtmlContainerCell::InsertCell(wxHtmlCell *f)
1251{
1252 if (!m_Cells) m_Cells = m_LastCell = f;
04dbb646 1253 else
4f9297b0
VS
1254 {
1255 m_LastCell->SetNext(f);
5526e819 1256 m_LastCell = f;
4f9297b0 1257 if (m_LastCell) while (m_LastCell->GetNext()) m_LastCell = m_LastCell->GetNext();
5526e819 1258 }
4f9297b0 1259 f->SetParent(this);
5660c520 1260 m_LastLayout = -1;
5526e819
VS
1261}
1262
1263
1264
1265void wxHtmlContainerCell::SetAlign(const wxHtmlTag& tag)
1266{
04dbb646 1267 if (tag.HasParam(wxT("ALIGN")))
4f9297b0 1268 {
0413cec5 1269 wxString alg = tag.GetParam(wxT("ALIGN"));
5526e819 1270 alg.MakeUpper();
0413cec5 1271 if (alg == wxT("CENTER"))
efba2b89 1272 SetAlignHor(wxHTML_ALIGN_CENTER);
0413cec5 1273 else if (alg == wxT("LEFT"))
efba2b89 1274 SetAlignHor(wxHTML_ALIGN_LEFT);
5c1bfc5d
VS
1275 else if (alg == wxT("JUSTIFY"))
1276 SetAlignHor(wxHTML_ALIGN_JUSTIFY);
0413cec5 1277 else if (alg == wxT("RIGHT"))
efba2b89 1278 SetAlignHor(wxHTML_ALIGN_RIGHT);
5660c520 1279 m_LastLayout = -1;
5526e819
VS
1280 }
1281}
1282
1283
1284
edbd0635 1285void wxHtmlContainerCell::SetWidthFloat(const wxHtmlTag& tag, double pixel_scale)
5526e819 1286{
04dbb646 1287 if (tag.HasParam(wxT("WIDTH")))
4f9297b0 1288 {
5526e819 1289 int wdi;
0413cec5 1290 wxString wd = tag.GetParam(wxT("WIDTH"));
5526e819 1291
93763ad5 1292 if (wd[wd.length()-1] == wxT('%'))
0cb9cfb2 1293 {
66a77a74 1294 wxSscanf(wd.c_str(), wxT("%i%%"), &wdi);
efba2b89 1295 SetWidthFloat(wdi, wxHTML_UNITS_PERCENT);
5526e819 1296 }
04dbb646 1297 else
0cb9cfb2 1298 {
66a77a74 1299 wxSscanf(wd.c_str(), wxT("%i"), &wdi);
edbd0635 1300 SetWidthFloat((int)(pixel_scale * (double)wdi), wxHTML_UNITS_PIXELS);
5526e819 1301 }
5660c520 1302 m_LastLayout = -1;
5526e819
VS
1303 }
1304}
1305
1306
1307
1308const wxHtmlCell* wxHtmlContainerCell::Find(int condition, const void* param) const
1309{
04dbb646 1310 if (m_Cells)
d699f48b 1311 {
bf7d7ee7
VS
1312 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
1313 {
999836aa 1314 const wxHtmlCell *r = cell->Find(condition, param);
bf7d7ee7
VS
1315 if (r) return r;
1316 }
1317 }
1318 return NULL;
5526e819
VS
1319}
1320
1321
36c4ff4d
VS
1322wxHtmlCell *wxHtmlContainerCell::FindCellByPos(wxCoord x, wxCoord y,
1323 unsigned flags) const
5526e819 1324{
6d41981d 1325 if ( flags & wxHTML_FIND_EXACT )
4f9297b0 1326 {
adf2eb2d
VS
1327 for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
1328 {
1329 int cx = cell->GetPosX(),
1330 cy = cell->GetPosY();
1331
1332 if ( (cx <= x) && (cx + cell->GetWidth() > x) &&
1333 (cy <= y) && (cy + cell->GetHeight() > y) )
1334 {
1335 return cell->FindCellByPos(x - cx, y - cy, flags);
1336 }
1337 }
adf2eb2d 1338 }
6d41981d 1339 else if ( flags & wxHTML_FIND_NEAREST_AFTER )
adf2eb2d
VS
1340 {
1341 wxHtmlCell *c;
adf2eb2d 1342 for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
0cb9cfb2 1343 {
03693319
VS
1344 if ( cell->IsFormattingCell() )
1345 continue;
1346 int cellY = cell->GetPosY();
d1da8872 1347 if (!( y < cellY || (y < cellY + cell->GetHeight() &&
03693319 1348 x < cell->GetPosX() + cell->GetWidth()) ))
adf2eb2d 1349 continue;
d1da8872 1350
03693319 1351 c = cell->FindCellByPos(x - cell->GetPosX(), y - cellY, flags);
adf2eb2d 1352 if (c) return c;
5526e819
VS
1353 }
1354 }
6d41981d 1355 else if ( flags & wxHTML_FIND_NEAREST_BEFORE )
adf2eb2d 1356 {
e24529d7 1357 wxHtmlCell *c2, *c = NULL;
adf2eb2d
VS
1358 for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
1359 {
03693319
VS
1360 if ( cell->IsFormattingCell() )
1361 continue;
1362 int cellY = cell->GetPosY();
1363 if (!( cellY + cell->GetHeight() <= y ||
1364 (y >= cellY && x >= cell->GetPosX()) ))
adf2eb2d 1365 break;
03693319 1366 c2 = cell->FindCellByPos(x - cell->GetPosX(), y - cellY, flags);
e24529d7
VS
1367 if (c2)
1368 c = c2;
adf2eb2d 1369 }
e24529d7 1370 if (c) return c;
adf2eb2d 1371 }
6d41981d
VZ
1372
1373 return NULL;
f6010d8f
VZ
1374}
1375
1376
bc55e31b
VS
1377bool wxHtmlContainerCell::ProcessMouseClick(wxHtmlWindowInterface *window,
1378 const wxPoint& pos,
1379 const wxMouseEvent& event)
f6010d8f 1380{
bc55e31b
VS
1381#if WXWIN_COMPATIBILITY_2_6
1382 wxHtmlCellOnMouseClickCompatHelper compat(window, pos, event);
1383 return compat.CallOnMouseClick(this);
5526e819
VS
1384}
1385
bc55e31b
VS
1386void wxHtmlContainerCell::OnMouseClick(wxWindow*,
1387 int, int, const wxMouseEvent& event)
1388{
9a83f860 1389 wxCHECK_RET( gs_helperOnMouseClick, wxT("unexpected call to OnMouseClick") );
bc55e31b
VS
1390 wxHtmlWindowInterface *window = gs_helperOnMouseClick->window;
1391 const wxPoint& pos = gs_helperOnMouseClick->pos;
1392#endif // WXWIN_COMPATIBILITY_2_6
1393
1394 bool retval = false;
1395 wxHtmlCell *cell = FindCellByPos(pos.x, pos.y);
1396 if ( cell )
1397 retval = cell->ProcessMouseClick(window, pos, event);
1398
1399#if WXWIN_COMPATIBILITY_2_6
1400 gs_helperOnMouseClick->retval = retval;
1401#else
1402 return retval;
1403#endif // WXWIN_COMPATIBILITY_2_6
1404}
5526e819
VS
1405
1406
adf2eb2d
VS
1407wxHtmlCell *wxHtmlContainerCell::GetFirstTerminal() const
1408{
e3774124
VS
1409 if ( m_Cells )
1410 {
1411 wxHtmlCell *c2;
1412 for (wxHtmlCell *c = m_Cells; c; c = c->GetNext())
1413 {
1414 c2 = c->GetFirstTerminal();
1415 if ( c2 )
1416 return c2;
1417 }
1418 }
1419 return NULL;
adf2eb2d
VS
1420}
1421
1422wxHtmlCell *wxHtmlContainerCell::GetLastTerminal() const
1423{
e3774124 1424 if ( m_Cells )
adf2eb2d 1425 {
e3774124 1426 // most common case first:
4ce19ed7 1427 wxHtmlCell *c = m_LastCell->GetLastTerminal();
e3774124
VS
1428 if ( c )
1429 return c;
4ce19ed7 1430
ace0fab4 1431 wxHtmlCell *ctmp;
4ce19ed7
VZ
1432 wxHtmlCell *c2 = NULL;
1433 for (c = m_Cells; c; c = c->GetNext())
ace0fab4
VS
1434 {
1435 ctmp = c->GetLastTerminal();
1436 if ( ctmp )
1437 c2 = ctmp;
1438 }
e3774124 1439 return c2;
adf2eb2d
VS
1440 }
1441 else
1442 return NULL;
1443}
79d6c018
VS
1444
1445
ace0fab4
VS
1446static bool IsEmptyContainer(wxHtmlContainerCell *cell)
1447{
1448 for ( wxHtmlCell *c = cell->GetFirstChild(); c; c = c->GetNext() )
1449 {
1450 if ( !c->IsTerminalCell() || !c->IsFormattingCell() )
1451 return false;
1452 }
1453 return true;
1454}
1455
1456void wxHtmlContainerCell::RemoveExtraSpacing(bool top, bool bottom)
d1da8872 1457{
ace0fab4
VS
1458 if ( top )
1459 SetIndent(0, wxHTML_INDENT_TOP);
1460 if ( bottom )
1461 SetIndent(0, wxHTML_INDENT_BOTTOM);
1462
1463 if ( m_Cells )
1464 {
1465 wxHtmlCell *c;
1466 wxHtmlContainerCell *cont;
1467 if ( top )
1468 {
1469 for ( c = m_Cells; c; c = c->GetNext() )
1470 {
1471 if ( c->IsTerminalCell() )
1472 {
1473 if ( !c->IsFormattingCell() )
1474 break;
1475 }
1476 else
1477 {
1478 cont = (wxHtmlContainerCell*)c;
1479 if ( IsEmptyContainer(cont) )
1480 {
1481 cont->SetIndent(0, wxHTML_INDENT_VERTICAL);
1482 }
1483 else
1484 {
1485 cont->RemoveExtraSpacing(true, false);
1486 break;
1487 }
1488 }
1489 }
1490 }
d1da8872 1491
ace0fab4
VS
1492 if ( bottom )
1493 {
1494 wxArrayPtrVoid arr;
1495 for ( c = m_Cells; c; c = c->GetNext() )
1496 arr.Add((void*)c);
d1da8872 1497
ace0fab4
VS
1498 for ( int i = arr.GetCount() - 1; i >= 0; i--)
1499 {
1500 c = (wxHtmlCell*)arr[i];
1501 if ( c->IsTerminalCell() )
1502 {
1503 if ( !c->IsFormattingCell() )
1504 break;
1505 }
1506 else
1507 {
1508 cont = (wxHtmlContainerCell*)c;
1509 if ( IsEmptyContainer(cont) )
1510 {
3e905c52
RD
1511 cont->SetIndent(0, wxHTML_INDENT_VERTICAL);
1512 }
ace0fab4
VS
1513 else
1514 {
1515 cont->RemoveExtraSpacing(false, true);
1516 break;
1517 }
1518 }
1519 }
1520 }
1521 }
1522}
1523
1524
5526e819
VS
1525
1526
36c4ff4d 1527// --------------------------------------------------------------------------
5526e819 1528// wxHtmlColourCell
36c4ff4d 1529// --------------------------------------------------------------------------
5526e819 1530
4f44ea36
MB
1531IMPLEMENT_ABSTRACT_CLASS(wxHtmlColourCell, wxHtmlCell)
1532
36c4ff4d
VS
1533void wxHtmlColourCell::Draw(wxDC& dc,
1534 int x, int y,
1535 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
f30e67db 1536 wxHtmlRenderingInfo& info)
5526e819 1537{
f30e67db 1538 DrawInvisible(dc, x, y, info);
5526e819
VS
1539}
1540
36c4ff4d
VS
1541void wxHtmlColourCell::DrawInvisible(wxDC& dc,
1542 int WXUNUSED(x), int WXUNUSED(y),
f30e67db 1543 wxHtmlRenderingInfo& info)
5526e819 1544{
f30e67db 1545 wxHtmlRenderingState& state = info.GetState();
efba2b89 1546 if (m_Flags & wxHTML_CLR_FOREGROUND)
36c4ff4d
VS
1547 {
1548 state.SetFgColour(m_Colour);
1549 if (state.GetSelectionState() != wxHTML_SEL_IN)
bfc248a3
VS
1550 dc.SetTextForeground(m_Colour);
1551 else
1552 dc.SetTextForeground(
1553 info.GetStyle().GetSelectedTextColour(m_Colour));
36c4ff4d 1554 }
04dbb646 1555 if (m_Flags & wxHTML_CLR_BACKGROUND)
4f9297b0 1556 {
36c4ff4d 1557 state.SetBgColour(m_Colour);
f5413b87
VZ
1558 state.SetBgMode(wxSOLID);
1559 const wxColour c = state.GetSelectionState() == wxHTML_SEL_IN
1560 ? info.GetStyle().GetSelectedTextBgColour(m_Colour)
1561 : m_Colour;
1562 dc.SetTextBackground(c);
1563 dc.SetBackground(c);
1564 dc.SetBackgroundMode(wxSOLID);
1565 }
1566 if (m_Flags & wxHTML_CLR_TRANSPARENT_BACKGROUND)
1567 {
1568 state.SetBgColour(m_Colour);
1569 state.SetBgMode(wxTRANSPARENT);
1570 const wxColour c = state.GetSelectionState() == wxHTML_SEL_IN
1571 ? info.GetStyle().GetSelectedTextBgColour(m_Colour)
1572 : m_Colour;
1573 dc.SetTextBackground(c);
1574 dc.SetBackgroundMode(wxTRANSPARENT);
5526e819 1575 }
5526e819
VS
1576}
1577
1578
1579
1580
36c4ff4d 1581// ---------------------------------------------------------------------------
5526e819 1582// wxHtmlFontCell
36c4ff4d 1583// ---------------------------------------------------------------------------
5526e819 1584
4f44ea36
MB
1585IMPLEMENT_ABSTRACT_CLASS(wxHtmlFontCell, wxHtmlCell)
1586
36c4ff4d
VS
1587void wxHtmlFontCell::Draw(wxDC& dc,
1588 int WXUNUSED(x), int WXUNUSED(y),
1589 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
f30e67db 1590 wxHtmlRenderingInfo& WXUNUSED(info))
5526e819 1591{
921d0fb1 1592 dc.SetFont(m_Font);
5526e819
VS
1593}
1594
36c4ff4d 1595void wxHtmlFontCell::DrawInvisible(wxDC& dc, int WXUNUSED(x), int WXUNUSED(y),
f30e67db 1596 wxHtmlRenderingInfo& WXUNUSED(info))
5526e819 1597{
921d0fb1 1598 dc.SetFont(m_Font);
5526e819
VS
1599}
1600
1601
1602
1603
1604
1605
1606
1607
36c4ff4d 1608// ---------------------------------------------------------------------------
5526e819 1609// wxHtmlWidgetCell
36c4ff4d 1610// ---------------------------------------------------------------------------
5526e819 1611
4f44ea36
MB
1612IMPLEMENT_ABSTRACT_CLASS(wxHtmlWidgetCell, wxHtmlCell)
1613
5526e819
VS
1614wxHtmlWidgetCell::wxHtmlWidgetCell(wxWindow *wnd, int w)
1615{
1616 int sx, sy;
1617 m_Wnd = wnd;
4f9297b0 1618 m_Wnd->GetSize(&sx, &sy);
5526e819
VS
1619 m_Width = sx, m_Height = sy;
1620 m_WidthFloat = w;
1621}
1622
1623
36c4ff4d
VS
1624void wxHtmlWidgetCell::Draw(wxDC& WXUNUSED(dc),
1625 int WXUNUSED(x), int WXUNUSED(y),
1626 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
f30e67db 1627 wxHtmlRenderingInfo& WXUNUSED(info))
5526e819
VS
1628{
1629 int absx = 0, absy = 0, stx, sty;
1630 wxHtmlCell *c = this;
1631
04dbb646 1632 while (c)
4f9297b0
VS
1633 {
1634 absx += c->GetPosX();
1635 absy += c->GetPosY();
1636 c = c->GetParent();
5526e819
VS
1637 }
1638
c4184573
VS
1639 wxScrolledWindow *scrolwin =
1640 wxDynamicCast(m_Wnd->GetParent(), wxScrolledWindow);
1641 wxCHECK_RET( scrolwin,
9a83f860 1642 wxT("widget cells can only be placed in wxHtmlWindow") );
c4184573
VS
1643
1644 scrolwin->GetViewStart(&stx, &sty);
1645 m_Wnd->SetSize(absx - wxHTML_SCROLL_STEP * stx,
1646 absy - wxHTML_SCROLL_STEP * sty,
1647 m_Width, m_Height);
5526e819
VS
1648}
1649
1650
1651
36c4ff4d
VS
1652void wxHtmlWidgetCell::DrawInvisible(wxDC& WXUNUSED(dc),
1653 int WXUNUSED(x), int WXUNUSED(y),
f30e67db 1654 wxHtmlRenderingInfo& WXUNUSED(info))
5526e819
VS
1655{
1656 int absx = 0, absy = 0, stx, sty;
1657 wxHtmlCell *c = this;
1658
04dbb646 1659 while (c)
4f9297b0
VS
1660 {
1661 absx += c->GetPosX();
1662 absy += c->GetPosY();
1663 c = c->GetParent();
5526e819 1664 }
7e941458 1665
e421922f 1666 ((wxScrolledWindow*)(m_Wnd->GetParent()))->GetViewStart(&stx, &sty);
4f9297b0 1667 m_Wnd->SetSize(absx - wxHTML_SCROLL_STEP * stx, absy - wxHTML_SCROLL_STEP * sty, m_Width, m_Height);
5526e819
VS
1668}
1669
1670
1671
1672void wxHtmlWidgetCell::Layout(int w)
1673{
04dbb646 1674 if (m_WidthFloat != 0)
4f9297b0 1675 {
5526e819 1676 m_Width = (w * m_WidthFloat) / 100;
4f9297b0 1677 m_Wnd->SetSize(m_Width, m_Height);
5526e819
VS
1678 }
1679
1680 wxHtmlCell::Layout(w);
1681}
1682
e3774124
VS
1683
1684
1685// ----------------------------------------------------------------------------
1686// wxHtmlTerminalCellsInterator
1687// ----------------------------------------------------------------------------
1688
1689const wxHtmlCell* wxHtmlTerminalCellsInterator::operator++()
1690{
1691 if ( !m_pos )
1692 return NULL;
1693
1694 do
1695 {
1696 if ( m_pos == m_to )
1697 {
1698 m_pos = NULL;
1699 return NULL;
1700 }
1701
1702 if ( m_pos->GetNext() )
1703 m_pos = m_pos->GetNext();
1704 else
1705 {
1706 // we must go up the hierarchy until we reach container where this
1707 // is not the last child, and then go down to first terminal cell:
1708 while ( m_pos->GetNext() == NULL )
1709 {
1710 m_pos = m_pos->GetParent();
1711 if ( !m_pos )
1712 return NULL;
1713 }
1714 m_pos = m_pos->GetNext();
1715 }
1716 while ( m_pos->GetFirstChild() != NULL )
1717 m_pos = m_pos->GetFirstChild();
1718 } while ( !m_pos->IsTerminalCell() );
86ff9b45 1719
e3774124
VS
1720 return m_pos;
1721}
1722
5526e819 1723#endif