feat: add a new awesome feature

This commit is contained in:
2025-11-19 15:14:39 +08:00
parent 5420bfd644
commit 58d4e8ab2f
23 changed files with 3360 additions and 3971 deletions

View File

@@ -17,21 +17,43 @@ void Canvas::clearAllControls()
controls.clear();
}
void Canvas::draw()
{
if (!dirty||!show)return;
if (!dirty || !show)
{
for (auto& control : controls)
if (auto c = dynamic_cast<Table*>(control.get()))
c->draw();
return;
}
saveStyle();
setlinecolor(canvasBorderClor);//设置线色
setfillcolor(canvasBkClor);//设置填充色
if(StellarX::FillMode::Null != canvasFillMode)
setfillcolor(canvasBkClor);//设置填充色
setfillstyle((int)canvasFillMode);//设置填充模式
setlinestyle((int)canvasLineStyle, canvaslinewidth);
if ((saveBkX != this->x) || (saveBkY != this->y) || (!hasSnap) || (saveWidth != this->width) || (saveHeight != this->height) || !saveBkImage)
saveBackground(x, y, width, height);
// 恢复背景(清除旧内容)
restBackground();
// 在绘制画布之前,先恢复并更新背景快照:
// 1. 如果已有快照,则先回贴旧快照以清除之前的内容。
// 2. 当坐标或尺寸变化,或缓存图像无效时,丢弃旧快照并重新抓取新的背景。
if (hasSnap)
{
// 恢复旧快照,清除上一次绘制
restBackground();
// 如果位置或尺寸变了,或没有有效缓存,则重新抓取
if (!saveBkImage || saveBkX != this->x || saveBkY != this->y || saveWidth != this->width || saveHeight != this->height)
{
discardBackground();
saveBackground(this->x, this->y, this->width, this->height);
}
}
else
{
// 首次绘制或没有快照时直接抓取背景
saveBackground(this->x, this->y, this->width, this->height);
}
// 再次恢复最新快照,确保绘制区域干净
restBackground();
//根据画布形状绘制
switch (shape)
{
@@ -158,9 +180,173 @@ void Canvas::setDirty(bool dirty)
void Canvas::onWindowResize()
{
Control::onWindowResize(); // 先处理自
for (auto& ch : controls) // 再转发给所有子控件
ch->onWindowResize();
// 先处理自身的快照等逻辑
Control::onWindowResize();
// 记录父容器原始尺寸(用于计算子控件的右/下边距)
int origParentW = this->localWidth;
int origParentH = this->localHeight;
// 当前容器的新尺寸
int finalW = this->width;
int finalH = this->height;
// 当前容器的新坐标(全局坐标)
int parentX = this->x;
int parentY = this->y;
// 调整每个子控件在 AnchorToEdges 模式下的位置与尺寸
for (auto& ch : controls)
{
// Only adjust when using anchor-to-edges layout
if (ch->getLayoutMode() == StellarX::LayoutMode::AnchorToEdges)
{
// Determine whether this child is a Table; tables keep their height constant
bool isTable = (dynamic_cast<Table*>(ch.get()) != nullptr);
// Unpack anchors
auto a1 = ch->getAnchor_1();
auto a2 = ch->getAnchor_2();
bool anchorLeft = (a1 == StellarX::Anchor::Left || a2 == StellarX::Anchor::Left);
bool anchorRight = (a1 == StellarX::Anchor::Right || a2 == StellarX::Anchor::Right);
bool anchorTop = (a1 == StellarX::Anchor::Top || a2 == StellarX::Anchor::Top);
bool anchorBottom = (a1 == StellarX::Anchor::Bottom || a2 == StellarX::Anchor::Bottom);
// If it's a table, treat as anchored left and right horizontally and anchored top vertically by default.
if (isTable)
{
anchorLeft = true;
anchorRight = true;
// If no explicit vertical anchor was provided, default to top.
if (!(anchorTop || anchorBottom))
{
anchorTop = true;
}
}
// Compute new X and width
int newX = ch->getX();
int newWidth = ch->getWidth();
if (anchorLeft && anchorRight)
{
// Scale horizontally relative to parent's size.
if (origParentW > 0)
{
// Maintain proportional position and size based on original local values.
double scaleW = static_cast<double>(finalW) / static_cast<double>(origParentW);
newX = parentX + static_cast<int>(ch->getLocalX() * scaleW + 0.5);
newWidth = static_cast<int>(ch->getLocalWidth() * scaleW + 0.5);
}
else
{
// Fallback: keep original
newX = parentX + ch->getLocalX();
newWidth = ch->getLocalWidth();
}
}
else if (anchorLeft && !anchorRight)
{
// Only left anchored: keep original width and left margin.
newWidth = ch->getLocalWidth();
newX = parentX + ch->getLocalX();
}
else if (!anchorLeft && anchorRight)
{
// Only right anchored: keep original width and right margin.
newWidth = ch->getLocalWidth();
int origRightDist = origParentW - (ch->getLocalX() + ch->getLocalWidth());
newX = parentX + finalW - origRightDist - newWidth;
}
else
{
// No horizontal anchor: position relative to parent's left and width unchanged.
newWidth = ch->getLocalWidth();
newX = parentX + ch->getLocalX();
}
ch->setX(newX);
ch->setWidth(newWidth);
// Compute new Y and height
int newY = ch->getY();
int newHeight = ch->getHeight();
if (isTable)
{
// Table: Height remains constant; adjust Y based on anchors.
newHeight = ch->getLocalHeight();
if (anchorTop && anchorBottom)
{
// If both top and bottom anchored, scale Y but keep height.
if (origParentH > 0)
{
double scaleH = static_cast<double>(finalH) / static_cast<double>(origParentH);
newY = parentY + static_cast<int>(ch->getLocalY() * scaleH + 0.5);
}
else
{
newY = parentY + ch->getLocalY();
}
}
else if (anchorTop && !anchorBottom)
{
// Top anchored only
newY = parentY + ch->getLocalY();
}
else if (!anchorTop && anchorBottom)
{
// Bottom anchored only
int origBottomDist = origParentH - (ch->getLocalY() + ch->getLocalHeight());
newY = parentY + finalH - origBottomDist - newHeight;
}
else
{
// No vertical anchor: default to top
newY = parentY + ch->getLocalY();
}
}
else
{
if (anchorTop && anchorBottom)
{
// Scale vertically relative to parent's size.
if (origParentH > 0)
{
double scaleH = static_cast<double>(finalH) / static_cast<double>(origParentH);
newY = parentY + static_cast<int>(ch->getLocalY() * scaleH + 0.5);
newHeight = static_cast<int>(ch->getLocalHeight() * scaleH + 0.5);
}
else
{
newY = parentY + ch->getLocalY();
newHeight = ch->getLocalHeight();
}
}
else if (anchorTop && !anchorBottom)
{
// Top anchored only: keep height constant
newHeight = ch->getLocalHeight();
newY = parentY + ch->getLocalY();
}
else if (!anchorTop && anchorBottom)
{
// Bottom anchored only: keep height and adjust Y relative to bottom
newHeight = ch->getLocalHeight();
int origBottomDist = origParentH - (ch->getLocalY() + ch->getLocalHeight());
newY = parentY + finalH - origBottomDist - newHeight;
}
else
{
// No vertical anchor: position relative to parent's top, height constant.
newHeight = ch->getLocalHeight();
newY = parentY + ch->getLocalY();
}
}
ch->setY(newY);
ch->setHeight(newHeight);
}
// Always forward the window resize event to the child (recursively).
ch->onWindowResize();
}
}
void Canvas::requestRepaint(Control* parent)