Update to latest ZWidget
This commit is contained in:
parent
6dd59c7787
commit
d24d5ae2c8
16 changed files with 578 additions and 36 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ public:
|
|||
|
||||
void SetImage(std::shared_ptr<Image> newImage);
|
||||
|
||||
double GetPreferredWidth() const;
|
||||
double GetPreferredHeight() const;
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "widgets/lineedit/lineedit.h"
|
||||
#include "core/utf8reader.h"
|
||||
#include "core/colorf.h"
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 = {};
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue