1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/html/m_list.cpp
3 // Purpose:     wxHtml module for lists
4 // Author:      Vaclav Slavik
5 // RCS-ID:      $Id: m_list.cpp 38788 2006-04-18 08:11:26Z ABX $
6 // Copyright:   (c) 1999 Vaclav Slavik
7 // Licence:     wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9 
10 #include "wx/wxprec.h"
11 
12 #ifdef __BORLANDC__
13     #pragma hdrstop
14 #endif
15 
16 #if wxUSE_HTML && wxUSE_STREAMS
17 
18 #ifndef WXPRECOMP
19     #include "wx/brush.h"
20     #include "wx/dc.h"
21 #endif
22 
23 #include "wx/html/forcelnk.h"
24 #include "wx/html/m_templ.h"
25 
26 #include "wx/html/htmlcell.h"
27 
28 FORCE_LINK_ME(m_list)
29 
30 
31 //-----------------------------------------------------------------------------
32 // wxHtmlListmarkCell
33 //-----------------------------------------------------------------------------
34 
35 class wxHtmlListmarkCell : public wxHtmlCell
36 {
37     private:
38         wxBrush m_Brush;
39     public:
40         wxHtmlListmarkCell(wxDC *dc, const wxColour& clr);
41         void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2,
42                   wxHtmlRenderingInfo& info);
43 
44     DECLARE_NO_COPY_CLASS(wxHtmlListmarkCell)
45 };
46 
wxHtmlListmarkCell(wxDC * dc,const wxColour & clr)47 wxHtmlListmarkCell::wxHtmlListmarkCell(wxDC* dc, const wxColour& clr) : wxHtmlCell(), m_Brush(clr, wxSOLID)
48 {
49     m_Width =  dc->GetCharHeight();
50     m_Height = dc->GetCharHeight();
51     // bottom of list mark is lined with bottom of letters in next cell
52     m_Descent = m_Height / 3;
53 }
54 
55 
56 
Draw(wxDC & dc,int x,int y,int WXUNUSED (view_y1),int WXUNUSED (view_y2),wxHtmlRenderingInfo & WXUNUSED (info))57 void wxHtmlListmarkCell::Draw(wxDC& dc, int x, int y,
58                               int WXUNUSED(view_y1), int WXUNUSED(view_y2),
59                               wxHtmlRenderingInfo& WXUNUSED(info))
60 {
61     dc.SetBrush(m_Brush);
62     dc.DrawEllipse(x + m_PosX + m_Width / 3, y + m_PosY + m_Height / 3,
63                    (m_Width / 3), (m_Width / 3));
64 }
65 
66 //-----------------------------------------------------------------------------
67 // wxHtmlListCell
68 //-----------------------------------------------------------------------------
69 
70 struct wxHtmlListItemStruct
71 {
72     wxHtmlContainerCell *mark;
73     wxHtmlContainerCell *cont;
74     int minWidth;
75     int maxWidth;
76 };
77 
78 class wxHtmlListCell : public wxHtmlContainerCell
79 {
80     private:
81         wxBrush m_Brush;
82 
83         int m_NumRows;
84         wxHtmlListItemStruct *m_RowInfo;
85         void ReallocRows(int rows);
86         void ComputeMinMaxWidths();
87         int ComputeMaxBase(wxHtmlCell *cell);
88         int m_ListmarkWidth;
89 
90     public:
91         wxHtmlListCell(wxHtmlContainerCell *parent);
92         virtual ~wxHtmlListCell();
93         void AddRow(wxHtmlContainerCell *mark, wxHtmlContainerCell *cont);
94         virtual void Layout(int w);
95 
96     DECLARE_NO_COPY_CLASS(wxHtmlListCell)
97 };
98 
wxHtmlListCell(wxHtmlContainerCell * parent)99 wxHtmlListCell::wxHtmlListCell(wxHtmlContainerCell *parent) : wxHtmlContainerCell(parent)
100 {
101     m_NumRows = 0;
102     m_RowInfo = 0;
103     m_ListmarkWidth = 0;
104 }
105 
~wxHtmlListCell()106 wxHtmlListCell::~wxHtmlListCell()
107 {
108     if (m_RowInfo) free(m_RowInfo);
109 }
110 
ComputeMaxBase(wxHtmlCell * cell)111 int wxHtmlListCell::ComputeMaxBase(wxHtmlCell *cell)
112 {
113     if(!cell)
114         return 0;
115 
116     wxHtmlCell *child = cell->GetFirstChild();
117 
118     while(child)
119     {
120         int base = ComputeMaxBase( child );
121         if ( base > 0 ) return base + child->GetPosY();
122         child = child->GetNext();
123     }
124 
125     return cell->GetHeight() - cell->GetDescent();
126 }
127 
Layout(int w)128 void wxHtmlListCell::Layout(int w)
129 {
130     wxHtmlCell::Layout(w);
131 
132     ComputeMinMaxWidths();
133     m_Width = wxMax(m_Width, wxMin(w, GetMaxTotalWidth()));
134 
135     int s_width = m_Width - m_IndentLeft;
136 
137     int vpos = 0;
138     for (int r = 0; r < m_NumRows; r++)
139     {
140         // do layout first time to layout contents and adjust pos
141         m_RowInfo[r].mark->Layout(m_ListmarkWidth);
142         m_RowInfo[r].cont->Layout(s_width - m_ListmarkWidth);
143 
144         const int base_mark = ComputeMaxBase( m_RowInfo[r].mark );
145         const int base_cont = ComputeMaxBase( m_RowInfo[r].cont );
146         const int adjust_mark = vpos + wxMax(base_cont-base_mark,0);
147         const int adjust_cont = vpos + wxMax(base_mark-base_cont,0);
148 
149         m_RowInfo[r].mark->SetPos(m_IndentLeft, adjust_mark);
150         m_RowInfo[r].cont->SetPos(m_IndentLeft + m_ListmarkWidth, adjust_cont);
151 
152         vpos = wxMax(adjust_mark + m_RowInfo[r].mark->GetHeight(),
153                      adjust_cont + m_RowInfo[r].cont->GetHeight());
154     }
155     m_Height = vpos;
156 }
157 
AddRow(wxHtmlContainerCell * mark,wxHtmlContainerCell * cont)158 void wxHtmlListCell::AddRow(wxHtmlContainerCell *mark, wxHtmlContainerCell *cont)
159 {
160     ReallocRows(++m_NumRows);
161     m_RowInfo[m_NumRows - 1].mark = mark;
162     m_RowInfo[m_NumRows - 1].cont = cont;
163 }
164 
ReallocRows(int rows)165 void wxHtmlListCell::ReallocRows(int rows)
166 {
167     m_RowInfo = (wxHtmlListItemStruct*) realloc(m_RowInfo, sizeof(wxHtmlListItemStruct) * rows);
168     m_RowInfo[rows - 1].mark = NULL;
169     m_RowInfo[rows - 1].cont = NULL;
170     m_RowInfo[rows - 1].minWidth = 0;
171     m_RowInfo[rows - 1].maxWidth = 0;
172 
173     m_NumRows = rows;
174 }
175 
ComputeMinMaxWidths()176 void wxHtmlListCell::ComputeMinMaxWidths()
177 {
178     if (m_NumRows == 0) return;
179 
180     m_MaxTotalWidth = 0;
181     m_Width = 0;
182 
183     for (int r = 0; r < m_NumRows; r++)
184     {
185         wxHtmlListItemStruct& row = m_RowInfo[r];
186         row.mark->Layout(1);
187         row.cont->Layout(1);
188         int maxWidth = row.cont->GetMaxTotalWidth();
189         int width = row.cont->GetWidth();
190         if (row.mark->GetWidth() > m_ListmarkWidth)
191             m_ListmarkWidth = row.mark->GetWidth();
192         if (maxWidth > m_MaxTotalWidth)
193             m_MaxTotalWidth = maxWidth;
194         if (width > m_Width)
195             m_Width = width;
196     }
197     m_Width += m_ListmarkWidth + m_IndentLeft;
198     m_MaxTotalWidth += m_ListmarkWidth + m_IndentLeft;
199 }
200 
201 //-----------------------------------------------------------------------------
202 // wxHtmlListcontentCell
203 //-----------------------------------------------------------------------------
204 
205 class wxHtmlListcontentCell : public wxHtmlContainerCell
206 {
207 public:
wxHtmlListcontentCell(wxHtmlContainerCell * p)208     wxHtmlListcontentCell(wxHtmlContainerCell *p) : wxHtmlContainerCell(p) {}
Layout(int w)209     virtual void Layout(int w) {
210         // Reset top indentation, fixes <li><p>
211         SetIndent(0, wxHTML_INDENT_TOP);
212         wxHtmlContainerCell::Layout(w);
213     }
214 };
215 
216 //-----------------------------------------------------------------------------
217 // The list handler:
218 //-----------------------------------------------------------------------------
219 
220 
221 TAG_HANDLER_BEGIN(OLULLI, "OL,UL,LI")
222 
223     TAG_HANDLER_VARS
224         wxHtmlListCell *m_List;
225         int m_Numbering;
226                 // this is number of actual item of list or 0 for dots
227 
TAG_HANDLER_CONSTR(OLULLI)228     TAG_HANDLER_CONSTR(OLULLI)
229     {
230         m_List = NULL;
231         m_Numbering = 0;
232     }
233 
TAG_HANDLER_PROC(tag)234     TAG_HANDLER_PROC(tag)
235     {
236         wxHtmlContainerCell *c;
237 
238         // List Item:
239         if (m_List && tag.GetName() == wxT("LI"))
240         {
241             c = m_WParser->SetContainer(new wxHtmlContainerCell(m_List));
242             c->SetAlignVer(wxHTML_ALIGN_TOP);
243 
244             wxHtmlContainerCell *mark = c;
245             c->SetWidthFloat(2 * m_WParser->GetCharWidth(), wxHTML_UNITS_PIXELS);
246             if (m_Numbering == 0)
247             {
248                 // Centering gives more space after the bullet
249                 c->SetAlignHor(wxHTML_ALIGN_CENTER);
250                 c->InsertCell(new wxHtmlListmarkCell(m_WParser->GetDC(), m_WParser->GetActualColor()));
251             }
252             else
253             {
254                 c->SetAlignHor(wxHTML_ALIGN_RIGHT);
255                 wxString markStr;
256                 markStr.Printf(wxT("%i. "), m_Numbering);
257                 c->InsertCell(new wxHtmlWordCell(markStr, *(m_WParser->GetDC())));
258             }
259             m_WParser->CloseContainer();
260 
261             c = m_WParser->OpenContainer();
262 
263             m_List->AddRow(mark, c);
264             c = m_WParser->OpenContainer();
265             m_WParser->SetContainer(new wxHtmlListcontentCell(c));
266 
267             if (m_Numbering != 0) m_Numbering++;
268         }
269 
270         // Begin of List (not-numbered): "UL", "OL"
271         else if (tag.GetName() == wxT("UL") || tag.GetName() == wxT("OL"))
272         {
273             int oldnum = m_Numbering;
274 
275             if (tag.GetName() == wxT("UL")) m_Numbering = 0;
276             else m_Numbering = 1;
277 
278             wxHtmlContainerCell *oldcont;
279             oldcont = c = m_WParser->OpenContainer();
280 
281             wxHtmlListCell *oldList = m_List;
282             m_List = new wxHtmlListCell(c);
283             m_List->SetIndent(2 * m_WParser->GetCharWidth(), wxHTML_INDENT_LEFT);
284 
285             ParseInner(tag);
286 
287             m_WParser->SetContainer(oldcont);
288             m_WParser->CloseContainer();
289 
290             m_Numbering = oldnum;
291             m_List = oldList;
292             return true;
293         }
294         return false;
295 
296     }
297 
298 TAG_HANDLER_END(OLULLI)
299 
300 
301 TAGS_MODULE_BEGIN(List)
302 
303     TAGS_MODULE_ADD(OLULLI)
304 
305 TAGS_MODULE_END(List)
306 
307 #endif
308