Size Grid::Measure(const Size availableSize) { RebuildCellDataIfNeeded(); Size borderSize(GetBorderAndPaddingSize(cachedStyle)); Cell* cell; Control* el; for (Grid::CellData& d : els) { cell = GetCell(d.row, d.col); cell->desiredSize.Width = 0; cell->desiredSize.Height = 0; el = d.el; if (!el->IsVisible()) continue; // calculate max dx of each column (dx of widest cell in the row) // and max dy of each row (dy of tallest cell in the column) el->Measure(availableSize); // TODO: take cell's border and padding into account cell->desiredSize = el->DesiredSize(); // if a cell spans multiple columns, we don't count its size here if (d.colSpan == 1) { if (cell->desiredSize.Width > maxColWidth[d.col]) maxColWidth[d.col] = cell->desiredSize.Width; } if (cell->desiredSize.Height > maxRowHeight[d.row]) maxRowHeight[d.row] = cell->desiredSize.Height; } // account for cells with colSpan > 1. If cell.dx > total dx // of columns it spans, we widen the columns by equally // re-distributing the difference among columns for (Grid::CellData& d : els) { if (d.colSpan == 1) continue; cell = GetCell(d.row, d.col); int totalDx = 0; for (int i = d.col; i < d.col + d.colSpan; i++) { totalDx += maxColWidth[i]; } int diff = cell->desiredSize.Width - totalDx; if (diff > 0) { int diffPerCol = diff / d.colSpan; int rest = diff % d.colSpan; // note: we could try to redistribute rest for ideal sizing instead of // over-sizing but not sure if that would matter in practice if (rest > 0) diffPerCol += 1; CrashIf(diffPerCol * d.colSpan < diff); for (int i = d.col; i < d.col + d.colSpan; i++) { maxColWidth[i] += diffPerCol; } } } int desiredWidth = 0; int desiredHeight = 0; for (int row = 0; row < rows; row++) { desiredHeight += maxRowHeight[row]; } for (int col = 0; col < cols; col++) { desiredWidth += maxColWidth[col]; } // TODO: what to do if desired size is more than availableSize? desiredSize.Width = desiredWidth + borderSize.Width; desiredSize.Height = desiredHeight + borderSize.Height; return desiredSize; }
void CBitmapControl::Paint(HDC hDC, const UiRect& rcPaint) { try { if( !::IntersectRect( &m_rcPaint, &rcPaint, &m_rcItem ) ) return; Control::Paint(hDC, rcPaint); //paint bitmap if (width_ * height_ > 0) { int item_w = m_rcItem.right-m_rcItem.left; int item_h = m_rcItem.bottom-m_rcItem.top; int item_x = m_rcItem.left; int item_y = m_rcItem.top; int source_w = width_; int source_h = height_; if (source_w > 0 && source_h > 0 && parent_wnd_) { //居中 item_x += (item_w - source_w) / 2; item_y += (item_h - source_h) / 2; UiRect rcClient; ::GetClientRect(parent_wnd_->GetHWND(), &rcClient); int width = rcClient.right - rcClient.left; int height = rcClient.bottom - rcClient.top; //计算实际绘制区域坐标 int draw_x = max(rcPaint.left, item_x); draw_x = max(m_rcItem.left, draw_x); int draw_y = max(rcPaint.top, item_y); draw_y = max(m_rcItem.top, draw_y); int draw_h = min(rcPaint.bottom - draw_y, min(item_y + source_h, m_rcItem.bottom) - draw_y); draw_h = max(draw_h, 0); int src_x = draw_x - item_x; int src_y = draw_y - item_y; int src_w = min(rcPaint.right - draw_x, min(item_x + source_w, m_rcItem.right) - draw_x); src_w = max(src_w, 0); int dest_byte_width = width * 4; int src_byte_width = source_w * 4; int paint_byte_width = src_w * 4; char* dest_data = (char*)parent_wnd_->GetBits(); int bottom = height - draw_y - 1; dest_data += bottom * dest_byte_width + draw_x * 4; char* src_data = (char*)data_.c_str(); src_data += src_y * src_byte_width + src_x * 4; for (int i = 0; i < draw_h; ++i) { memcpy(dest_data, src_data, paint_byte_width); dest_data -= dest_byte_width; src_data += src_byte_width; } } } //绘制子控件 for( auto it = m_items.begin(); it != m_items.end(); it++ ) { Control* pControl = *it; if( !pControl->IsVisible() ) continue; UiRect controlPos = pControl->GetPos(); if( !::IntersectRect( &m_rcPaint, &rcPaint, &controlPos ) ) continue; pControl->AlphaPaint( hDC, rcPaint ); } } catch (...) { throw "CBitmapControl::DoPaint"; } }