feat: add a new awesome feature
This commit is contained in:
212
src/Button.cpp
212
src/Button.cpp
@@ -128,8 +128,23 @@ static std::string ellipsize_cjk_pref(const std::string& text, int maxW, const c
|
||||
return head;
|
||||
}
|
||||
|
||||
void Button::setTooltipStyle(COLORREF text, COLORREF bk, bool transparent)
|
||||
{
|
||||
tipLabel.textStyle.color = text;
|
||||
tipLabel.setTextBkColor(bk);
|
||||
tipLabel.setTextdisap(transparent);
|
||||
}
|
||||
|
||||
void Button::setTooltipTextsForToggle(const std::string& onText, const std::string& offText)
|
||||
{
|
||||
tipTextOn = onText;
|
||||
tipTextOff = offText;
|
||||
tipUserOverride = true;
|
||||
}
|
||||
|
||||
void Button::initButton(const std::string text, StellarX::ButtonMode mode, StellarX::ControlShape shape, COLORREF ct, COLORREF cf, COLORREF ch)
|
||||
{
|
||||
this->id = "Button";
|
||||
this->text = text;
|
||||
this->mode = mode;
|
||||
this->shape = shape;
|
||||
@@ -142,7 +157,7 @@ void Button::initButton(const std::string text, StellarX::ButtonMode mode, Stell
|
||||
// === Tooltip 默认:文本=按钮文本;白底黑字;不透明;用当前按钮字体样式 ===
|
||||
tipTextClick = tipTextOn = tipTextOff = this->text;
|
||||
tipLabel.setText(tipTextClick);
|
||||
tipLabel.setTextColor(RGB(167, 170, 172));
|
||||
tipLabel.textStyle.color = (RGB(167, 170, 172));
|
||||
tipLabel.setTextBkColor(RGB(255, 255, 255));
|
||||
tipLabel.setTextdisap(false);
|
||||
tipLabel.textStyle = this->textStyle; // 复用按钮字体样式
|
||||
@@ -158,105 +173,109 @@ Button::~Button()
|
||||
|
||||
void Button::draw()
|
||||
{
|
||||
if (dirty && show)
|
||||
{
|
||||
//保存当前样式和颜色
|
||||
saveStyle();
|
||||
if (!dirty || !show)return;
|
||||
|
||||
if (StellarX::ButtonMode::DISABLED == mode) //设置禁用按钮色
|
||||
//保存当前样式和颜色
|
||||
saveStyle();
|
||||
|
||||
if (StellarX::ButtonMode::DISABLED == mode) //设置禁用按钮色
|
||||
{
|
||||
setfillcolor(DISABLEDCOLOUR);
|
||||
textStyle.bStrikeOut = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 点击状态优先级最高,然后是悬停状态,最后是默认状态
|
||||
COLORREF col = click ? buttonTrueColor : (hover ? buttonHoverColor : buttonFalseColor);
|
||||
setfillcolor(col);
|
||||
}
|
||||
//
|
||||
//设置字体背景色透明
|
||||
setbkmode(TRANSPARENT);
|
||||
//边框颜色
|
||||
setlinecolor(buttonBorderColor);
|
||||
|
||||
//设置字体颜色
|
||||
settextcolor(textStyle.color);
|
||||
//设置字体样式
|
||||
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
|
||||
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
|
||||
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut);
|
||||
|
||||
if (needCutText)
|
||||
cutButtonText();
|
||||
|
||||
//获取字符串像素高度和宽度
|
||||
if ((this->oldtext_width != this->text_width || this->oldtext_height != this->text_height)
|
||||
|| (-1 == oldtext_width && oldtext_height == -1))
|
||||
{
|
||||
if (isUseCutText)
|
||||
{
|
||||
setfillcolor(DISABLEDCOLOUR);
|
||||
textStyle.bStrikeOut = true;
|
||||
this->oldtext_width = this->text_width = textwidth(LPCTSTR(this->cutText.c_str()));
|
||||
this->oldtext_height = this->text_height = textheight(LPCTSTR(this->cutText.c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 点击状态优先级最高,然后是悬停状态,最后是默认状态
|
||||
COLORREF col = click ? buttonTrueColor : (hover ? buttonHoverColor : buttonFalseColor);
|
||||
setfillcolor(col);
|
||||
this->oldtext_width = this->text_width = textwidth(LPCTSTR(this->text.c_str()));
|
||||
this->oldtext_height = this->text_height = textheight(LPCTSTR(this->text.c_str()));
|
||||
}
|
||||
//
|
||||
//设置字体背景色透明
|
||||
setbkmode(TRANSPARENT);
|
||||
//边框颜色
|
||||
setlinecolor(buttonBorderColor);
|
||||
|
||||
//设置字体颜色
|
||||
settextcolor(textStyle.color);
|
||||
//设置字体样式
|
||||
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
|
||||
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
|
||||
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut);
|
||||
|
||||
if (needCutText)
|
||||
cutButtonText();
|
||||
|
||||
//获取字符串像素高度和宽度
|
||||
if ((this->oldtext_width != this->text_width || this->oldtext_height != this->text_height)
|
||||
|| (-1 == oldtext_width && oldtext_height == -1))
|
||||
{
|
||||
if(isUseCutText)
|
||||
{
|
||||
this->oldtext_width = this->text_width = textwidth(LPCTSTR(this->cutText.c_str()));
|
||||
this->oldtext_height = this->text_height = textheight(LPCTSTR(this->cutText.c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->oldtext_width = this->text_width = textwidth(LPCTSTR(this->text.c_str()));
|
||||
this->oldtext_height = this->text_height = textheight(LPCTSTR(this->text.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
//设置按钮填充模式
|
||||
setfillstyle((int)buttonFillMode, (int)buttonFillIma, buttonFileIMAGE);
|
||||
//根据按钮形状绘制
|
||||
switch (shape)
|
||||
{
|
||||
case StellarX::ControlShape::RECTANGLE://有边框填充矩形
|
||||
fillrectangle(x, y, x + width, y + height);
|
||||
isUseCutText ? outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(cutText.c_str()))
|
||||
:outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::B_RECTANGLE://无边框填充矩形
|
||||
solidrectangle(x, y, x + width, y + height);
|
||||
isUseCutText ? outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(cutText.c_str()))
|
||||
:outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::ROUND_RECTANGLE://有边框填充圆角矩形
|
||||
fillroundrect(x, y, x + width, y + height, rouRectangleSize.ROUND_RECTANGLEwidth, rouRectangleSize.ROUND_RECTANGLEheight);
|
||||
isUseCutText? outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(cutText.c_str()))
|
||||
:outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::B_ROUND_RECTANGLE://无边框填充圆角矩形
|
||||
solidroundrect(x, y, x + width, y + height, rouRectangleSize.ROUND_RECTANGLEwidth, rouRectangleSize.ROUND_RECTANGLEheight);
|
||||
isUseCutText? outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(cutText.c_str()))
|
||||
:outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::CIRCLE://有边框填充圆形
|
||||
fillcircle(x + width / 2, y + height / 2, min(width, height) / 2);
|
||||
isUseCutText? outtextxy(x + width / 2 - text_width / 2, y + height / 2 - text_height / 2, LPCTSTR(cutText.c_str()))
|
||||
:outtextxy(x + width / 2 - text_width / 2, y + height / 2 - text_height / 2, LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::B_CIRCLE://无边框填充圆形
|
||||
solidcircle(x + width / 2, y + height / 2, min(width, height) / 2);
|
||||
isUseCutText ? outtextxy(x + width / 2 - text_width / 2, y + height / 2 - text_height / 2, LPCTSTR(cutText.c_str()))
|
||||
:outtextxy(x + width / 2 - text_width / 2, y + height / 2 - text_height / 2, LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::ELLIPSE://有边框填充椭圆
|
||||
fillellipse(x, y, x + width, y + height);
|
||||
isUseCutText ? outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(cutText.c_str()))
|
||||
:outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::B_ELLIPSE://无边框填充椭圆
|
||||
solidellipse(x, y, x + width, y + height);
|
||||
isUseCutText ? outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(cutText.c_str()))
|
||||
:outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
}
|
||||
|
||||
restoreStyle();//恢复默认字体样式和颜色
|
||||
dirty = false; //标记按钮不需要重绘
|
||||
|
||||
}
|
||||
|
||||
//设置按钮填充模式
|
||||
setfillstyle((int)buttonFillMode, (int)buttonFillIma, buttonFileIMAGE);
|
||||
if ((saveBkX != this->x) || (saveBkY != this->y) || (!hasSnap) || (saveWidth != this->width) || (saveHeight != this->height) || !saveBkImage)
|
||||
saveBackground(this->x, this->y, this->width, this->height);
|
||||
// 恢复背景(清除旧内容)
|
||||
restBackground();
|
||||
//根据按钮形状绘制
|
||||
switch (shape)
|
||||
{
|
||||
case StellarX::ControlShape::RECTANGLE://有边框填充矩形
|
||||
fillrectangle(x, y, x + width, y + height);
|
||||
isUseCutText ? outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(cutText.c_str()))
|
||||
: outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::B_RECTANGLE://无边框填充矩形
|
||||
solidrectangle(x, y, x + width, y + height);
|
||||
isUseCutText ? outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(cutText.c_str()))
|
||||
: outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::ROUND_RECTANGLE://有边框填充圆角矩形
|
||||
fillroundrect(x, y, x + width, y + height, rouRectangleSize.ROUND_RECTANGLEwidth, rouRectangleSize.ROUND_RECTANGLEheight);
|
||||
isUseCutText ? outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(cutText.c_str()))
|
||||
: outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::B_ROUND_RECTANGLE://无边框填充圆角矩形
|
||||
solidroundrect(x, y, x + width, y + height, rouRectangleSize.ROUND_RECTANGLEwidth, rouRectangleSize.ROUND_RECTANGLEheight);
|
||||
isUseCutText ? outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(cutText.c_str()))
|
||||
: outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::CIRCLE://有边框填充圆形
|
||||
fillcircle(x + width / 2, y + height / 2, min(width, height) / 2);
|
||||
isUseCutText ? outtextxy(x + width / 2 - text_width / 2, y + height / 2 - text_height / 2, LPCTSTR(cutText.c_str()))
|
||||
: outtextxy(x + width / 2 - text_width / 2, y + height / 2 - text_height / 2, LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::B_CIRCLE://无边框填充圆形
|
||||
solidcircle(x + width / 2, y + height / 2, min(width, height) / 2);
|
||||
isUseCutText ? outtextxy(x + width / 2 - text_width / 2, y + height / 2 - text_height / 2, LPCTSTR(cutText.c_str()))
|
||||
: outtextxy(x + width / 2 - text_width / 2, y + height / 2 - text_height / 2, LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::ELLIPSE://有边框填充椭圆
|
||||
fillellipse(x, y, x + width, y + height);
|
||||
isUseCutText ? outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(cutText.c_str()))
|
||||
: outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::ControlShape::B_ELLIPSE://无边框填充椭圆
|
||||
solidellipse(x, y, x + width, y + height);
|
||||
isUseCutText ? outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(cutText.c_str()))
|
||||
: outtextxy((x + (width - text_width) / 2), (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
}
|
||||
|
||||
restoreStyle();//恢复默认字体样式和颜色
|
||||
dirty = false; //标记按钮不需要重绘
|
||||
|
||||
|
||||
}
|
||||
// 处理鼠标事件,检测点击和悬停状态
|
||||
// 根据按钮模式和形状进行不同的处理
|
||||
@@ -398,7 +417,7 @@ bool Button::handleEvent(const ExMessage& msg)
|
||||
|
||||
// 如果需要重绘,立即执行
|
||||
if (dirty)
|
||||
draw();
|
||||
requestRepaint();
|
||||
if(tipEnabled && tipVisible)
|
||||
tipLabel.draw();
|
||||
return consume;
|
||||
@@ -420,8 +439,11 @@ void Button::setOnToggleOffListener(const std::function<void()>&& callback)
|
||||
|
||||
void Button::setbuttonMode(StellarX::ButtonMode mode)
|
||||
{
|
||||
if (this->mode == StellarX::ButtonMode::DISABLED && mode != StellarX::ButtonMode::DISABLED)
|
||||
textStyle.bStrikeOut = false;
|
||||
//取值范围参考 buttMode的枚举注释
|
||||
this->mode = mode;
|
||||
dirty = true; // 标记需要重绘
|
||||
}
|
||||
|
||||
void Button::setROUND_RECTANGLEwidth(int width)
|
||||
@@ -532,7 +554,7 @@ void Button::setButtonClick(BOOL click)
|
||||
flushmessage(EX_MOUSE | EX_KEY);
|
||||
}
|
||||
if (dirty)
|
||||
draw();
|
||||
requestRepaint();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
#include "Canvas.h"
|
||||
|
||||
Canvas::Canvas()
|
||||
:Control(0, 0, 100, 100) {}
|
||||
:Control(0, 0, 100, 100)
|
||||
{
|
||||
this->id = "Canvas";
|
||||
}
|
||||
|
||||
Canvas::Canvas(int x, int y, int width, int height)
|
||||
:Control(x, y, width, height) {}
|
||||
:Control(x, y, width, height)
|
||||
{
|
||||
this->id = "Canvas";
|
||||
}
|
||||
|
||||
void Canvas::clearAllControls()
|
||||
{
|
||||
@@ -14,14 +20,17 @@ void Canvas::clearAllControls()
|
||||
|
||||
void Canvas::draw()
|
||||
{
|
||||
if (!dirty && !show)return;
|
||||
if (!dirty||!show)return;
|
||||
saveStyle();
|
||||
|
||||
setlinecolor(canvasBorderClor);//设置线色
|
||||
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(this->x, this->y, this->width, this->height);
|
||||
// 恢复背景(清除旧内容)
|
||||
restBackground();
|
||||
//根据画布形状绘制
|
||||
switch (shape)
|
||||
{
|
||||
@@ -51,16 +60,22 @@ void Canvas::draw()
|
||||
|
||||
bool Canvas::handleEvent(const ExMessage& msg)
|
||||
{
|
||||
if(!show)return false;
|
||||
if (!show)return false;
|
||||
bool consumed = false;
|
||||
bool anyDirty = false;
|
||||
|
||||
for (auto it = controls.rbegin(); it != controls.rend(); ++it)
|
||||
if ((*it)->handleEvent(msg))
|
||||
return true; // 事件被消费短路传递,立即返回true 否则返回false
|
||||
return false;
|
||||
for (auto it = controls.rbegin(); it != controls.rend(); ++it)
|
||||
{
|
||||
consumed |= it->get()->handleEvent(msg);
|
||||
if (it->get()->isDirty()) anyDirty = true;
|
||||
}
|
||||
if (anyDirty) requestRepaint();
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void Canvas::addControl(std::unique_ptr<Control> control)
|
||||
{
|
||||
control->setParent(this);
|
||||
controls.push_back(std::move(control));
|
||||
dirty = true;
|
||||
}
|
||||
@@ -117,5 +132,32 @@ void Canvas::setLinewidth(int width)
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void Canvas::setIsVisible(bool visible)
|
||||
{
|
||||
this->show = visible;
|
||||
dirty = true;
|
||||
for (auto& control : controls)
|
||||
{
|
||||
control->setIsVisible(visible);
|
||||
control->setDirty(true);
|
||||
}
|
||||
if (!visible)
|
||||
this->updateBackground();
|
||||
}
|
||||
|
||||
void Canvas::setDirty(bool dirty)
|
||||
{
|
||||
this->dirty = dirty;
|
||||
for(auto& control : controls)
|
||||
control->setDirty(dirty);
|
||||
}
|
||||
|
||||
void Canvas::onWindowResize()
|
||||
{
|
||||
Control::onWindowResize(); // 先处理自己
|
||||
for (auto& ch : controls) // 再转发给所有子控件
|
||||
ch->onWindowResize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -42,6 +42,18 @@ bool StellarX::ControlText::operator!=(const ControlText& text)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
void Control::setIsVisible(bool show)
|
||||
{
|
||||
if (!show)
|
||||
this->updateBackground();
|
||||
this->show = show;
|
||||
}
|
||||
void Control::onWindowResize()
|
||||
{
|
||||
// 自己:丢快照 + 标脏
|
||||
discardBackground();
|
||||
setDirty(true);
|
||||
}
|
||||
// 保存当前的绘图状态(字体、颜色、线型等)
|
||||
// 在控件绘制前调用,确保不会影响全局绘图状态
|
||||
void Control::saveStyle()
|
||||
@@ -65,6 +77,20 @@ void Control::restoreStyle()
|
||||
setfillstyle(BS_SOLID);//恢复填充
|
||||
}
|
||||
|
||||
void Control::requestRepaint()
|
||||
{
|
||||
if (parent) parent->requestRepaint(); // 向上冒泡
|
||||
else onRequestRepaintAsRoot(); // 到根控件/窗口兜底
|
||||
}
|
||||
|
||||
void Control::onRequestRepaintAsRoot()
|
||||
{
|
||||
|
||||
discardBackground();
|
||||
setDirty(true);
|
||||
draw(); // 只有“无父”时才允许立即画,不会被谁覆盖
|
||||
}
|
||||
|
||||
void Control::saveBackground(int x, int y, int w, int h)
|
||||
{
|
||||
if (w <= 0 || h <= 0) return;
|
||||
@@ -105,10 +131,6 @@ void Control::discardBackground()
|
||||
|
||||
void Control::updateBackground()
|
||||
{
|
||||
if (saveBkImage)
|
||||
{
|
||||
delete saveBkImage;
|
||||
saveBkImage = nullptr;
|
||||
}
|
||||
hasSnap = false; saveWidth = saveHeight = 0;
|
||||
restBackground();
|
||||
discardBackground();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
Dialog::Dialog(Window& h,std::string text,std::string message, StellarX::MessageBoxType type, bool modal)
|
||||
: Canvas(),message(message), type(type), modal(modal), hWnd(h), titleText(text)
|
||||
{
|
||||
this->id = "Dialog";
|
||||
show = false;
|
||||
}
|
||||
|
||||
@@ -36,10 +37,9 @@ void Dialog::draw()
|
||||
saveStyle();
|
||||
|
||||
|
||||
// 保存背景(仅在第一次绘制时)
|
||||
if (saveBkImage == nullptr)
|
||||
saveBackground((x - BorderWidth), (y - BorderWidth), (width + 2 * BorderWidth), (height + 2 * BorderWidth));
|
||||
|
||||
if ((saveBkX != this->x) || (saveBkY != this->y) || (!hasSnap) || (saveWidth != this->width) || (saveHeight != this->height) || !saveBkImage)
|
||||
saveBackground(this->x, this->y, this->width, this->height);
|
||||
|
||||
Canvas::setBorderColor(this->borderColor);
|
||||
Canvas::setLinewidth(this->BorderWidth);
|
||||
Canvas::setCanvasBkColor(this->backgroundColor);
|
||||
@@ -191,7 +191,7 @@ void Dialog::Show()
|
||||
// 重绘
|
||||
if (dirty)
|
||||
{
|
||||
draw();
|
||||
requestRepaint();
|
||||
FlushBatchDraw();
|
||||
}
|
||||
|
||||
|
||||
350
src/TabControl.cpp
Normal file
350
src/TabControl.cpp
Normal file
@@ -0,0 +1,350 @@
|
||||
#include "TabControl.h"
|
||||
|
||||
inline void TabControl::initTabBar()
|
||||
{
|
||||
if (controls.empty())return;
|
||||
int butW = max(this->width / (int)controls.size(), BUTMINWIDTH);
|
||||
int butH = max(this->height / (int)controls.size(), BUTMINHEIGHT);
|
||||
|
||||
if (this->tabPlacement == StellarX::TabPlacement::Top || this->tabPlacement == StellarX::TabPlacement::Bottom)
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.first->setHeight(tabBarHeight);
|
||||
c.first->setWidth(butW);
|
||||
}
|
||||
else if (this->tabPlacement == StellarX::TabPlacement::Left || this->tabPlacement == StellarX::TabPlacement::Right)
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.first->setHeight(butH);
|
||||
c.first->setWidth(tabBarHeight);
|
||||
}
|
||||
int i = 0;
|
||||
switch (this->tabPlacement)
|
||||
{
|
||||
case StellarX::TabPlacement::Top:
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.first->setX(this->x + i * butW);
|
||||
c.first->setY(this->y);
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
case StellarX::TabPlacement::Bottom:
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.first->setX(this->x + i * butW);
|
||||
c.first->setY(this->y+this->height - tabBarHeight);
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
case StellarX::TabPlacement::Left:
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.first->setX(this->x);
|
||||
c.first->setY(this->y+i* butH);
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
case StellarX::TabPlacement::Right:
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.first->setX(this->x+this->width - tabBarHeight);
|
||||
c.first->setY(this->y + i * butH);
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabControl::initTabPage()
|
||||
{
|
||||
if (controls.empty())return;
|
||||
//子控件坐标原点
|
||||
int nX = 0;
|
||||
int nY = 0;
|
||||
switch (this->tabPlacement)
|
||||
{
|
||||
case StellarX::TabPlacement::Top:
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.second->setX(this->x);
|
||||
c.second->setY(this->y + tabBarHeight);
|
||||
c.second->setWidth(this->width);
|
||||
c.second->setHeight(this->height - tabBarHeight);
|
||||
}
|
||||
nX = this->x;
|
||||
nY = this->y + tabBarHeight;
|
||||
for (auto& c : controls)
|
||||
{
|
||||
for (auto& v : c.second->getControls())
|
||||
{
|
||||
v->setX(v->getLocalX() + nX);
|
||||
v->setY(v->getLocalY() + nY);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case StellarX::TabPlacement::Bottom:
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.second->setX(this->x);
|
||||
c.second->setY(this->y);
|
||||
c.second->setWidth(this->width);
|
||||
c.second->setHeight(this->height - tabBarHeight);
|
||||
}
|
||||
nX = this->x;
|
||||
nY = this->y;
|
||||
for (auto& c : controls)
|
||||
{
|
||||
for (auto& v : c.second->getControls())
|
||||
{
|
||||
v->setX(v->getLocalX() + nX);
|
||||
v->setY(v->getLocalY() + nY);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case StellarX::TabPlacement::Left:
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.second->setX(this->x + tabBarHeight);
|
||||
c.second->setY(this->y);
|
||||
c.second->setWidth(this->width - tabBarHeight);
|
||||
c.second->setHeight(this->height);
|
||||
}
|
||||
nX = this->x + tabBarHeight;
|
||||
nY = this->y;
|
||||
for (auto& c : controls)
|
||||
{
|
||||
for (auto& v : c.second->getControls())
|
||||
{
|
||||
v->setX(v->getLocalX() + nX);
|
||||
v->setY(v->getLocalY() + nY);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case StellarX::TabPlacement::Right:
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.second->setX(this->x);
|
||||
c.second->setY(this->y);
|
||||
c.second->setWidth(this->width - tabBarHeight);
|
||||
c.second->setHeight(this->height);
|
||||
}
|
||||
nX = this->x;
|
||||
nY = this->y;
|
||||
for (auto& c : controls)
|
||||
{
|
||||
for (auto& v : c.second->getControls())
|
||||
{
|
||||
v->setX(v->getLocalX() + nX);
|
||||
v->setY(v->getLocalY() + nY);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TabControl::TabControl():Canvas()
|
||||
{
|
||||
this->id = "TabControl";
|
||||
}
|
||||
|
||||
TabControl::TabControl(int x, int y, int width, int height)
|
||||
: Canvas(x, y, width, height)
|
||||
{
|
||||
this->id = "TabControl";
|
||||
}
|
||||
|
||||
TabControl::~TabControl()
|
||||
{
|
||||
}
|
||||
|
||||
void TabControl::draw()
|
||||
{
|
||||
if (!dirty || !show)return;
|
||||
if ((saveBkX != this->x) || (saveBkY != this->y) || (!hasSnap) || (saveWidth != this->width) || (saveHeight != this->height) || !saveBkImage)
|
||||
saveBackground(this->x, this->y, this->width, this->height);
|
||||
// 恢复背景(清除旧内容)
|
||||
restBackground();
|
||||
Canvas::draw();
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.first->setDirty(true);
|
||||
c.first->draw();
|
||||
}
|
||||
for (auto& c : controls)
|
||||
if(c.second->IsVisible())
|
||||
{
|
||||
c.second->setDirty(true);
|
||||
c.second->draw();
|
||||
}
|
||||
dirty = false;
|
||||
|
||||
}
|
||||
|
||||
bool TabControl::handleEvent(const ExMessage& msg)
|
||||
{
|
||||
if (!show)return false;
|
||||
bool consume = false;
|
||||
for (auto& c : controls)
|
||||
if (c.first->handleEvent(msg))
|
||||
{
|
||||
consume = true;
|
||||
break;
|
||||
}
|
||||
for (auto& c : controls)
|
||||
if(c.second->IsVisible())
|
||||
if (c.second->handleEvent(msg))
|
||||
{
|
||||
consume = true;
|
||||
break;
|
||||
}
|
||||
if (dirty)
|
||||
requestRepaint();
|
||||
return consume;
|
||||
}
|
||||
|
||||
void TabControl::add(std::pair<std::unique_ptr<Button>, std::unique_ptr<Canvas>>&& control)
|
||||
{
|
||||
controls.push_back(std::move(control));
|
||||
initTabBar();
|
||||
initTabPage();
|
||||
size_t idx = controls.size() - 1;
|
||||
controls[idx].first->setParent(this);
|
||||
controls[idx].first->enableTooltip(true);
|
||||
controls[idx].first->setbuttonMode(StellarX::ButtonMode::TOGGLE);
|
||||
controls[idx].first->setOnToggleOnListener([this,idx]()
|
||||
{
|
||||
controls[idx].second->setIsVisible(true);
|
||||
controls[idx].second->onWindowResize();
|
||||
for (auto& tab : controls)
|
||||
{
|
||||
if (tab.first->getButtonText() != controls[idx].first->getButtonText())
|
||||
{
|
||||
tab.first->setButtonClick(false);
|
||||
tab.second->setIsVisible(false);
|
||||
}
|
||||
}
|
||||
dirty = true;
|
||||
});
|
||||
controls[idx].first->setOnToggleOffListener([this,idx]()
|
||||
{
|
||||
controls[idx].second->setIsVisible(false);
|
||||
|
||||
dirty = true;
|
||||
});
|
||||
controls[idx].second->setParent(this);
|
||||
controls[idx].second->setLinewidth(canvaslinewidth);
|
||||
controls[idx].second->setIsVisible(false);
|
||||
}
|
||||
|
||||
void TabControl::add(std::string tabText, std::unique_ptr<Control> control)
|
||||
{
|
||||
control->setDirty(true);
|
||||
for (auto& tab : controls)
|
||||
{
|
||||
if (tab.first->getButtonText() == tabText)
|
||||
{
|
||||
control->setParent(tab.second.get());
|
||||
control->setIsVisible( tab.second->IsVisible());
|
||||
tab.second->addControl(std::move(control));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TabControl::setTabPlacement(StellarX::TabPlacement placement)
|
||||
{
|
||||
this->tabPlacement = placement;
|
||||
setDirty(true);
|
||||
initTabBar();
|
||||
initTabPage();
|
||||
|
||||
}
|
||||
|
||||
void TabControl::setTabBarHeight(int height)
|
||||
{
|
||||
tabBarHeight = height;
|
||||
setDirty(true);
|
||||
initTabBar();
|
||||
initTabPage();
|
||||
}
|
||||
|
||||
void TabControl::setIsVisible(bool visible)
|
||||
{
|
||||
// 先让基类 Canvas 处理自己的回贴/丢快照逻辑
|
||||
Canvas::setIsVisible(visible); // <--- 新增
|
||||
|
||||
this->show = visible;
|
||||
for (auto& tab : controls)
|
||||
{
|
||||
tab.first->setIsVisible(visible);
|
||||
//页也要跟着关/开,否则它们会保留旧的 saveBkImage
|
||||
tab.second->setIsVisible(visible);
|
||||
tab.second->setDirty(true);
|
||||
}
|
||||
}
|
||||
|
||||
void TabControl::onWindowResize()
|
||||
{
|
||||
Control::onWindowResize();
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.first->onWindowResize();
|
||||
c.second->onWindowResize();
|
||||
}
|
||||
}
|
||||
|
||||
int TabControl::getActiveIndex() const
|
||||
{
|
||||
int idx = -1;
|
||||
for (auto& c : controls)
|
||||
{
|
||||
idx++;
|
||||
if (c.first->isClicked())
|
||||
return idx;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
void TabControl::setActiveIndex(int idx)
|
||||
{
|
||||
if (idx < 0 || idx > controls.size() - 1) return;
|
||||
if (controls[idx].first->getButtonMode() == StellarX::ButtonMode::DISABLED)return;
|
||||
if (controls[idx].first->isClicked())
|
||||
{
|
||||
if (controls[idx].second->IsVisible())
|
||||
return;
|
||||
else
|
||||
controls[idx].second->setIsVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
controls[idx].first->setButtonClick(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int TabControl::count() const
|
||||
{
|
||||
return (int)controls.size();
|
||||
}
|
||||
|
||||
int TabControl::indexOf(const std::string& tabText) const
|
||||
{
|
||||
int idx = -1;
|
||||
for(auto& c : controls)
|
||||
{
|
||||
idx++;
|
||||
if (c.first->getButtonText() == tabText)
|
||||
return idx;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,16 +3,18 @@
|
||||
Label::Label()
|
||||
:Control(0, 0, 0, 0)
|
||||
{
|
||||
this->id = "Label";
|
||||
this->text = "默认标签";
|
||||
textColor = RGB(0,0,0);
|
||||
textStyle.color = RGB(0,0,0);
|
||||
textBkColor = RGB(255, 255, 255);; //默认白色背景
|
||||
}
|
||||
|
||||
Label::Label(int x, int y, std::string text, COLORREF textcolor, COLORREF bkColor)
|
||||
:Control(x, y, 0, 0)
|
||||
{
|
||||
this->id = "Label";
|
||||
this->text = text;
|
||||
textColor = textcolor;
|
||||
textStyle.color = textcolor;
|
||||
textBkColor = bkColor; //默认白色背景
|
||||
}
|
||||
|
||||
@@ -28,14 +30,21 @@ void Label::draw()
|
||||
setbkmode(OPAQUE); //设置背景不透明
|
||||
setbkcolor(textBkColor); //设置背景颜色
|
||||
}
|
||||
settextcolor(textColor);
|
||||
settextcolor(textStyle.color);
|
||||
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
|
||||
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
|
||||
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut); //设置字体样式
|
||||
this->saveBackground(x, y,textwidth(text.c_str()),textheight(text.c_str()));
|
||||
this-> restBackground();
|
||||
if (0 == this->width || 0 == this->height)
|
||||
{
|
||||
this->width = textwidth(text.c_str());
|
||||
this->height = textheight(text.c_str());
|
||||
}
|
||||
if ((saveBkX != this->x) || (saveBkY != this->y) || (!hasSnap) || (saveWidth != this->width) || (saveHeight != this->height) || !saveBkImage)
|
||||
saveBackground(this->x, this->y,this->width,this->height);
|
||||
// 恢复背景(清除旧内容)
|
||||
restBackground();
|
||||
outtextxy(x, y, LPCTSTR(text.c_str()));
|
||||
this->restoreStyle();
|
||||
restoreStyle();
|
||||
dirty = false;
|
||||
}
|
||||
}
|
||||
@@ -52,12 +61,6 @@ void Label::setTextdisap(bool key)
|
||||
this->dirty = true;
|
||||
}
|
||||
|
||||
void Label::setTextColor(COLORREF color)
|
||||
{
|
||||
textColor = color;
|
||||
this->dirty = true;
|
||||
}
|
||||
|
||||
void Label::setTextBkColor(COLORREF color)
|
||||
{
|
||||
textBkColor = color;
|
||||
@@ -68,4 +71,5 @@ void Label::setText(std::string text)
|
||||
{
|
||||
this->text = text;
|
||||
this->dirty = true;
|
||||
|
||||
}
|
||||
|
||||
103
src/table.cpp
103
src/table.cpp
@@ -7,8 +7,8 @@ void Table::drawTable()
|
||||
|
||||
// 表体从“表头之下”开始
|
||||
dX = x + border;
|
||||
dY = y + border + lineHeights.at(0) + 10; // 表头高度
|
||||
uY = dY + lineHeights.at(0) + 10;
|
||||
dY = y + border + lineHeights.at(0) + TABLE_HEADER_EXTRA; // 表头高度
|
||||
uY = dY + lineHeights.at(0) + TABLE_ROW_EXTRA;
|
||||
|
||||
size_t startRow = (currentPage - 1) * rowsPerPage;
|
||||
size_t endRow = startRow + (size_t)rowsPerPage < data.size() ? startRow + (size_t)rowsPerPage : data.size();
|
||||
@@ -17,14 +17,14 @@ void Table::drawTable()
|
||||
{
|
||||
for (size_t j = 0; j < data[i].size(); ++j)
|
||||
{
|
||||
uX = dX + colWidths.at(j) + 20; // 列宽 + 20
|
||||
uX = dX + colWidths.at(j) + TABLE_COL_GAP;
|
||||
fillrectangle(dX, dY, uX, uY);
|
||||
outtextxy(dX + 10, dY + 5, LPCTSTR(data[i][j].c_str()));
|
||||
dX += colWidths.at(j) + 20;
|
||||
outtextxy(dX + TABLE_PAD_X, dY + TABLE_PAD_Y, LPCTSTR(data[i][j].c_str()));
|
||||
dX += colWidths.at(j) + TABLE_COL_GAP;
|
||||
}
|
||||
dX = x + border;
|
||||
dY = uY;
|
||||
uY = dY + lineHeights.at(0) + 10;
|
||||
uY = dY + lineHeights.at(0) + TABLE_ROW_EXTRA;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,14 +36,14 @@ void Table::drawHeader()
|
||||
// 内容区原点 = x+border, y+border
|
||||
dX = x + border;
|
||||
dY = y + border;
|
||||
uY = dY + lineHeights.at(0) + 10;
|
||||
uY = dY + lineHeights.at(0) + TABLE_HEADER_EXTRA;
|
||||
|
||||
for (size_t i = 0; i < headers.size(); i++)
|
||||
{
|
||||
uX = dX + colWidths.at(i) + 20; // 注意这里是 +20,和表体一致
|
||||
uX = dX + colWidths.at(i) + TABLE_COL_GAP; // 注意这里是 +20,和表体一致
|
||||
fillrectangle(dX, dY, uX, uY);
|
||||
outtextxy(dX + 10, dY + 5, LPCTSTR(headers[i].c_str()));
|
||||
dX += colWidths.at(i) + 20; // 列间距 20
|
||||
outtextxy(dX + TABLE_PAD_X, dY + TABLE_PAD_Y, LPCTSTR(headers[i].c_str()));
|
||||
dX += colWidths.at(i) + TABLE_COL_GAP; // 列间距 20
|
||||
}
|
||||
}
|
||||
// 遍历所有数据单元和表头,计算每列的最大宽度和每行的最大高度,
|
||||
@@ -51,9 +51,9 @@ void Table::drawHeader()
|
||||
void Table::initTextWaH()
|
||||
{
|
||||
// 和绘制一致的单元内边距
|
||||
const int padX = 10; // 左右 padding
|
||||
const int padY = 5; // 上下 padding
|
||||
const int colGap = 20; // 列间距
|
||||
const int padX = TABLE_PAD_X; // 左右 padding
|
||||
const int padY = TABLE_PAD_Y; // 上下 padding
|
||||
const int colGap = TABLE_COL_GAP; // 列间距
|
||||
const int border = tableBorderWidth > 0 ? tableBorderWidth : 0;
|
||||
|
||||
// 统计每列最大文本宽 & 每列最大行高(包含数据 + 表头)
|
||||
@@ -101,9 +101,9 @@ void Table::initTextWaH()
|
||||
// 页脚:
|
||||
const int pageTextH = textheight(LPCTSTR(pageNumtext.c_str()));
|
||||
const int btnTextH = textheight(LPCTSTR("上一页"));
|
||||
const int btnPadV = 8;
|
||||
const int btnPadV = TABLE_BTN_TEXT_PAD_V;
|
||||
const int btnH = btnTextH + 2 * btnPadV;
|
||||
const int footerPad = 16;
|
||||
const int footerPad = TABLE_FOOTER_PAD;
|
||||
const int footerH = (pageTextH > btnH ? pageTextH : btnH) + footerPad;
|
||||
|
||||
// 最终表宽/高:内容 + 对称边框
|
||||
@@ -113,16 +113,16 @@ void Table::initTextWaH()
|
||||
|
||||
void Table::initButton()
|
||||
{
|
||||
const int gap = 12; // 页码与按钮之间的固定间距
|
||||
const int padH = 12; // 按钮水平内边距
|
||||
const int padV = 0; // 按钮垂直内边距
|
||||
const int gap = TABLE_BTN_GAP;
|
||||
const int padH = TABLE_BTN_PAD_H;
|
||||
const int padV = TABLE_BTN_PAD_V; // 按钮垂直内边距
|
||||
|
||||
int pageW = textwidth(LPCTSTR(pageNumtext.c_str()));
|
||||
int lblH = textheight(LPCTSTR(pageNumtext.c_str()));
|
||||
|
||||
// 统一按钮尺寸(用按钮文字自身宽高 + padding)
|
||||
int prevW = textwidth(LPCTSTR("上一页")) + padH * 2;
|
||||
int nextW = textwidth(LPCTSTR("下一页")) + padH * 2;
|
||||
int prevW = textwidth(LPCTSTR(TABLE_STR_PREV)) + padH * 2;
|
||||
int nextW = textwidth(LPCTSTR(TABLE_STR_NEXT)) + padH * 2;
|
||||
int btnH = lblH + padV * 2;
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ void Table::initButton()
|
||||
int btnY = pY; // 和页码同一基线
|
||||
|
||||
if (!prevButton)
|
||||
prevButton = new Button(prevX, btnY, prevW, btnH, "上一页", RGB(0, 0, 0), RGB(255, 255, 255));
|
||||
prevButton = new Button(prevX, btnY, prevW, btnH, TABLE_STR_PREV, RGB(0, 0, 0), RGB(255, 255, 255));
|
||||
else
|
||||
{
|
||||
prevButton->setX(prevX);
|
||||
@@ -141,7 +141,7 @@ void Table::initButton()
|
||||
}
|
||||
|
||||
if (!nextButton)
|
||||
nextButton = new Button(nextX, btnY, nextW, btnH, "下一页", RGB(0, 0, 0), RGB(255, 255, 255));
|
||||
nextButton = new Button(nextX, btnY, nextW, btnH, TABLE_STR_NEXT, RGB(0, 0, 0), RGB(255, 255, 255));
|
||||
else
|
||||
{
|
||||
nextButton->setX(nextX);
|
||||
@@ -178,20 +178,20 @@ void Table::initPageNum()
|
||||
// 统一坐标系
|
||||
const int border = tableBorderWidth > 0 ? tableBorderWidth : 0;
|
||||
const int baseH = lineHeights.empty() ? 0 : lineHeights.at(0);
|
||||
const int headerH = baseH + 10;
|
||||
const int rowsH = baseH * rowsPerPage + rowsPerPage * 10;
|
||||
const int headerH = baseH + TABLE_HEADER_EXTRA;
|
||||
const int rowsH = baseH * rowsPerPage + rowsPerPage * TABLE_ROW_EXTRA;
|
||||
|
||||
// 内容宽度 = sum(colWidths + 20);initTextWaH() 已把 this->width += 2*border
|
||||
// 因此 contentW = this->width - 2*border 更稳妥
|
||||
const int contentW = this->width - (border << 1);
|
||||
|
||||
// 页脚顶部位置(表头 + 可视数据区 之后)
|
||||
pY = y + border + headerH + rowsH + 8; // +8 顶部留白
|
||||
pY = y + border + headerH + rowsH + TABLE_FOOTER_BLANK; // +8 顶部留白
|
||||
|
||||
// 按理来说 x + (this->width - textW) / 2;就可以
|
||||
// 但是在绘制时,发现控件偏右,因此减去40
|
||||
int textW = textwidth(LPCTSTR(pageNumtext.c_str()));
|
||||
pX = x - 40 +(this->width - textW) / 2;
|
||||
pX = x + TABLE_PAGE_TEXT_OFFSET_X +(this->width - textW) / 2;
|
||||
|
||||
if (!pageNum)
|
||||
pageNum = new Label(pX, pY, pageNumtext);
|
||||
@@ -217,6 +217,7 @@ void Table::drawPageNum()
|
||||
if (nullptr == pageNum)
|
||||
initPageNum();
|
||||
pageNum->setText(pageNumtext);
|
||||
pageNum->textStyle = this->textStyle;
|
||||
if (StellarX::FillMode::Null == tableFillMode)
|
||||
pageNum->setTextdisap(true);
|
||||
pageNum->draw();
|
||||
@@ -244,6 +245,7 @@ void Table::drawButton()
|
||||
Table::Table(int x, int y)
|
||||
:Control(x, y, 0, 0)
|
||||
{
|
||||
this->id = "Table";
|
||||
}
|
||||
|
||||
Table::~Table()
|
||||
@@ -264,6 +266,28 @@ Table::~Table()
|
||||
|
||||
void Table::draw()
|
||||
{
|
||||
//在这里先初始化保证翻页按钮不为空
|
||||
// 在一些容器中,Table不会被立即绘制可能导致事件事件传递时触发空指针警报
|
||||
// 由于单元格初始化依赖字体数据所以先设置一次字体样式
|
||||
// 先保存当前绘图状态
|
||||
saveStyle();
|
||||
|
||||
// 设置表格样式
|
||||
setfillcolor(tableBkClor);
|
||||
setlinecolor(tableBorderClor);
|
||||
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
|
||||
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
|
||||
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut);
|
||||
settextcolor(textStyle.color);
|
||||
setlinestyle((int)tableLineStyle, tableBorderWidth);
|
||||
setfillstyle((int)tableFillMode);
|
||||
// 是否需要计算单元格尺寸
|
||||
if (isNeedCellSize)
|
||||
{
|
||||
initTextWaH();
|
||||
isNeedCellSize = false;
|
||||
}
|
||||
restoreStyle();
|
||||
if (this->dirty && this->show)
|
||||
{
|
||||
// 先保存当前绘图状态
|
||||
@@ -280,13 +304,6 @@ void Table::draw()
|
||||
setfillstyle((int)tableFillMode);
|
||||
setbkmode(TRANSPARENT);
|
||||
|
||||
// 是否需要计算单元格尺寸
|
||||
if (isNeedCellSize)
|
||||
{
|
||||
initTextWaH();
|
||||
isNeedCellSize = false;
|
||||
}
|
||||
|
||||
if (isNeedDrawHeaders)
|
||||
{
|
||||
// 重新设置表格样式
|
||||
@@ -302,27 +319,25 @@ void Table::draw()
|
||||
}
|
||||
//确保在绘制任何表格内容之前捕获背景
|
||||
// 临时恢复样式,确保捕获正确的背景
|
||||
if (!saveBkImage)
|
||||
if ((!hasSnap) || (saveWidth != this->width) || (saveHeight != this->height)||!saveBkImage)
|
||||
saveBackground(this->x, this->y, this->width, this->height);
|
||||
// 恢复背景(清除旧内容)
|
||||
restBackground();
|
||||
// 绘制表头
|
||||
|
||||
dX = x;
|
||||
dY = y;
|
||||
drawHeader();
|
||||
this->isNeedDrawHeaders = false;
|
||||
|
||||
|
||||
dX = x;
|
||||
dY = y;
|
||||
drawHeader();
|
||||
this->isNeedDrawHeaders = false;
|
||||
// 绘制当前页
|
||||
drawTable();
|
||||
|
||||
// 绘制页码标签
|
||||
drawPageNum();
|
||||
|
||||
// 绘制翻页按钮
|
||||
if (this->isShowPageButton)
|
||||
drawButton();
|
||||
|
||||
|
||||
// 恢复绘图状态
|
||||
restoreStyle();
|
||||
@@ -338,12 +353,12 @@ bool Table::handleEvent(const ExMessage& msg)
|
||||
return consume;
|
||||
else
|
||||
{
|
||||
consume = prevButton->handleEvent(msg);
|
||||
if (!consume)
|
||||
if(prevButton)consume = prevButton->handleEvent(msg);
|
||||
if (nextButton&&!consume)
|
||||
consume = nextButton->handleEvent(msg);
|
||||
}
|
||||
if (dirty)
|
||||
draw();
|
||||
requestRepaint();
|
||||
return consume;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
TextBox::TextBox(int x, int y, int width, int height, std::string text, StellarX::TextBoxmode mode, StellarX::ControlShape shape)
|
||||
:Control(x,y,width,height),text(text), mode(mode), shape(shape)
|
||||
{
|
||||
this->id = "TextBox";
|
||||
}
|
||||
|
||||
void TextBox::draw()
|
||||
@@ -27,7 +28,10 @@ void TextBox::draw()
|
||||
int text_width = textwidth(LPCTSTR(text.c_str()));
|
||||
int text_height = textheight(LPCTSTR(text.c_str()));
|
||||
|
||||
|
||||
if ((saveBkX != this->x) || (saveBkY != this->y) || (!hasSnap) || (saveWidth != this->width) || (saveHeight != this->height) || !saveBkImage)
|
||||
saveBackground(this->x, this->y, this->width, this->height);
|
||||
// 恢复背景(清除旧内容)
|
||||
restBackground();
|
||||
//根据形状绘制
|
||||
switch (shape)
|
||||
{
|
||||
@@ -87,7 +91,7 @@ bool TextBox::handleEvent(const ExMessage& msg)
|
||||
flushmessage(EX_MOUSE | EX_KEY);
|
||||
}
|
||||
if (dirty)
|
||||
draw();
|
||||
requestRepaint();
|
||||
|
||||
if (click)
|
||||
click = false;
|
||||
|
||||
@@ -38,8 +38,8 @@ Window::~Window()
|
||||
|
||||
void Window::draw() {
|
||||
// 使用 EasyX 创建基本窗口
|
||||
hWnd = initgraph(width, height, windowMode);
|
||||
SetWindowText(hWnd, headline.c_str());
|
||||
if (!hWnd)
|
||||
hWnd = initgraph(width, height, windowMode);
|
||||
// **启用窗口拉伸支持**:添加厚边框和最大化按钮样式
|
||||
LONG style = GetWindowLong(hWnd, GWL_STYLE);
|
||||
style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; // 可调整边框,启用最大化/最小化按钮
|
||||
@@ -65,7 +65,8 @@ void Window::draw(std::string imagePath)
|
||||
// 使用指定图片绘制窗口背景(铺满窗口)
|
||||
this->background = new IMAGE(width, height);
|
||||
bkImageFile = imagePath;
|
||||
hWnd = initgraph(width, height, windowMode);
|
||||
if (!hWnd)
|
||||
hWnd = initgraph(width, height, windowMode);
|
||||
SetWindowText(hWnd, headline.c_str());
|
||||
loadimage(background, imagePath.c_str(), width, height, true);
|
||||
putimage(0, 0, background);
|
||||
@@ -200,8 +201,7 @@ int Window::runEventLoop()
|
||||
// 标记所有控件/对话框为脏,确保都补一次背景/外观
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c->setDirty(true);
|
||||
c->updateBackground();
|
||||
c->onWindowResize();
|
||||
c->draw();
|
||||
}
|
||||
for (auto& d : dialogs)
|
||||
@@ -209,7 +209,7 @@ int Window::runEventLoop()
|
||||
auto dd = dynamic_cast<Dialog*>(d.get());
|
||||
dd->setDirty(true);
|
||||
dd->setInitialization(true);
|
||||
dd->draw();
|
||||
d->draw();
|
||||
}
|
||||
needResizeDirty = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user