Update to latest ZWidget

This commit is contained in:
Magnus Norddahl 2024-05-26 00:14:44 +02:00
commit d24d5ae2c8
16 changed files with 578 additions and 36 deletions

View file

@ -41,10 +41,23 @@ public:
// Widget noncontent area
void SetNoncontentSizes(double left, double top, double right, double bottom);
double GetNoncontentLeft() const { return GetStyleDouble("noncontent-left"); }
double GetNoncontentTop() const { return GetStyleDouble("noncontent-top"); }
double GetNoncontentRight() const { return GetStyleDouble("noncontent-right"); }
double GetNoncontentBottom() const { return GetStyleDouble("noncontent-bottom"); }
double GetNoncontentLeft() const { return GridFitSize(GetStyleDouble("noncontent-left")); }
double GetNoncontentTop() const { return GridFitSize(GetStyleDouble("noncontent-top")); }
double GetNoncontentRight() const { return GridFitSize(GetStyleDouble("noncontent-right")); }
double GetNoncontentBottom() const { return GridFitSize(GetStyleDouble("noncontent-bottom")); }
// Get the DPI scale factor for the window the widget is located on
double GetDpiScale() const;
// Align point to the nearest physical screen pixel
double GridFitPoint(double p) const;
Point GridFitPoint(double x, double y) const { return GridFitPoint(Point(x, y)); }
Point GridFitPoint(Point p) const { return Point(GridFitPoint(p.x), GridFitPoint(p.y)); }
// Convert size to exactly covering physical screen pixels
double GridFitSize(double s) const;
Size GridFitSize(double w, double h) const { return GridFitSize(Size(w, h)); }
Size GridFitSize(Size s) const { return Size(GridFitSize(s.width), GridFitSize(s.height)); }
// Widget frame box
Rect GetFrameGeometry() const;
@ -108,7 +121,7 @@ public:
std::string GetClipboardText();
void SetClipboardText(const std::string& text);
Widget* Window();
Widget* Window() const;
Canvas* GetCanvas() const;
Widget* ChildAt(double x, double y) { return ChildAt(Point(x, y)); }
Widget* ChildAt(const Point& pos);

View file

@ -11,6 +11,7 @@ public:
void SetImage(std::shared_ptr<Image> newImage);
double GetPreferredWidth() const;
double GetPreferredHeight() const;
protected:

View file

@ -2,6 +2,13 @@
#pragma once
#include "../../core/widget.h"
#include "../textlabel/textlabel.h"
#include "../imagebox/imagebox.h"
class Menu;
class MenubarItem;
class MenuItem;
class MenuItemSeparator;
class Menubar : public Widget
{
@ -9,6 +16,83 @@ public:
Menubar(Widget* parent);
~Menubar();
MenubarItem* AddItem(std::string text, std::function<void(Menu* menu)> onOpen, bool alignRight = false);
protected:
void OnGeometryChanged() override;
private:
void ShowMenu(MenubarItem* item);
void CloseMenu();
std::vector<MenubarItem*> menuItems;
Menu* openMenu = nullptr;
friend class MenubarItem;
};
class MenubarItem : public Widget
{
public:
MenubarItem(Menubar* menubar, std::string text, bool alignRight);
void SetOpenCallback(std::function<void(Menu* menu)> callback) { onOpen = std::move(callback); }
const std::function<void(Menu* menu)>& GetOpenCallback() const { return onOpen; }
double GetPreferredWidth() const;
bool AlignRight = false;
protected:
void OnPaint(Canvas* canvas) override;
bool OnMouseDown(const Point& pos, InputKey key) override;
bool OnMouseUp(const Point& pos, InputKey key) override;
void OnMouseMove(const Point& pos) override;
void OnMouseLeave() override;
private:
Menubar* menubar = nullptr;
std::function<void(Menu* menu)> onOpen;
std::string text;
};
class Menu : public Widget
{
public:
Menu(Widget* parent);
void SetLeftPosition(const Point& globalPos);
void SetRightPosition(const Point& globalPos);
MenuItem* AddItem(std::shared_ptr<Image> icon, std::string text, std::function<void()> onClick = {});
MenuItemSeparator* AddSeparator();
double GetPreferredWidth() const;
double GetPreferredHeight() const;
protected:
void OnGeometryChanged() override;
std::function<void()> onCloseMenu;
friend class Menubar;
};
class MenuItem : public Widget
{
public:
MenuItem(Widget* parent);
ImageBox* icon = nullptr;
TextLabel* text = nullptr;
protected:
void OnMouseMove(const Point& pos) override;
void OnMouseLeave() override;
void OnGeometryChanged() override;
};
class MenuItemSeparator : public Widget
{
public:
MenuItemSeparator(Widget* parent);
};

View file

@ -118,7 +118,7 @@ public:
class DisplayWindow
{
public:
static std::unique_ptr<DisplayWindow> Create(DisplayWindowHost* windowHost);
static std::unique_ptr<DisplayWindow> Create(DisplayWindowHost* windowHost, bool popupWindow);
static void ProcessEvents();
static void RunLoop();
@ -157,6 +157,9 @@ public:
virtual int GetPixelHeight() const = 0;
virtual double GetDpiScale() const = 0;
virtual Point MapFromGlobal(const Point& pos) const = 0;
virtual Point MapToGlobal(const Point& pos) const = 0;
virtual void SetBorderColor(uint32_t bgra8) = 0;
virtual void SetCaptionColor(uint32_t bgra8) = 0;
virtual void SetCaptionTextColor(uint32_t bgra8) = 0;

View file

@ -765,6 +765,95 @@ void BitmapCanvas::drawGlyph(CanvasTexture* texture, float left, float top, floa
if (x1 <= x0 || y1 <= y0)
return;
#if 1 // Use gamma correction
// To linear
float cred = color.r * color.r; // std::pow(color.r, 2.2f);
float cgreen = color.g * color.g; // std::pow(color.g, 2.2f);
float cblue = color.b * color.b; // std::pow(color.b, 2.2f);
#ifdef USE_SSE2
__m128 crgba = _mm_set_ps(0.0f, cred, cgreen, cblue);
#endif
float uscale = uvwidth / width;
float vscale = uvheight / height;
for (int y = y0; y < y1; y++)
{
float vpix = v + vscale * (y + 0.5f - top);
const uint32_t* sline = src + ((int)vpix) * swidth;
uint32_t* dline = dest + y * dwidth;
int x = x0;
#ifdef USE_SSE2
while (x < x1)
{
float upix = u + uscale * (x + 0.5f - left);
__m128i spixel = _mm_cvtsi32_si128(sline[(int)upix]);
spixel = _mm_unpacklo_epi8(spixel, _mm_setzero_si128());
spixel = _mm_unpacklo_epi16(spixel, _mm_setzero_si128());
__m128 srgba = _mm_mul_ps(_mm_cvtepi32_ps(spixel), _mm_set_ps1(1.0f / 255.0f));
__m128i dpixel = _mm_cvtsi32_si128(dline[x]);
dpixel = _mm_unpacklo_epi8(dpixel, _mm_setzero_si128());
dpixel = _mm_unpacklo_epi16(dpixel, _mm_setzero_si128());
__m128 drgba = _mm_mul_ps(_mm_cvtepi32_ps(dpixel), _mm_set_ps1(1.0f / 255.0f));
// To linear
drgba = _mm_mul_ps(drgba, drgba);
// dest.rgb = color.rgb * src.rgb + dest.rgb * (1-src.rgb)
__m128 frgba = _mm_add_ps(_mm_mul_ps(crgba, srgba), _mm_mul_ps(drgba, _mm_sub_ps(_mm_set_ps1(1.0f), srgba)));
// To srgb
frgba = _mm_sqrt_ps(frgba);
__m128i rgba = _mm_cvtps_epi32(_mm_add_ps(_mm_mul_ps(frgba, _mm_set_ps1(255.0f)), _mm_set_ps1(0.5f)));
rgba = _mm_packs_epi32(rgba, _mm_setzero_si128());
rgba = _mm_packus_epi16(rgba, _mm_setzero_si128());
dline[x] = ((uint32_t)_mm_cvtsi128_si32(rgba)) | 0xff000000;
x++;
}
#else
while (x < x1)
{
float upix = u + uscale * (x + 0.5f - left);
uint32_t spixel = sline[(int)upix];
float sred = ((spixel >> 16) & 0xff) * (1.0f / 255.0f);
float sgreen = ((spixel >> 8) & 0xff) * (1.0f / 255.0f);
float sblue = (spixel & 0xff) * (1.0f / 255.0f);
uint32_t dpixel = dline[x];
float dred = ((dpixel >> 16) & 0xff) * (1.0f / 255.0f);
float dgreen = ((dpixel >> 8) & 0xff) * (1.0f / 255.0f);
float dblue = (dpixel & 0xff) * (1.0f / 255.0f);
// To linear
dred = dred * dred; // std::pow(dred, 2.2f);
dgreen = dgreen * dgreen; // std::pow(dgreen, 2.2f);
dblue = dblue * dblue; // std::pow(dblue, 2.2f);
// dest.rgb = color.rgb * src.rgb + dest.rgb * (1-src.rgb)
double fr = cred * sred + dred * (1.0f - sred);
double fg = cgreen * sgreen + dgreen * (1.0f - sgreen);
double fb = cblue * sblue + dblue * (1.0f - sblue);
// To srgb
fr = std::sqrt(fr); // std::pow(fr, 1.0f / 2.2f);
fg = std::sqrt(fg); // std::pow(fg, 1.0f / 2.2f);
fb = std::sqrt(fb); // std::pow(fb, 1.0f / 2.2f);
uint32_t r = (int)(fr * 255.0f + 0.5f);
uint32_t g = (int)(fg * 255.0f + 0.5f);
uint32_t b = (int)(fb * 255.0f + 0.5f);
dline[x] = 0xff000000 | (r << 16) | (g << 8) | b;
x++;
}
#endif
}
#else
uint32_t cred = (int32_t)clamp(color.r * 255.0f, 0.0f, 255.0f);
uint32_t cgreen = (int32_t)clamp(color.g * 255.0f, 0.0f, 255.0f);
uint32_t cblue = (int32_t)clamp(color.b * 255.0f, 0.0f, 255.0f);
@ -832,6 +921,7 @@ void BitmapCanvas::drawGlyph(CanvasTexture* texture, float left, float top, floa
x++;
}
}
#endif
}
void BitmapCanvas::begin(const Colorf& color)

View file

@ -102,14 +102,16 @@ void BasicWidgetStyle::Paint(Widget* widget, Canvas* canvas, Size size)
Colorf borderright = widget->GetStyleColor("border-right-color");
Colorf borderbottom = widget->GetStyleColor("border-bottom-color");
double borderwidth = widget->GridFitSize(1.0);
if (bordertop.a > 0.0f)
canvas->fillRect(Rect::xywh(0.0, 0.0, size.width, 1.0), bordertop);
canvas->fillRect(Rect::xywh(0.0, 0.0, size.width, borderwidth), bordertop);
if (borderbottom.a > 0.0f)
canvas->fillRect(Rect::xywh(0.0, size.height - 1.0, size.width, 1.0), borderbottom);
canvas->fillRect(Rect::xywh(0.0, size.height - borderwidth, size.width, borderwidth), borderbottom);
if (borderleft.a > 0.0f)
canvas->fillRect(Rect::xywh(0.0, 0.0, 1.0, size.height - 0.0), borderleft);
canvas->fillRect(Rect::xywh(0.0, 0.0, borderwidth, size.height), borderleft);
if (borderright.a > 0.0f)
canvas->fillRect(Rect::xywh(size.width - 1.0, 0.0, 1.0, size.height - 0.0), borderright);
canvas->fillRect(Rect::xywh(size.width - borderwidth, 0.0, borderwidth, size.height), borderright);
}
/////////////////////////////////////////////////////////////////////////////
@ -154,6 +156,9 @@ DarkWidgetTheme::DarkWidgetTheme()
auto tabbar_tab = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "tabbar-tab");
auto tabwidget_stack = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "tabwidget-stack");
auto checkbox_label = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "checkbox-label");
auto menubaritem = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "menubaritem");
auto menu = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "menu");
auto menuitem = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "menuitem");
widget->SetString("font-family", "NotoSans");
widget->SetColor("color", Colorf::fromRgba8(226, 223, 219));
@ -229,6 +234,21 @@ DarkWidgetTheme::DarkWidgetTheme()
checkbox_label->SetColor("checked-color", Colorf::fromRgba8(226, 223, 219));
checkbox_label->SetColor("unchecked-outer-border-color", Colorf::fromRgba8(99, 99, 99));
checkbox_label->SetColor("unchecked-inner-border-color", Colorf::fromRgba8(51, 51, 51));
menubaritem->SetColor("hover", "background-color", Colorf::fromRgba8(78, 78, 78));
menubaritem->SetColor("down", "background-color", Colorf::fromRgba8(88, 88, 88));
menu->SetDouble("noncontent-left", 5.0);
menu->SetDouble("noncontent-top", 5.0);
menu->SetDouble("noncontent-right", 5.0);
menu->SetDouble("noncontent-bottom", 5.0);
menu->SetColor("border-left-color", Colorf::fromRgba8(100, 100, 100));
menu->SetColor("border-top-color", Colorf::fromRgba8(100, 100, 100));
menu->SetColor("border-right-color", Colorf::fromRgba8(100, 100, 100));
menu->SetColor("border-bottom-color", Colorf::fromRgba8(100, 100, 100));
menuitem->SetColor("hover", "background-color", Colorf::fromRgba8(78, 78, 78));
menuitem->SetColor("down", "background-color", Colorf::fromRgba8(88, 88, 88));
}
/////////////////////////////////////////////////////////////////////////////
@ -246,6 +266,9 @@ LightWidgetTheme::LightWidgetTheme()
auto tabbar_tab = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "tabbar-tab");
auto tabwidget_stack = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "tabwidget-stack");
auto checkbox_label = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "checkbox-label");
auto menubaritem = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "menubaritem");
auto menu = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "menu");
auto menuitem = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "menuitem");
widget->SetString("font-family", "NotoSans");
widget->SetColor("color", Colorf::fromRgba8(0, 0, 0));
@ -321,4 +344,19 @@ LightWidgetTheme::LightWidgetTheme()
checkbox_label->SetColor("checked-color", Colorf::fromRgba8(50, 50, 50));
checkbox_label->SetColor("unchecked-outer-border-color", Colorf::fromRgba8(156, 156, 156));
checkbox_label->SetColor("unchecked-inner-border-color", Colorf::fromRgba8(200, 200, 200));
menubaritem->SetColor("hover", "background-color", Colorf::fromRgba8(200, 200, 200));
menubaritem->SetColor("down", "background-color", Colorf::fromRgba8(190, 190, 190));
menu->SetDouble("noncontent-left", 5.0);
menu->SetDouble("noncontent-top", 5.0);
menu->SetDouble("noncontent-right", 5.0);
menu->SetDouble("noncontent-bottom", 5.0);
menu->SetColor("border-left-color", Colorf::fromRgba8(155, 155, 155));
menu->SetColor("border-top-color", Colorf::fromRgba8(155, 155, 155));
menu->SetColor("border-right-color", Colorf::fromRgba8(155, 155, 155));
menu->SetColor("border-bottom-color", Colorf::fromRgba8(155, 155, 155));
menuitem->SetColor("hover", "background-color", Colorf::fromRgba8(200, 200, 200));
menuitem->SetColor("down", "background-color", Colorf::fromRgba8(190, 190, 190));
}

View file

@ -4,12 +4,14 @@
#include "core/colorf.h"
#include "core/theme.h"
#include <stdexcept>
#include <cmath>
#include <algorithm>
Widget::Widget(Widget* parent, WidgetType type) : Type(type)
{
if (type != WidgetType::Child)
{
DispWindow = DisplayWindow::Create(this);
DispWindow = DisplayWindow::Create(this, type == WidgetType::Popup);
DispCanvas = Canvas::create(DispWindow.get());
SetStyleState("root");
@ -167,6 +169,10 @@ void Widget::SetFrameGeometry(const Rect& geometry)
top = std::min(top, FrameGeometry.bottom());
right = std::max(right, FrameGeometry.left());
bottom = std::max(bottom, FrameGeometry.top());
left = GridFitPoint(left);
top = GridFitPoint(top);
right = GridFitPoint(right);
bottom = GridFitPoint(bottom);
ContentGeometry = Rect::ltrb(left, top, right, bottom);
OnGeometryChanged();
}
@ -458,12 +464,12 @@ void Widget::SetClipboardText(const std::string& text)
w->DispWindow->SetClipboardText(text);
}
Widget* Widget::Window()
Widget* Widget::Window() const
{
for (Widget* w = this; w != nullptr; w = w->Parent())
for (const Widget* w = this; w != nullptr; w = w->Parent())
{
if (w->DispWindow)
return w;
return const_cast<Widget*>(w);
}
return nullptr;
}
@ -510,7 +516,7 @@ Point Widget::MapFromGlobal(const Point& pos) const
{
if (cur->DispWindow)
{
return p - cur->GetFrameGeometry().topLeft();
return cur->DispWindow->MapFromGlobal(p);
}
p -= cur->ContentGeometry.topLeft();
}
@ -536,7 +542,7 @@ Point Widget::MapToGlobal(const Point& pos) const
{
if (cur->DispWindow)
{
return cur->GetFrameGeometry().topLeft() + p;
return cur->DispWindow->MapToGlobal(p);
}
p += cur->ContentGeometry.topLeft();
}
@ -705,9 +711,21 @@ void Widget::OnWindowKeyUp(InputKey key)
void Widget::OnWindowGeometryChanged()
{
if (!DispWindow)
return;
Size size = DispWindow->GetClientSize();
FrameGeometry = Rect::xywh(0.0, 0.0, size.width, size.height);
ContentGeometry = FrameGeometry;
double left = FrameGeometry.left() + GetNoncontentLeft();
double top = FrameGeometry.top() + GetNoncontentTop();
double right = FrameGeometry.right() - GetNoncontentRight();
double bottom = FrameGeometry.bottom() - GetNoncontentBottom();
left = std::min(left, FrameGeometry.right());
top = std::min(top, FrameGeometry.bottom());
right = std::max(right, FrameGeometry.left());
bottom = std::max(bottom, FrameGeometry.top());
ContentGeometry = Rect::ltrb(left, top, right, bottom);
OnGeometryChanged();
}
@ -728,6 +746,26 @@ void Widget::OnWindowDpiScaleChanged()
{
}
double Widget::GetDpiScale() const
{
Widget* w = Window();
return w ? w->DispWindow->GetDpiScale() : 1.0;
}
double Widget::GridFitPoint(double p) const
{
double dpiscale = GetDpiScale();
return std::round(p * dpiscale) / dpiscale;
}
double Widget::GridFitSize(double s) const
{
if (s <= 0.0)
return 0.0;
double dpiscale = GetDpiScale();
return std::max(std::floor(s * dpiscale + 0.25), 1.0) / dpiscale;
}
Size Widget::GetScreenSize()
{
return DisplayWindow::GetScreenSize();

View file

@ -41,16 +41,24 @@ double CheckboxLabel::GetPreferredHeight() const
void CheckboxLabel::OnPaint(Canvas* canvas)
{
// To do: add and use GetStyleImage for the checkbox
double center = GridFitPoint(GetHeight() * 0.5);
double borderwidth = GridFitSize(1.0);
double outerboxsize = GridFitSize(10.0);
double innerboxsize = outerboxsize - 2.0 * borderwidth;
double checkedsize = innerboxsize - 2.0 * borderwidth;
if (checked)
{
canvas->fillRect(Rect::xywh(0.0, GetHeight() * 0.5 - 6.0, 10.0, 10.0), GetStyleColor("checked-outer-border-color"));
canvas->fillRect(Rect::xywh(1.0, GetHeight() * 0.5 - 5.0, 8.0, 8.0), GetStyleColor("checked-inner-border-color"));
canvas->fillRect(Rect::xywh(2.0, GetHeight() * 0.5 - 4.0, 6.0, 6.0), GetStyleColor("checked-color"));
canvas->fillRect(Rect::xywh(0.0, center - 6.0 * borderwidth, outerboxsize, outerboxsize), GetStyleColor("checked-outer-border-color"));
canvas->fillRect(Rect::xywh(1.0 * borderwidth, center - 5.0 * borderwidth, innerboxsize, innerboxsize), GetStyleColor("checked-inner-border-color"));
canvas->fillRect(Rect::xywh(2.0 * borderwidth, center - 4.0 * borderwidth, checkedsize, checkedsize), GetStyleColor("checked-color"));
}
else
{
canvas->fillRect(Rect::xywh(0.0, GetHeight() * 0.5 - 6.0, 10.0, 10.0), GetStyleColor("unchecked-outer-border-color"));
canvas->fillRect(Rect::xywh(1.0, GetHeight() * 0.5 - 5.0, 8.0, 8.0), GetStyleColor("unchecked-inner-border-color"));
canvas->fillRect(Rect::xywh(0.0, center - 6.0 * borderwidth, outerboxsize, outerboxsize), GetStyleColor("unchecked-outer-border-color"));
canvas->fillRect(Rect::xywh(1.0 * borderwidth, center - 5.0 * borderwidth, innerboxsize, innerboxsize), GetStyleColor("unchecked-inner-border-color"));
}
canvas->drawText(Point(14.0, GetHeight() - 5.0), GetStyleColor("color"), text);

View file

@ -5,6 +5,14 @@ ImageBox::ImageBox(Widget* parent) : Widget(parent)
{
}
double ImageBox::GetPreferredWidth() const
{
if (image)
return (double)image->GetWidth();
else
return 0.0;
}
double ImageBox::GetPreferredHeight() const
{
if (image)

View file

@ -1,4 +1,4 @@
#include <algorithm>
#include "widgets/lineedit/lineedit.h"
#include "core/utf8reader.h"
#include "core/colorf.h"

View file

@ -4,13 +4,214 @@
Menubar::Menubar(Widget* parent) : Widget(parent)
{
SetStyleClass("menubar");
}
Menubar::~Menubar()
{
}
void Menubar::OnPaint(Canvas* canvas)
MenubarItem* Menubar::AddItem(std::string text, std::function<void(Menu* menu)> onOpen, bool alignRight)
{
canvas->drawText(Point(16.0, 21.0), Colorf::fromRgba8(0, 0, 0), "File Edit View Tools Window Help");
auto item = new MenubarItem(this, text, alignRight);
item->SetOpenCallback(std::move(onOpen));
menuItems.push_back(item);
OnGeometryChanged();
return item;
}
void Menubar::ShowMenu(MenubarItem* item)
{
CloseMenu();
if (item->GetOpenCallback())
{
openMenu = new Menu(this);
openMenu->onCloseMenu = [=]() { CloseMenu(); };
item->GetOpenCallback()(openMenu);
if (item->AlignRight)
openMenu->SetRightPosition(item->MapToGlobal(Point(item->GetWidth(), item->GetHeight())));
else
openMenu->SetLeftPosition(item->MapToGlobal(Point(0.0, item->GetHeight())));
openMenu->Show();
}
}
void Menubar::CloseMenu()
{
//delete openMenu;
//openMenu = nullptr;
}
void Menubar::OnGeometryChanged()
{
double w = GetWidth();
double h = GetHeight();
double left = 0.0;
double right = w;
for (MenubarItem* item : menuItems)
{
double itemwidth = item->GetPreferredWidth();
itemwidth += 16.0;
if (!item->AlignRight)
{
item->SetFrameGeometry(left, 0.0, itemwidth, h);
left += itemwidth;
}
else
{
right -= itemwidth;
item->SetFrameGeometry(right, 0.0, itemwidth, h);
}
}
}
/////////////////////////////////////////////////////////////////////////////
MenubarItem::MenubarItem(Menubar* menubar, std::string text, bool alignRight) : Widget(menubar), menubar(menubar), text(text), AlignRight(alignRight)
{
SetStyleClass("menubaritem");
}
bool MenubarItem::OnMouseDown(const Point& pos, InputKey key)
{
menubar->ShowMenu(this);
return true;
}
bool MenubarItem::OnMouseUp(const Point& pos, InputKey key)
{
return true;
}
void MenubarItem::OnMouseMove(const Point& pos)
{
if (GetStyleState().empty())
{
SetStyleState("hover");
}
}
void MenubarItem::OnMouseLeave()
{
SetStyleState("");
}
double MenubarItem::GetPreferredWidth() const
{
Canvas* canvas = GetCanvas();
return canvas->measureText(text).width;
}
void MenubarItem::OnPaint(Canvas* canvas)
{
double x = (GetWidth() - canvas->measureText(text).width) * 0.5;
canvas->drawText(Point(x, 21.0), GetStyleColor("color"), text);
}
/////////////////////////////////////////////////////////////////////////////
Menu::Menu(Widget* parent) : Widget(parent, WidgetType::Popup)
{
SetStyleClass("menu");
}
void Menu::SetLeftPosition(const Point& pos)
{
SetFrameGeometry(Rect::xywh(pos.x, pos.y, GetPreferredWidth() + GetNoncontentLeft() + GetNoncontentRight(), GetPreferredHeight() + GetNoncontentTop() + GetNoncontentBottom()));
}
void Menu::SetRightPosition(const Point& pos)
{
SetFrameGeometry(Rect::xywh(pos.x - GetWidth() - GetNoncontentLeft() - GetNoncontentRight(), pos.y, GetWidth() + GetNoncontentLeft() + GetNoncontentRight(), GetHeight() + GetNoncontentTop() + GetNoncontentBottom()));
}
MenuItem* Menu::AddItem(std::shared_ptr<Image> icon, std::string text, std::function<void()> onClick)
{
auto item = new MenuItem(this);
if (icon)
item->icon->SetImage(icon);
item->text->SetText(text);
/*
item->element->addEventListener("click", [=](Event* event)
{
event->stopPropagation();
if (onCloseMenu)
onCloseMenu();
if (onClick)
onClick();
});
*/
return item;
}
MenuItemSeparator* Menu::AddSeparator()
{
auto sep = new MenuItemSeparator(this);
return sep;
}
double Menu::GetPreferredWidth() const
{
return 200.0;
}
double Menu::GetPreferredHeight() const
{
double h = 0.0;
for (Widget* item = FirstChild(); item != nullptr; item = item->NextSibling())
{
h += 20.0;
}
return h;
}
void Menu::OnGeometryChanged()
{
double w = GetWidth();
double h = GetHeight();
double y = 0.0;
for (Widget* item = FirstChild(); item != nullptr; item = item->NextSibling())
{
item->SetFrameGeometry(Rect::xywh(0.0, y, w, 20.0));
y += 20.0;
}
}
/////////////////////////////////////////////////////////////////////////////
MenuItem::MenuItem(Widget* parent) : Widget(parent)
{
SetStyleClass("menuitem");
icon = new ImageBox(this);
text = new TextLabel(this);
}
void MenuItem::OnMouseMove(const Point& pos)
{
if (GetStyleState().empty())
{
SetStyleState("hover");
}
}
void MenuItem::OnMouseLeave()
{
SetStyleState("");
}
void MenuItem::OnGeometryChanged()
{
double iconwidth = icon->GetPreferredWidth();
double iconheight = icon->GetPreferredHeight();
double w = GetWidth();
double h = GetHeight();
icon->SetFrameGeometry(Rect::xywh(0.0, (h - iconheight) * 0.5, iconwidth, iconheight));
text->SetFrameGeometry(Rect::xywh(iconwidth, 0.0, w - iconwidth, h));
}
/////////////////////////////////////////////////////////////////////////////
MenuItemSeparator::MenuItemSeparator(Widget* parent) : Widget(parent)
{
SetStyleClass("menuitemseparator");
}

View file

@ -24,11 +24,14 @@ static void CheckInitSDL()
static InitSDL initsdl;
}
SDL2DisplayWindow::SDL2DisplayWindow(DisplayWindowHost* windowHost) : WindowHost(windowHost)
SDL2DisplayWindow::SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow) : WindowHost(windowHost)
{
CheckInitSDL();
int result = SDL_CreateWindowAndRenderer(320, 200, SDL_WINDOW_HIDDEN /*| SDL_WINDOW_ALLOW_HIGHDPI*/, &WindowHandle, &RendererHandle);
unsigned int flags = SDL_WINDOW_HIDDEN /*| SDL_WINDOW_ALLOW_HIGHDPI*/;
if (popupWindow)
flags |= SDL_WINDOW_BORDERLESS;
int result = SDL_CreateWindowAndRenderer(320, 200, flags, &WindowHandle, &RendererHandle);
if (result != 0)
throw std::runtime_error(std::string("Unable to create SDL window:") + SDL_GetError());
@ -174,6 +177,24 @@ Rect SDL2DisplayWindow::GetWindowFrame() const
return Rect::xywh(x / uiscale, y / uiscale, w / uiscale, h / uiscale);
}
Point SDL2DisplayWindow::MapFromGlobal(const Point& pos) const
{
int x = 0;
int y = 0;
double uiscale = GetDpiScale();
SDL_GetWindowPosition(WindowHandle, &x, &y);
return Point(pos.x - x / uiscale, pos.y - y / uiscale);
}
Point SDL2DisplayWindow::MapToGlobal(const Point& pos) const
{
int x = 0;
int y = 0;
double uiscale = GetDpiScale();
SDL_GetWindowPosition(WindowHandle, &x, &y);
return Point(pos.x + x / uiscale, pos.y + y / uiscale);
}
Size SDL2DisplayWindow::GetClientSize() const
{
int w = 0;

View file

@ -8,7 +8,7 @@
class SDL2DisplayWindow : public DisplayWindow
{
public:
SDL2DisplayWindow(DisplayWindowHost* windowHost);
SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow);
~SDL2DisplayWindow();
void SetWindowTitle(const std::string& text) override;
@ -45,6 +45,9 @@ public:
std::string GetClipboardText() override;
void SetClipboardText(const std::string& text) override;
Point MapFromGlobal(const Point& pos) const override;
Point MapToGlobal(const Point& pos) const override;
void* GetNativeHandle() override { return WindowHandle; }
static void DispatchEvent(const SDL_Event& event);

View file

@ -56,7 +56,7 @@ static std::wstring to_utf16(const std::string& str)
return result;
}
Win32DisplayWindow::Win32DisplayWindow(DisplayWindowHost* windowHost) : WindowHost(windowHost)
Win32DisplayWindow::Win32DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow) : WindowHost(windowHost)
{
Windows.push_front(this);
WindowsIterator = Windows.begin();
@ -74,7 +74,18 @@ Win32DisplayWindow::Win32DisplayWindow(DisplayWindowHost* windowHost) : WindowHo
// WS_CAPTION shows the caption (yay! actually a flag that does what it says it does!)
// WS_SYSMENU shows the min/max/close buttons
// WS_THICKFRAME makes the window resizable
CreateWindowEx(WS_EX_APPWINDOW | WS_EX_DLGMODALFRAME, L"ZWidgetWindow", L"", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0, 0, 100, 100, 0, 0, GetModuleHandle(0), this);
DWORD style = 0, exstyle = 0;
if (popupWindow)
{
style = WS_POPUP;
}
else
{
exstyle = WS_EX_APPWINDOW | WS_EX_DLGMODALFRAME;
style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
}
CreateWindowEx(exstyle, L"ZWidgetWindow", L"", style, 0, 0, 100, 100, 0, 0, GetModuleHandle(0), this);
/*
RAWINPUTDEVICE rid;
@ -246,6 +257,26 @@ Rect Win32DisplayWindow::GetWindowFrame() const
return Rect(box.left / dpiscale, box.top / dpiscale, box.right / dpiscale, box.bottom / dpiscale);
}
Point Win32DisplayWindow::MapFromGlobal(const Point& pos) const
{
double dpiscale = GetDpiScale();
POINT point = {};
point.x = (LONG)std::round(pos.x / dpiscale);
point.y = (LONG)std::round(pos.y / dpiscale);
ScreenToClient(WindowHandle, &point);
return Point(point.x * dpiscale, point.y * dpiscale);
}
Point Win32DisplayWindow::MapToGlobal(const Point& pos) const
{
double dpiscale = GetDpiScale();
POINT point = {};
point.x = (LONG)std::round(pos.x * dpiscale);
point.y = (LONG)std::round(pos.y * dpiscale);
ClientToScreen(WindowHandle, &point);
return Point(point.x / dpiscale, point.y / dpiscale);
}
Size Win32DisplayWindow::GetClientSize() const
{
RECT box = {};

View file

@ -14,7 +14,7 @@
class Win32DisplayWindow : public DisplayWindow
{
public:
Win32DisplayWindow(DisplayWindowHost* windowHost);
Win32DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow);
~Win32DisplayWindow();
void SetWindowTitle(const std::string& text) override;
@ -53,6 +53,9 @@ public:
std::string GetClipboardText() override;
void SetClipboardText(const std::string& text) override;
Point MapFromGlobal(const Point& pos) const override;
Point MapToGlobal(const Point& pos) const override;
Point GetLParamPos(LPARAM lparam) const;
void* GetNativeHandle() override { return reinterpret_cast<void*>(WindowHandle); }

View file

@ -6,9 +6,9 @@
#include "win32/win32displaywindow.h"
std::unique_ptr<DisplayWindow> DisplayWindow::Create(DisplayWindowHost* windowHost)
std::unique_ptr<DisplayWindow> DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow)
{
return std::make_unique<Win32DisplayWindow>(windowHost);
return std::make_unique<Win32DisplayWindow>(windowHost, popupWindow);
}
void DisplayWindow::ProcessEvents()
@ -43,7 +43,7 @@ void DisplayWindow::StopTimer(void* timerID)
#elif defined(__APPLE__)
std::unique_ptr<DisplayWindow> DisplayWindow::Create(DisplayWindowHost* windowHost)
std::unique_ptr<DisplayWindow> DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow)
{
throw std::runtime_error("DisplayWindow::Create not implemented");
}
@ -82,9 +82,9 @@ void DisplayWindow::StopTimer(void* timerID)
#include "sdl2/sdl2displaywindow.h"
std::unique_ptr<DisplayWindow> DisplayWindow::Create(DisplayWindowHost* windowHost)
std::unique_ptr<DisplayWindow> DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow)
{
return std::make_unique<SDL2DisplayWindow>(windowHost);
return std::make_unique<SDL2DisplayWindow>(windowHost, popupWindow);
}
void DisplayWindow::ProcessEvents()