void CMultilineList::RenderContent(CDC & dc, CRect & r)
{
   dc.FillRect(r,CBrush::FromHandle(GetSysColorBrush(COLOR_WINDOW)));

   dc.SetBkMode(TRANSPARENT);
   dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));

   CPen * origPen = dc.SelectObject(&m_gridPen);

   int y1 = 0;
   int row = 0;

   // determine top visible row and setup y1 to be the top of its rendering area
   for (int yPos = 0; row < m_nRows; row++)
   {
      int thisRowHeight = m_rowHeights[row];

      if ((yPos + thisRowHeight) > m_viewYPos)
      {
         y1 = r.top - (m_viewYPos - yPos);
         break;
      }
      else
      {
         yPos += thisRowHeight;
      }
   }

   int firstRenderedRow = row;

	// for each row
   for (; (row < m_nRows) && (y1 <= r.bottom); row++)
   {
		// start with zero height
      int y2 = y1;

		// for each column
      for (int col = 0, x1 = r.left-m_viewXPos; (col < m_nCols); col++)
      {
			// get the column object (if it exists) or use defaults
         Column column;
         std::map<int,Column>::iterator i = m_columns.find(col);
         if (i != m_columns.end())
         {
            column = i->second;
         }

			// get the cell object (if it exists) or use defaults
         Cell cell;
         map<pair<int,int>,Cell>::iterator j = m_cells.find(make_pair(col,row));
         if (j != m_cells.end())
         {
            cell = j->second;
         }

			// determine the required size of the text, given the column width

         int x2 = x1 + column.m_width;

         CRect textRect(x1,y1,x2,y1);
         textRect.DeflateRect(INNER_PADDING,INNER_PADDING);
         int origRight = textRect.right;
         
         dc.DrawTextEx(cell.m_text,textRect,
            DT_CALCRECT|DT_LEFT|DT_NOPREFIX|DT_TOP|DT_WORDBREAK,
            NULL);
         
         textRect.right = origRight;

			// if this row is selected, fill in the background with the selection color and
			// set the text color
         if (row == m_curSelRow)
         {
            CRect bgRect(textRect);
            bgRect.InflateRect(INNER_PADDING,INNER_PADDING);
            bgRect.bottom = bgRect.top + m_rowHeights[row] + GRID_WIDTH;
            bgRect.top += GRID_WIDTH;
            dc.FillRect(bgRect,CBrush::FromHandle(GetSysColorBrush(COLOR_HIGHLIGHT)));
            dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
         }
         else
         {
				// else, ensure text color is set to the non-selected color
            dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
         }

         textRect.bottom += INNER_PADDING;
         textRect.bottom += GRID_WIDTH;

			// ensure tallest cell is stored
         if (textRect.bottom > y2)
         {
            y2 = textRect.bottom;
         }

			// render the cell text
         dc.DrawTextEx(cell.m_text,textRect,
            DT_LEFT|DT_NOPREFIX|DT_TOP|DT_WORDBREAK,
            NULL);

         x1 = x2;
      }

		// render horizontal grid line below the current row
      dc.MoveTo(r.left,y2+GRID_WIDTH);
      dc.LineTo(x1,y2+GRID_WIDTH);

		// if not the first row, also render the top horizontal line above the current row
      if (row > firstRenderedRow)
      {
         dc.MoveTo(r.left,y1+GRID_WIDTH);
         dc.LineTo(x1,y1+GRID_WIDTH);
      }

		// render the vertical lines between the columns
      for (int col = 0, x1 = r.left-m_viewXPos; (col < m_nCols) && (x1 <= r.right); col++)
      {
         Column column;
         std::map<int,Column>::iterator i = m_columns.find(col);
         if (i != m_columns.end())
         {
            column = i->second;
         }

         int x2 = x1 + column.m_width;

         dc.MoveTo(x2,y1+GRID_WIDTH);
         dc.LineTo(x2,y2+GRID_WIDTH);

         x1 = x2;
      }

      y1 = y2;
   }

   dc.SelectObject(origPen);
}