Squashed 'libraries/ZWidget/' changes from cecd34301d..924b8e0e78
924b8e0e78 Fix scroll size issue f0344ed99b Add option to hide scrollbar when no scrolling is to be had f7b01d6625 Remove stray sdl 214d098353 Theme role improvements 82d0431ca5 Textedit highlight now follows theme 373ab3f4ca Added hex Colorf alias 5ea6d5a62a Reduced duplicate code a92e045b18 Simplified theme d076c9991c Expanded example e4556c97df Named colors 6d9300c742 Fix COM thread error 6499e5c523 Add null pointer checks f9d5724210 Fix x11 backend locking up Implement raw mouse input support (XInput 2.0) Fix x11 DPI scaling 4a86fb5056 XInitThreads must be called when using vulkan 8095090774 Add DPI scale to X11 backend 02fb328172 Mute a bunch of warnings f13c745a63 Fix typo 5689bf5edd Merge in changes from SurrealEngine Use C++20 Make SDL2 optional git-subtree-dir: libraries/ZWidget git-subtree-split: 924b8e0e786093708c0d73419a347f8e6ffe55d6
This commit is contained in:
parent
6356d87438
commit
87689ccb5f
27 changed files with 880 additions and 524 deletions
|
|
@ -17,6 +17,14 @@ if (UNIX AND NOT APPLE)
|
|||
)
|
||||
endif()
|
||||
|
||||
# SDL2 finding stuff
|
||||
# Optional on all platforms
|
||||
find_package(SDL2 QUIET)
|
||||
if(NOT ${SDL2_FOUND})
|
||||
include(FindPkgConfig)
|
||||
pkg_search_module(SDL2 sdl2)
|
||||
endif()
|
||||
|
||||
set(ZWIDGET_SOURCES
|
||||
src/core/canvas.cpp
|
||||
src/core/font.cpp
|
||||
|
|
@ -226,11 +234,12 @@ elseif(APPLE)
|
|||
set(ZWIDGET_DEFINES -DUNIX -D_UNIX)
|
||||
set(ZWIDGET_LINK_OPTIONS -pthread)
|
||||
else()
|
||||
set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_SDL2_SOURCES} ${ZWIDGET_X11_SOURCES})
|
||||
set(ZWIDGET_LIBS ${CMAKE_DL_LIBS} -ldl -lX11)
|
||||
set(ZWIDGET_DEFINES -DUNIX -D_UNIX -DUSE_SDL2 -DUSE_X11)
|
||||
set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_X11_SOURCES})
|
||||
set(ZWIDGET_LIBS ${CMAKE_DL_LIBS} -lX11 -lXi)
|
||||
set(ZWIDGET_DEFINES -DUNIX -D_UNIX -DUSE_X11)
|
||||
set(ZWIDGET_LINK_OPTIONS -pthread)
|
||||
if (DBUS_FOUND)
|
||||
include_directories("/usr/lib64/dbus-1.0/include") # Bazzite (and probably Fedora 42) keeps the platform-specific dbus headers in this folder
|
||||
set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_DBUS_SOURCES})
|
||||
set(ZWIDGET_INCLUDE_DIRS ${ZWIDGET_INCLUDE_DIRS} ${DBUS_INCLUDE_DIRS})
|
||||
set(ZWIDGET_LIBS ${ZWIDGET_LIBS} ${DBUS_LDFLAGS})
|
||||
|
|
@ -244,10 +253,16 @@ else()
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(SDL2_FOUND)
|
||||
set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_SDL2_SOURCES})
|
||||
set(ZWIDGET_LIBS ${ZWIDGET_LIBS} ${SDL2_LIBRARIES} -lSDL2)
|
||||
set(ZWIDGET_DEFINES ${ZWIDGET_DEFINES} -DUSE_SDL2)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set(CXX_WARNING_FLAGS /W3)
|
||||
set(CXX_WARNING_FLAGS /W3)
|
||||
else()
|
||||
set(CXX_WARNING_FLAGS -Wall -Wpedantic)
|
||||
set(CXX_WARNING_FLAGS -Wall -Wpedantic)
|
||||
endif()
|
||||
|
||||
add_library(zwidget STATIC ${ZWIDGET_SOURCES} ${ZWIDGET_INCLUDES})
|
||||
|
|
@ -256,7 +271,7 @@ target_compile_definitions(zwidget PRIVATE ${ZWIDGET_DEFINES})
|
|||
target_include_directories(zwidget PRIVATE ${ZWIDGET_INCLUDE_DIRS})
|
||||
target_link_options(zwidget PRIVATE ${ZWIDGET_LINK_OPTIONS})
|
||||
target_link_libraries(zwidget ${ZWIDGET_LIBS})
|
||||
set_target_properties(zwidget PROPERTIES CXX_STANDARD 17)
|
||||
set_target_properties(zwidget PROPERTIES CXX_STANDARD 20)
|
||||
target_compile_options(zwidget PRIVATE ${CXX_WARNING_FLAGS})
|
||||
|
||||
if(MSVC)
|
||||
|
|
@ -275,7 +290,7 @@ if(ZWIDGET_BUILD_EXAMPLE)
|
|||
example/picopng.cpp
|
||||
example/picopng.h
|
||||
)
|
||||
target_compile_options(zwidget_example PRIVATE ${CXX_WARNING_FLAGS})
|
||||
target_compile_options(zwidget_example PRIVATE ${CXX_WARNING_FLAGS})
|
||||
|
||||
add_custom_command(
|
||||
TARGET zwidget_example POST_BUILD
|
||||
|
|
@ -296,10 +311,10 @@ if(ZWIDGET_BUILD_EXAMPLE)
|
|||
elseif(APPLE)
|
||||
target_link_libraries(zwidget_example PRIVATE "-framework Cocoa -framework OpenGL")
|
||||
else()
|
||||
target_link_libraries(zwidget_example PRIVATE ${ZWIDGET_LIBS} SDL2::SDL2)
|
||||
target_link_libraries(zwidget_example PRIVATE ${ZWIDGET_LIBS})
|
||||
endif()
|
||||
|
||||
set_target_properties(zwidget_example PROPERTIES CXX_STANDARD 17)
|
||||
set_target_properties(zwidget_example PROPERTIES CXX_STANDARD 20)
|
||||
|
||||
if(MSVC)
|
||||
set_property(TARGET zwidget_example PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
|
|
|||
|
|
@ -13,136 +13,29 @@
|
|||
#include <zwidget/widgets/pushbutton/pushbutton.h>
|
||||
#include <zwidget/widgets/checkboxlabel/checkboxlabel.h>
|
||||
#include "picopng.h"
|
||||
#include <zwidget/widgets/tabwidget/tabwidget.h>
|
||||
|
||||
// ************************************************************
|
||||
// Prototypes
|
||||
// ************************************************************
|
||||
|
||||
static std::vector<uint8_t> ReadAllBytes(const std::string& filename);
|
||||
|
||||
class LauncherWindow : public Widget
|
||||
class LauncherWindowTab1 : public Widget
|
||||
{
|
||||
public:
|
||||
LauncherWindow() : Widget(nullptr, WidgetType::Window)
|
||||
{
|
||||
Logo = new ImageBox(this);
|
||||
WelcomeLabel = new TextLabel(this);
|
||||
VersionLabel = new TextLabel(this);
|
||||
SelectLabel = new TextLabel(this);
|
||||
GeneralLabel = new TextLabel(this);
|
||||
ExtrasLabel = new TextLabel(this);
|
||||
FullscreenCheckbox = new CheckboxLabel(this);
|
||||
DisableAutoloadCheckbox = new CheckboxLabel(this);
|
||||
DontAskAgainCheckbox = new CheckboxLabel(this);
|
||||
LightsCheckbox = new CheckboxLabel(this);
|
||||
BrightmapsCheckbox = new CheckboxLabel(this);
|
||||
WidescreenCheckbox = new CheckboxLabel(this);
|
||||
PlayButton = new PushButton(this);
|
||||
ExitButton = new PushButton(this);
|
||||
GamesList = new ListView(this);
|
||||
Choices = new Dropdown(this);
|
||||
LauncherWindowTab1(Widget parent);
|
||||
void OnGeometryChanged() override;
|
||||
private:
|
||||
TextEdit* Text = nullptr;
|
||||
};
|
||||
|
||||
SetWindowBackground(Colorf::fromRgba8(51, 51, 51));
|
||||
SetWindowBorderColor(Colorf::fromRgba8(51, 51, 51));
|
||||
SetWindowCaptionColor(Colorf::fromRgba8(33, 33, 33));
|
||||
SetWindowCaptionTextColor(Colorf::fromRgba8(226, 223, 219));
|
||||
SetWindowTitle("VKDoom Launcher");
|
||||
|
||||
WelcomeLabel->SetText("Welcome to VKDoom");
|
||||
VersionLabel->SetText("Version 0xdeadbabe.");
|
||||
SelectLabel->SetText("Select which game file (IWAD) to run.");
|
||||
PlayButton->SetText("Play Game");
|
||||
ExitButton->SetText("Exit");
|
||||
|
||||
ExitButton->OnClick = []{
|
||||
DisplayWindow::ExitLoop();
|
||||
};
|
||||
|
||||
GeneralLabel->SetText("General");
|
||||
ExtrasLabel->SetText("Extra Graphics");
|
||||
FullscreenCheckbox->SetText("Fullscreen");
|
||||
DisableAutoloadCheckbox->SetText("Disable autoload");
|
||||
DontAskAgainCheckbox->SetText("Don't ask me again");
|
||||
LightsCheckbox->SetText("Lights");
|
||||
BrightmapsCheckbox->SetText("Brightmaps");
|
||||
WidescreenCheckbox->SetText("Widescreen");
|
||||
|
||||
Choices->SetMaxDisplayItems(2);
|
||||
Choices->AddItem("First");
|
||||
Choices->AddItem("Second");
|
||||
Choices->AddItem("Third");
|
||||
Choices->AddItem("Fourth");
|
||||
Choices->AddItem("Fifth");
|
||||
Choices->AddItem("Sixth");
|
||||
|
||||
Choices->OnChanged = [this](int index) {
|
||||
std::cout << "Selected " << index << ":" << Choices->GetItem(index) << std::endl;
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
auto filedata = ReadAllBytes("banner.png");
|
||||
std::vector<unsigned char> pixels;
|
||||
unsigned long width = 0, height = 0;
|
||||
int result = decodePNG(pixels, width, height, (const unsigned char*)filedata.data(), filedata.size(), true);
|
||||
if (result == 0)
|
||||
{
|
||||
Logo->SetImage(Image::Create(width, height, ImageFormat::R8G8B8A8, pixels.data()));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void OnGeometryChanged() override
|
||||
{
|
||||
double y = 0.0;
|
||||
|
||||
Logo->SetFrameGeometry(0.0, y, GetWidth(), Logo->GetPreferredHeight());
|
||||
y += Logo->GetPreferredHeight();
|
||||
|
||||
y += 10.0;
|
||||
|
||||
WelcomeLabel->SetFrameGeometry(20.0, y, GetWidth() - 40.0, WelcomeLabel->GetPreferredHeight());
|
||||
y += WelcomeLabel->GetPreferredHeight();
|
||||
|
||||
VersionLabel->SetFrameGeometry(20.0, y, GetWidth() - 40.0, VersionLabel->GetPreferredHeight());
|
||||
y += VersionLabel->GetPreferredHeight();
|
||||
|
||||
y += 10.0;
|
||||
|
||||
SelectLabel->SetFrameGeometry(20.0, y, GetWidth() - 40.0 - Choices->GetPreferredWidth(), SelectLabel->GetPreferredHeight());
|
||||
y += SelectLabel->GetPreferredHeight();
|
||||
|
||||
Choices->SetFrameGeometry(GetWidth() - 20.0 - Choices->GetPreferredWidth(), y-Choices->GetPreferredHeight(), Choices->GetPreferredWidth(), Choices->GetPreferredHeight());
|
||||
|
||||
double listViewTop = y + 10.0;
|
||||
|
||||
y = GetHeight() - 15.0 - PlayButton->GetPreferredHeight();
|
||||
PlayButton->SetFrameGeometry(20.0, y, 120.0, PlayButton->GetPreferredHeight());
|
||||
ExitButton->SetFrameGeometry(GetWidth() - 20.0 - 120.0, y, 120.0, PlayButton->GetPreferredHeight());
|
||||
|
||||
y -= 20.0;
|
||||
|
||||
double panelWidth = 150.0;
|
||||
y -= DontAskAgainCheckbox->GetPreferredHeight();
|
||||
DontAskAgainCheckbox->SetFrameGeometry(20.0, y, 190.0, DontAskAgainCheckbox->GetPreferredHeight());
|
||||
WidescreenCheckbox->SetFrameGeometry(GetWidth() - 20.0 - panelWidth, y, panelWidth, WidescreenCheckbox->GetPreferredHeight());
|
||||
|
||||
y -= DisableAutoloadCheckbox->GetPreferredHeight();
|
||||
DisableAutoloadCheckbox->SetFrameGeometry(20.0, y, 190.0, DisableAutoloadCheckbox->GetPreferredHeight());
|
||||
BrightmapsCheckbox->SetFrameGeometry(GetWidth() - 20.0 - panelWidth, y, panelWidth, BrightmapsCheckbox->GetPreferredHeight());
|
||||
|
||||
y -= FullscreenCheckbox->GetPreferredHeight();
|
||||
FullscreenCheckbox->SetFrameGeometry(20.0, y, 190.0, FullscreenCheckbox->GetPreferredHeight());
|
||||
LightsCheckbox->SetFrameGeometry(GetWidth() - 20.0 - panelWidth, y, panelWidth, LightsCheckbox->GetPreferredHeight());
|
||||
|
||||
y -= GeneralLabel->GetPreferredHeight();
|
||||
GeneralLabel->SetFrameGeometry(20.0, y, 190.0, GeneralLabel->GetPreferredHeight());
|
||||
ExtrasLabel->SetFrameGeometry(GetWidth() - 20.0 - panelWidth, y, panelWidth, ExtrasLabel->GetPreferredHeight());
|
||||
|
||||
double listViewBottom = y - 10.0;
|
||||
GamesList->SetFrameGeometry(20.0, listViewTop, GetWidth() - 40.0, std::max(listViewBottom - listViewTop, 0.0));
|
||||
}
|
||||
|
||||
ImageBox* Logo = nullptr;
|
||||
class LauncherWindowTab2 : public Widget
|
||||
{
|
||||
public:
|
||||
LauncherWindowTab2(Widget parent);
|
||||
void OnGeometryChanged() override;
|
||||
private:
|
||||
TextLabel* WelcomeLabel = nullptr;
|
||||
TextLabel* VersionLabel = nullptr;
|
||||
TextLabel* SelectLabel = nullptr;
|
||||
|
|
@ -154,13 +47,244 @@ public:
|
|||
CheckboxLabel* LightsCheckbox = nullptr;
|
||||
CheckboxLabel* BrightmapsCheckbox = nullptr;
|
||||
CheckboxLabel* WidescreenCheckbox = nullptr;
|
||||
PushButton* PlayButton = nullptr;
|
||||
PushButton* ExitButton = nullptr;
|
||||
ListView* GamesList = nullptr;
|
||||
Dropdown* Choices = nullptr;
|
||||
};
|
||||
|
||||
static std::vector<uint8_t> ReadAllBytes(const std::string& filename);
|
||||
class LauncherWindowTab3 : public Widget
|
||||
{
|
||||
public:
|
||||
LauncherWindowTab3(Widget parent);
|
||||
void OnGeometryChanged() override;
|
||||
private:
|
||||
TextLabel* Label = nullptr;
|
||||
Dropdown* Choices = nullptr;
|
||||
PushButton* Popup = nullptr;
|
||||
};
|
||||
|
||||
class LauncherWindow : public Widget
|
||||
{
|
||||
public:
|
||||
LauncherWindow();
|
||||
private:
|
||||
void OnClose() override;
|
||||
void OnGeometryChanged() override;
|
||||
|
||||
ImageBox* Logo = nullptr;
|
||||
TabWidget* Pages = nullptr;
|
||||
PushButton* ExitButton = nullptr;
|
||||
|
||||
LauncherWindowTab1* Tab1 = nullptr;
|
||||
LauncherWindowTab2* Tab2 = nullptr;
|
||||
LauncherWindowTab3* Tab3 = nullptr;
|
||||
};
|
||||
|
||||
// ************************************************************
|
||||
// UI implementation
|
||||
// ************************************************************
|
||||
|
||||
LauncherWindow::LauncherWindow(): Widget(nullptr, WidgetType::Window)
|
||||
{
|
||||
SetWindowTitle("ZWidget Demo");
|
||||
|
||||
Logo = new ImageBox(this);
|
||||
ExitButton = new PushButton(this);
|
||||
Pages = new TabWidget(this);
|
||||
|
||||
Tab1 = new LauncherWindowTab1(this);
|
||||
Tab2 = new LauncherWindowTab2(this);
|
||||
Tab3 = new LauncherWindowTab3(this);
|
||||
|
||||
Pages->AddTab(Tab1, "Welcome");
|
||||
Pages->AddTab(Tab2, "VKDoom");
|
||||
Pages->AddTab(Tab3, "ZWidgets");
|
||||
|
||||
ExitButton->SetText("Exit");
|
||||
|
||||
ExitButton->OnClick = []{
|
||||
DisplayWindow::ExitLoop();
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
auto filedata = ReadAllBytes("banner.png");
|
||||
std::vector<unsigned char> pixels;
|
||||
unsigned long width = 0, height = 0;
|
||||
int result = decodePNG(pixels, width, height, (const unsigned char*)filedata.data(), filedata.size(), true);
|
||||
if (result == 0)
|
||||
{
|
||||
Logo->SetImage(Image::Create(width, height, ImageFormat::R8G8B8A8, pixels.data()));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherWindow::OnGeometryChanged()
|
||||
{
|
||||
double y = 0, h;
|
||||
|
||||
h = Logo->GetPreferredHeight();
|
||||
Logo->SetFrameGeometry(0, y, GetWidth(), h);
|
||||
y += h;
|
||||
|
||||
h = GetHeight() - y - ExitButton->GetPreferredHeight() - 40;
|
||||
Pages->SetFrameGeometry(0, y, GetWidth(), h);
|
||||
y += h + 20;
|
||||
|
||||
ExitButton->SetFrameGeometry(GetWidth() - 20 - 120, y, 120, ExitButton->GetPreferredHeight());
|
||||
}
|
||||
|
||||
void LauncherWindow::OnClose()
|
||||
{
|
||||
DisplayWindow::ExitLoop();
|
||||
}
|
||||
|
||||
LauncherWindowTab1::LauncherWindowTab1(Widget parent): Widget(nullptr)
|
||||
{
|
||||
Text = new TextEdit(this);
|
||||
|
||||
Text->SetText(
|
||||
"Welcome to VKDoom\n\n"
|
||||
"Click the tabs to look at other widgets\n\n"
|
||||
"Also, this text is editable\n"
|
||||
);
|
||||
}
|
||||
|
||||
void LauncherWindowTab1::OnGeometryChanged()
|
||||
{
|
||||
Text->SetFrameGeometry(0, 10, GetWidth(), GetHeight());
|
||||
}
|
||||
|
||||
LauncherWindowTab2::LauncherWindowTab2(Widget parent): Widget(nullptr)
|
||||
{
|
||||
WelcomeLabel = new TextLabel(this);
|
||||
VersionLabel = new TextLabel(this);
|
||||
SelectLabel = new TextLabel(this);
|
||||
GeneralLabel = new TextLabel(this);
|
||||
ExtrasLabel = new TextLabel(this);
|
||||
FullscreenCheckbox = new CheckboxLabel(this);
|
||||
DisableAutoloadCheckbox = new CheckboxLabel(this);
|
||||
DontAskAgainCheckbox = new CheckboxLabel(this);
|
||||
LightsCheckbox = new CheckboxLabel(this);
|
||||
BrightmapsCheckbox = new CheckboxLabel(this);
|
||||
WidescreenCheckbox = new CheckboxLabel(this);
|
||||
GamesList = new ListView(this);
|
||||
|
||||
WelcomeLabel->SetText("Welcome to VKDoom");
|
||||
VersionLabel->SetText("Version 0xdeadbabe.");
|
||||
SelectLabel->SetText("Select which game file (IWAD) to run.");
|
||||
|
||||
GamesList->AddItem("Doom");
|
||||
GamesList->AddItem("Doom 2: Electric Boogaloo");
|
||||
GamesList->AddItem("Doom 3D");
|
||||
GamesList->AddItem("Doom 4: The Quest for Peace");
|
||||
GamesList->AddItem("Doom on Ice");
|
||||
GamesList->AddItem("The Doom");
|
||||
GamesList->AddItem("Doom 2");
|
||||
|
||||
GeneralLabel->SetText("General");
|
||||
ExtrasLabel->SetText("Extra Graphics");
|
||||
FullscreenCheckbox->SetText("Fullscreen");
|
||||
DisableAutoloadCheckbox->SetText("Disable autoload");
|
||||
DontAskAgainCheckbox->SetText("Don't ask me again");
|
||||
LightsCheckbox->SetText("Lights");
|
||||
BrightmapsCheckbox->SetText("Brightmaps");
|
||||
WidescreenCheckbox->SetText("Widescreen");
|
||||
}
|
||||
|
||||
void LauncherWindowTab2::OnGeometryChanged()
|
||||
{
|
||||
double y = 0, h;
|
||||
|
||||
h = WelcomeLabel->GetPreferredHeight();
|
||||
WelcomeLabel->SetFrameGeometry(20, y, GetWidth() - 40, h);
|
||||
y += h;
|
||||
|
||||
h = VersionLabel->GetPreferredHeight();
|
||||
VersionLabel->SetFrameGeometry(20, y, GetWidth() - 40, h);
|
||||
y += h + 10;
|
||||
|
||||
h = SelectLabel->GetPreferredHeight();
|
||||
SelectLabel->SetFrameGeometry(20, y, GetWidth() - 40, h);
|
||||
y += h;
|
||||
|
||||
double listViewTop = y + 10, listViewBottom;
|
||||
|
||||
y = GetHeight();
|
||||
|
||||
h = DontAskAgainCheckbox->GetPreferredHeight();
|
||||
y -= h;
|
||||
DontAskAgainCheckbox->SetFrameGeometry(20, y, 190, h);
|
||||
WidescreenCheckbox->SetFrameGeometry(GetWidth() - 170, y, 150, WidescreenCheckbox->GetPreferredHeight());
|
||||
|
||||
h = DisableAutoloadCheckbox->GetPreferredHeight();
|
||||
y -= h;
|
||||
DisableAutoloadCheckbox->SetFrameGeometry(20, y, 190, h);
|
||||
BrightmapsCheckbox->SetFrameGeometry(GetWidth() - 170, y, 150, BrightmapsCheckbox->GetPreferredHeight());
|
||||
|
||||
h = FullscreenCheckbox->GetPreferredHeight();
|
||||
y -= h;
|
||||
FullscreenCheckbox->SetFrameGeometry(20, y, 190, h);
|
||||
LightsCheckbox->SetFrameGeometry(GetWidth() - 170, y, 150, LightsCheckbox->GetPreferredHeight());
|
||||
|
||||
h = GeneralLabel->GetPreferredHeight();
|
||||
y -= h;
|
||||
GeneralLabel->SetFrameGeometry(20, y, 190, GeneralLabel->GetPreferredHeight());
|
||||
ExtrasLabel->SetFrameGeometry(GetWidth() - 170, y, 150, ExtrasLabel->GetPreferredHeight());
|
||||
|
||||
listViewBottom = y - 10;
|
||||
GamesList->SetFrameGeometry(20, listViewTop, GetWidth() - 40, std::max<double>(listViewBottom - listViewTop, 0));
|
||||
}
|
||||
|
||||
LauncherWindowTab3::LauncherWindowTab3(Widget parent): Widget(nullptr)
|
||||
{
|
||||
Label = new TextLabel(this);
|
||||
Choices = new Dropdown(this);
|
||||
Popup = new PushButton(this);
|
||||
|
||||
Label->SetText("Oh my, even more widgets");
|
||||
Popup->SetText("Click me.");
|
||||
|
||||
Choices->SetMaxDisplayItems(2);
|
||||
Choices->AddItem("First");
|
||||
Choices->AddItem("Second");
|
||||
Choices->AddItem("Third");
|
||||
Choices->AddItem("Fourth");
|
||||
Choices->AddItem("Fifth");
|
||||
Choices->AddItem("Sixth");
|
||||
|
||||
Choices->OnChanged = [this](int index) {
|
||||
std::cout << "Selected " << index << ":" << Choices->GetItem(index) << std::endl;
|
||||
};
|
||||
|
||||
Popup->OnClick = []{
|
||||
std::cout << "TODO: open popup" << std::endl;
|
||||
};
|
||||
}
|
||||
|
||||
void LauncherWindowTab3::OnGeometryChanged()
|
||||
{
|
||||
double y = 0, h;
|
||||
|
||||
y += 10;
|
||||
|
||||
h = Label->GetPreferredHeight();
|
||||
Label->SetFrameGeometry(20, y, GetWidth() - 40, h);
|
||||
y += h + 10;
|
||||
|
||||
h = Choices->GetPreferredHeight();
|
||||
Choices->SetFrameGeometry(20, y, Choices->GetPreferredWidth(), h);
|
||||
y += h + 10;
|
||||
|
||||
h = Popup->GetPreferredHeight();
|
||||
Popup->SetFrameGeometry(20, y, 120, h);
|
||||
y += h;
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// Shared code
|
||||
// ************************************************************
|
||||
|
||||
std::vector<SingleFontData> LoadWidgetFontData(const std::string& name)
|
||||
{
|
||||
|
|
@ -178,9 +302,22 @@ enum class Backend {
|
|||
Default, Win32, SDL2, X11, Wayland
|
||||
};
|
||||
|
||||
int example(Backend backend = Backend::Default)
|
||||
enum class Theme {
|
||||
Default, Light, Dark
|
||||
};
|
||||
|
||||
int example(
|
||||
Backend backend = Backend::Default,
|
||||
Theme theme = Theme::Default
|
||||
)
|
||||
{
|
||||
WidgetTheme::SetTheme(std::make_unique<DarkWidgetTheme>());
|
||||
// just for testing themes
|
||||
switch (theme)
|
||||
{
|
||||
case Theme::Default: WidgetTheme::SetTheme(std::make_unique<DarkWidgetTheme>()); break;
|
||||
case Theme::Dark: WidgetTheme::SetTheme(std::make_unique<DarkWidgetTheme>()); break;
|
||||
case Theme::Light: WidgetTheme::SetTheme(std::make_unique<LightWidgetTheme>()); break;
|
||||
}
|
||||
|
||||
// just for testing backends
|
||||
switch (backend)
|
||||
|
|
@ -192,38 +329,19 @@ int example(Backend backend = Backend::Default)
|
|||
case Backend::Wayland: DisplayBackend::Set(DisplayBackend::TryCreateWayland()); break;
|
||||
}
|
||||
|
||||
#if 1
|
||||
auto launcher = new LauncherWindow();
|
||||
launcher->SetFrameGeometry(100.0, 100.0, 615.0, 668.0);
|
||||
launcher->Show();
|
||||
#else
|
||||
auto mainwindow = new MainWindow();
|
||||
auto textedit = new TextEdit(mainwindow);
|
||||
textedit->SetText(R"(
|
||||
#version 460
|
||||
|
||||
in vec4 AttrPos;
|
||||
in vec4 AttrColor;
|
||||
out vec4 Color;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = AttrPos;
|
||||
Color = AttrColor;
|
||||
}
|
||||
)");
|
||||
mainwindow->SetWindowTitle("ZWidget Example");
|
||||
mainwindow->SetFrameGeometry(100.0, 100.0, 1700.0, 900.0);
|
||||
mainwindow->SetCentralWidget(textedit);
|
||||
textedit->SetFocus();
|
||||
mainwindow->Show();
|
||||
#endif
|
||||
|
||||
DisplayWindow::RunLoop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// Platform-specific code
|
||||
// ************************************************************
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#include <Windows.h>
|
||||
|
|
@ -305,18 +423,25 @@ static std::vector<uint8_t> ReadAllBytes(const std::string& filename)
|
|||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
std::string backendStr = argc > 1? argv[1]: "";
|
||||
std::transform(backendStr.begin(), backendStr.end(), backendStr.begin(),
|
||||
[](unsigned char c){ return std::tolower(c); });
|
||||
|
||||
Backend backend = Backend::Default;
|
||||
Theme theme = Theme::Default;
|
||||
|
||||
if (backendStr == "sdl2") backend = Backend::SDL2;
|
||||
if (backendStr == "x11") backend = Backend::X11;
|
||||
if (backendStr == "wayland") backend = Backend::Wayland;
|
||||
if (backendStr == "win32") backend = Backend::Win32; // lol
|
||||
for (auto i = 1; i < argc; i++)
|
||||
{
|
||||
std::string s = argv[i];
|
||||
std::transform(s.begin(), s.end(), s.begin(),
|
||||
[](unsigned char c){ return std::tolower(c); });
|
||||
|
||||
example(backend);
|
||||
if (s == "light") { theme = Theme::Light; continue; }
|
||||
if (s == "dark") { theme = Theme::Dark; continue; }
|
||||
|
||||
if (s == "sdl2") { backend = Backend::SDL2; continue; }
|
||||
if (s == "x11") { backend = Backend::X11; continue; }
|
||||
if (s == "wayland") { backend = Backend::Wayland; continue; }
|
||||
if (s == "win32") { backend = Backend::Win32; continue; } // lol
|
||||
}
|
||||
|
||||
example(backend, theme);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ int decodePNG(std::vector<unsigned char>& out_image, unsigned long& image_width,
|
|||
readPngHeader(&in[0], size); if(error) return;
|
||||
size_t pos = 33; //first byte of the first chunk after the header
|
||||
std::vector<unsigned char> idat; //the data from idat chunks
|
||||
bool IEND = false, known_type = true;
|
||||
bool IEND = false/*, known_type = true*/;
|
||||
info.key_defined = false;
|
||||
while(!IEND) //loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer
|
||||
{
|
||||
|
|
@ -312,7 +312,7 @@ int decodePNG(std::vector<unsigned char>& out_image, unsigned long& image_width,
|
|||
{
|
||||
if(!(in[pos + 0] & 32)) { error = 69; return; } //error: unknown critical chunk (5th bit of first byte of chunk type is 0)
|
||||
pos += (chunkLength + 4); //skip 4 letters and uninterpreted data of unimplemented chunk
|
||||
known_type = false;
|
||||
//known_type = false;
|
||||
}
|
||||
pos += 4; //step over CRC (which is ignored)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,21 @@ public:
|
|||
return { r * s, g * s, b * s, a * s };
|
||||
}
|
||||
|
||||
static Colorf fromRgba(uint32_t rgba)
|
||||
{
|
||||
return fromRgba8(
|
||||
0xff & rgba>>24,
|
||||
0xff & rgba>>16,
|
||||
0xff & rgba>>8,
|
||||
0xff & rgba
|
||||
);
|
||||
}
|
||||
|
||||
static Colorf fromRgb(uint32_t rgb)
|
||||
{
|
||||
return fromRgba(rgb<<8 | 0xff);
|
||||
}
|
||||
|
||||
uint32_t toBgra8() const
|
||||
{
|
||||
uint32_t cr = (int)(std::max(std::min(r * 255.0f, 255.0f), 0.0f));
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ private:
|
|||
Colorf cursor_color;
|
||||
|
||||
std::string::size_type sel_start = 0, sel_end = 0;
|
||||
Colorf sel_foreground, sel_background = Colorf::fromRgba8(153, 201, 239);
|
||||
Colorf sel_foreground, sel_background;
|
||||
|
||||
std::string text;
|
||||
std::vector<SpanObject> objects;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,23 @@ public:
|
|||
|
||||
class WidgetTheme
|
||||
{
|
||||
struct SimpleTheme {
|
||||
const Colorf bgMain; // background
|
||||
const Colorf fgMain; //
|
||||
const Colorf bgLight; // headers / inputs
|
||||
const Colorf fgLight; //
|
||||
const Colorf bgAction; // interactive elements
|
||||
const Colorf fgAction; //
|
||||
const Colorf bgHover; // hover / highlight
|
||||
const Colorf fgHover; //
|
||||
const Colorf bgActive; // click
|
||||
const Colorf fgActive; //
|
||||
const Colorf border; // around elements
|
||||
const Colorf divider; // between elements
|
||||
};
|
||||
public:
|
||||
WidgetTheme() {}
|
||||
WidgetTheme(const struct SimpleTheme &theme);
|
||||
virtual ~WidgetTheme() = default;
|
||||
|
||||
WidgetStyle* RegisterStyle(std::unique_ptr<WidgetStyle> widgetStyle, const std::string& widgetClass);
|
||||
|
|
|
|||
|
|
@ -83,6 +83,11 @@ private:
|
|||
SpanLayout layout;
|
||||
Rect box;
|
||||
bool invalidated = true;
|
||||
|
||||
Line(const TextEdit *self)
|
||||
{
|
||||
layout.SetSelectionColors(self->selectionFG, self->selectionBG);
|
||||
}
|
||||
};
|
||||
|
||||
struct ivec2
|
||||
|
|
@ -96,9 +101,10 @@ private:
|
|||
bool operator!=(const ivec2& b) const { return x != b.x || y != b.y; }
|
||||
};
|
||||
|
||||
Colorf selectionBG, selectionFG;
|
||||
Scrollbar* vert_scrollbar;
|
||||
Timer* timer = nullptr;
|
||||
std::vector<Line> lines = { Line() };
|
||||
std::vector<Line> lines = { Line{this} };
|
||||
ivec2 cursor_pos = { 0, 0 };
|
||||
int max_length = -1;
|
||||
bool mouse_selecting = false;
|
||||
|
|
|
|||
|
|
@ -549,9 +549,7 @@ void BitmapCanvas::plot(float x, float y, float alpha, const Colorf& color)
|
|||
int xx = (int)x;
|
||||
int yy = (int)y;
|
||||
|
||||
int dwidth = width;
|
||||
int dheight = height;
|
||||
uint32_t* dest = pixels.data() + xx + yy * dwidth;
|
||||
uint32_t* dest = pixels.data() + xx + yy * width;
|
||||
|
||||
uint32_t cred = (int32_t)clamp(color.r * 256.0f, 0.0f, 256.0f);
|
||||
uint32_t cgreen = (int32_t)clamp(color.g * 256.0f, 0.0f, 256.0f);
|
||||
|
|
@ -665,7 +663,6 @@ void BitmapCanvas::fillTile(float left, float top, float width, float height, Co
|
|||
return;
|
||||
|
||||
int dwidth = this->width;
|
||||
int dheight = this->height;
|
||||
uint32_t* dest = this->pixels.data();
|
||||
|
||||
int x0 = (int)left;
|
||||
|
|
@ -771,11 +768,9 @@ void BitmapCanvas::drawTile(CanvasTexture* tex, float left, float top, float wid
|
|||
|
||||
auto texture = static_cast<BitmapTexture*>(tex);
|
||||
int swidth = texture->Width;
|
||||
int sheight = texture->Height;
|
||||
const uint32_t* src = texture->Data.data();
|
||||
|
||||
int dwidth = this->width;
|
||||
int dheight = this->height;
|
||||
uint32_t* dest = this->pixels.data();
|
||||
|
||||
int x0 = (int)left;
|
||||
|
|
@ -880,11 +875,9 @@ void BitmapCanvas::drawGlyph(CanvasTexture* tex, float left, float top, float wi
|
|||
|
||||
auto texture = static_cast<BitmapTexture*>(tex);
|
||||
int swidth = texture->Width;
|
||||
int sheight = texture->Height;
|
||||
const uint32_t* src = texture->Data.data();
|
||||
|
||||
int dwidth = this->width;
|
||||
int dheight = this->height;
|
||||
uint32_t* dest = this->pixels.data();
|
||||
|
||||
int x0 = (int)left;
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ PathFillRasterizer::Extent PathFillRasterizer::FindExtent(const PathScanline* sc
|
|||
|
||||
void PathFillRasterizer::Clear()
|
||||
{
|
||||
for (size_t y = first_scanline; y < last_scanline; y++)
|
||||
for (int y = first_scanline; y < last_scanline; y++)
|
||||
{
|
||||
auto& scanline = scanlines[y];
|
||||
if (!scanline.edges.empty())
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ int decodePNG(std::vector<unsigned char>& out_image, unsigned long& image_width,
|
|||
readPngHeader(&in[0], size); if(error) return;
|
||||
size_t pos = 33; //first byte of the first chunk after the header
|
||||
std::vector<unsigned char> idat; //the data from idat chunks
|
||||
bool IEND = false, known_type = true;
|
||||
bool IEND = false/*, known_type = true*/;
|
||||
info.key_defined = false;
|
||||
while(!IEND) //loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer
|
||||
{
|
||||
|
|
@ -314,7 +314,7 @@ int decodePNG(std::vector<unsigned char>& out_image, unsigned long& image_width,
|
|||
{
|
||||
if(!(in[pos + 0] & 32)) { error = 69; return; } //error: unknown critical chunk (5th bit of first byte of chunk type is 0)
|
||||
pos += (chunkLength + 4); //skip 4 letters and uninterpreted data of unimplemented chunk
|
||||
known_type = false;
|
||||
/*known_type = false;*/
|
||||
}
|
||||
pos += 4; //step over CRC (which is ignored)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,16 +72,12 @@ void SpanLayout::DrawLayout(Canvas* canvas)
|
|||
LineSegment& segment = line.segments.back();
|
||||
if (cursor_visible && segment.end <= cursor_pos)
|
||||
{
|
||||
switch (segment.type)
|
||||
{
|
||||
case object_text:
|
||||
if (segment.type == object_text)
|
||||
{
|
||||
double cursor_x = x + segment.x_position + canvas->measureText(segment.font, text.substr(segment.start, segment.end - segment.start)).width;
|
||||
double cursor_width = 1;
|
||||
canvas->fillRect(Rect::ltrb(cursor_x, y + line.ascender - segment.ascender, cursor_width, y + line.ascender + segment.descender), cursor_color);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -141,12 +141,26 @@ WidgetTheme* WidgetTheme::GetTheme()
|
|||
return CurrentTheme.get();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DarkWidgetTheme::DarkWidgetTheme()
|
||||
WidgetTheme::WidgetTheme(const struct SimpleTheme &theme)
|
||||
{
|
||||
|
||||
auto bgMain = theme.bgMain; // background
|
||||
auto fgMain = theme.fgMain; //
|
||||
auto bgLight = theme.bgLight; // headers / inputs
|
||||
auto fgLight = theme.fgLight; //
|
||||
auto bgAction = theme.bgAction; // interactive elements
|
||||
auto fgAction = theme.fgAction; //
|
||||
auto bgHover = theme.bgHover; // hover / highlight
|
||||
auto fgHover = theme.fgHover; //
|
||||
auto bgActive = theme.bgActive; // click
|
||||
auto fgActive = theme.fgActive; //
|
||||
auto border = theme.border; // around elements
|
||||
auto divider = theme.divider; // between elements
|
||||
|
||||
auto none = Colorf::transparent();
|
||||
|
||||
auto widget = RegisterStyle(std::make_unique<BasicWidgetStyle>(), "widget");
|
||||
auto textlabel = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "textlabel");
|
||||
/*auto textlabel =*/ RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "textlabel");
|
||||
auto pushbutton = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "pushbutton");
|
||||
auto lineedit = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "lineedit");
|
||||
auto textedit = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "textedit");
|
||||
|
|
@ -167,272 +181,177 @@ DarkWidgetTheme::DarkWidgetTheme()
|
|||
auto statusbar = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "statusbar");
|
||||
|
||||
widget->SetString("font-family", "NotoSans");
|
||||
widget->SetColor("color", Colorf::fromRgba8(226, 223, 219));
|
||||
widget->SetColor("window-background", Colorf::fromRgba8(51, 51, 51));
|
||||
widget->SetColor("window-border", Colorf::fromRgba8(51, 51, 51));
|
||||
widget->SetColor("window-caption-color", Colorf::fromRgba8(33, 33, 33));
|
||||
widget->SetColor("window-caption-text-color", Colorf::fromRgba8(226, 223, 219));
|
||||
widget->SetColor("color", fgMain);
|
||||
widget->SetColor("window-background", bgMain);
|
||||
widget->SetColor("window-border", bgMain);
|
||||
widget->SetColor("window-caption-color", bgLight);
|
||||
widget->SetColor("window-caption-text-color", fgLight);
|
||||
|
||||
pushbutton->SetDouble("noncontent-left", 10.0);
|
||||
pushbutton->SetDouble("noncontent-top", 5.0);
|
||||
pushbutton->SetDouble("noncontent-right", 10.0);
|
||||
pushbutton->SetDouble("noncontent-bottom", 5.0);
|
||||
pushbutton->SetColor("background-color", Colorf::fromRgba8(68, 68, 68));
|
||||
pushbutton->SetColor("border-left-color", Colorf::fromRgba8(100, 100, 100));
|
||||
pushbutton->SetColor("border-top-color", Colorf::fromRgba8(100, 100, 100));
|
||||
pushbutton->SetColor("border-right-color", Colorf::fromRgba8(100, 100, 100));
|
||||
pushbutton->SetColor("border-bottom-color", Colorf::fromRgba8(100, 100, 100));
|
||||
pushbutton->SetColor("hover", "background-color", Colorf::fromRgba8(78, 78, 78));
|
||||
pushbutton->SetColor("down", "background-color", Colorf::fromRgba8(88, 88, 88));
|
||||
pushbutton->SetColor("color", fgAction);
|
||||
pushbutton->SetColor("background-color", bgAction);
|
||||
pushbutton->SetColor("border-left-color", border);
|
||||
pushbutton->SetColor("border-top-color", border);
|
||||
pushbutton->SetColor("border-right-color", border);
|
||||
pushbutton->SetColor("border-bottom-color", border);
|
||||
pushbutton->SetColor("hover", "color", fgHover);
|
||||
pushbutton->SetColor("hover", "background-color", bgHover);
|
||||
pushbutton->SetColor("down", "color", fgActive);
|
||||
pushbutton->SetColor("down", "background-color", bgActive);
|
||||
|
||||
lineedit->SetDouble("noncontent-left", 5.0);
|
||||
lineedit->SetDouble("noncontent-top", 3.0);
|
||||
lineedit->SetDouble("noncontent-right", 5.0);
|
||||
lineedit->SetDouble("noncontent-bottom", 3.0);
|
||||
lineedit->SetColor("background-color", Colorf::fromRgba8(38, 38, 38));
|
||||
lineedit->SetColor("border-left-color", Colorf::fromRgba8(100, 100, 100));
|
||||
lineedit->SetColor("border-top-color", Colorf::fromRgba8(100, 100, 100));
|
||||
lineedit->SetColor("border-right-color", Colorf::fromRgba8(100, 100, 100));
|
||||
lineedit->SetColor("border-bottom-color", Colorf::fromRgba8(100, 100, 100));
|
||||
lineedit->SetColor("selection-color", Colorf::fromRgba8(100, 100, 100));
|
||||
lineedit->SetColor("no-focus-selection-color", Colorf::fromRgba8(68, 68, 68));
|
||||
lineedit->SetColor("color", fgLight);
|
||||
lineedit->SetColor("background-color", bgLight);
|
||||
lineedit->SetColor("border-left-color", border);
|
||||
lineedit->SetColor("border-top-color", border);
|
||||
lineedit->SetColor("border-right-color", border);
|
||||
lineedit->SetColor("border-bottom-color", border);
|
||||
lineedit->SetColor("selection-color", bgHover);
|
||||
lineedit->SetColor("no-focus-selection-color", bgHover);
|
||||
|
||||
textedit->SetDouble("noncontent-left", 8.0);
|
||||
textedit->SetDouble("noncontent-top", 8.0);
|
||||
textedit->SetDouble("noncontent-right", 8.0);
|
||||
textedit->SetDouble("noncontent-bottom", 8.0);
|
||||
textedit->SetColor("background-color", Colorf::fromRgba8(38, 38, 38));
|
||||
textedit->SetColor("border-left-color", Colorf::fromRgba8(100, 100, 100));
|
||||
textedit->SetColor("border-top-color", Colorf::fromRgba8(100, 100, 100));
|
||||
textedit->SetColor("border-right-color", Colorf::fromRgba8(100, 100, 100));
|
||||
textedit->SetColor("border-bottom-color", Colorf::fromRgba8(100, 100, 100));
|
||||
textedit->SetColor("color", fgLight);
|
||||
textedit->SetColor("background-color", bgLight);
|
||||
textedit->SetColor("border-left-color", border);
|
||||
textedit->SetColor("border-top-color", border);
|
||||
textedit->SetColor("border-right-color", border);
|
||||
textedit->SetColor("border-bottom-color", border);
|
||||
textedit->SetColor("selection-color", bgHover);
|
||||
|
||||
listview->SetDouble("noncontent-left", 10.0);
|
||||
listview->SetDouble("noncontent-top", 10.0);
|
||||
listview->SetDouble("noncontent-right", 3.0);
|
||||
listview->SetDouble("noncontent-bottom", 10.0);
|
||||
listview->SetColor("background-color", Colorf::fromRgba8(38, 38, 38));
|
||||
listview->SetColor("border-left-color", Colorf::fromRgba8(100, 100, 100));
|
||||
listview->SetColor("border-top-color", Colorf::fromRgba8(100, 100, 100));
|
||||
listview->SetColor("border-right-color", Colorf::fromRgba8(100, 100, 100));
|
||||
listview->SetColor("border-bottom-color", Colorf::fromRgba8(100, 100, 100));
|
||||
listview->SetColor("selection-color", Colorf::fromRgba8(100, 100, 100));
|
||||
listview->SetColor("color", fgLight);
|
||||
listview->SetColor("background-color", bgLight);
|
||||
listview->SetColor("border-left-color", border);
|
||||
listview->SetColor("border-top-color", border);
|
||||
listview->SetColor("border-right-color", border);
|
||||
listview->SetColor("border-bottom-color", border);
|
||||
listview->SetColor("selection-color", bgHover);
|
||||
|
||||
dropdown->SetDouble("noncontent-left", 5.0);
|
||||
dropdown->SetDouble("noncontent-top", 5.0);
|
||||
dropdown->SetDouble("noncontent-right", 5.0);
|
||||
dropdown->SetDouble("noncontent-bottom", 5.0);
|
||||
dropdown->SetColor("background-color", Colorf::fromRgba8(38, 38, 38));
|
||||
dropdown->SetColor("border-left-color", Colorf::fromRgba8(100, 100, 100));
|
||||
dropdown->SetColor("border-top-color", Colorf::fromRgba8(100, 100, 100));
|
||||
dropdown->SetColor("border-right-color", Colorf::fromRgba8(100, 100, 100));
|
||||
dropdown->SetColor("border-bottom-color", Colorf::fromRgba8(100, 100, 100));
|
||||
dropdown->SetColor("selection-color", Colorf::fromRgba8(100, 100, 100));
|
||||
dropdown->SetColor("arrow-color", Colorf::fromRgba8(100, 100, 100));
|
||||
dropdown->SetColor("color", fgLight);
|
||||
dropdown->SetColor("background-color", bgLight);
|
||||
dropdown->SetColor("border-left-color", border);
|
||||
dropdown->SetColor("border-top-color", border);
|
||||
dropdown->SetColor("border-right-color", border);
|
||||
dropdown->SetColor("border-bottom-color", border);
|
||||
dropdown->SetColor("arrow-color", border);
|
||||
|
||||
scrollbar->SetColor("track-color", Colorf::fromRgba8(33, 33, 33));
|
||||
scrollbar->SetColor("thumb-color", Colorf::fromRgba8(58, 58, 58));
|
||||
scrollbar->SetColor("track-color", divider);
|
||||
scrollbar->SetColor("thumb-color", border);
|
||||
|
||||
tabbar->SetDouble("spacer-left", 20.0);
|
||||
tabbar->SetDouble("spacer-right", 20.0);
|
||||
tabbar->SetColor("background-color", Colorf::fromRgba8(33, 33, 33));
|
||||
tabbar->SetColor("background-color", bgLight);
|
||||
|
||||
tabbar_tab->SetDouble("noncontent-left", 15.0);
|
||||
tabbar_tab->SetDouble("noncontent-right", 15.0);
|
||||
tabbar_tab->SetDouble("noncontent-top", 1.0);
|
||||
tabbar_tab->SetDouble("noncontent-bottom", 1.0);
|
||||
tabbar_tab->SetColor("background-color", Colorf::fromRgba8(38, 38, 38));
|
||||
tabbar_tab->SetColor("border-left-color", Colorf::fromRgba8(68, 68, 68));
|
||||
tabbar_tab->SetColor("border-top-color", Colorf::fromRgba8(68, 68, 68));
|
||||
tabbar_tab->SetColor("border-right-color", Colorf::fromRgba8(68, 68, 68));
|
||||
tabbar_tab->SetColor("border-bottom-color", Colorf::fromRgba8(100, 100, 100));
|
||||
tabbar_tab->SetColor("hover", "background-color", Colorf::fromRgba8(45, 45, 45));
|
||||
tabbar_tab->SetColor("active", "background-color", Colorf::fromRgba8(51, 51, 51));
|
||||
tabbar_tab->SetColor("active", "border-left-color", Colorf::fromRgba8(100, 100, 100));
|
||||
tabbar_tab->SetColor("active", "border-top-color", Colorf::fromRgba8(100, 100, 100));
|
||||
tabbar_tab->SetColor("active", "border-right-color", Colorf::fromRgba8(100, 100, 100));
|
||||
tabbar_tab->SetColor("active", "border-bottom-color", Colorf::transparent());
|
||||
tabbar_tab->SetColor("color", fgMain);
|
||||
tabbar_tab->SetColor("background-color", bgMain);
|
||||
tabbar_tab->SetColor("border-left-color", divider);
|
||||
tabbar_tab->SetColor("border-top-color", divider);
|
||||
tabbar_tab->SetColor("border-right-color", divider);
|
||||
tabbar_tab->SetColor("border-bottom-color", border);
|
||||
tabbar_tab->SetColor("hover", "color", fgAction);
|
||||
tabbar_tab->SetColor("hover", "background-color", bgAction);
|
||||
tabbar_tab->SetColor("active", "background-color", bgMain);
|
||||
tabbar_tab->SetColor("active", "border-left-color", border);
|
||||
tabbar_tab->SetColor("active", "border-top-color", border);
|
||||
tabbar_tab->SetColor("active", "border-right-color", border);
|
||||
tabbar_tab->SetColor("active", "border-bottom-color", none);
|
||||
|
||||
tabbar_spacer->SetDouble("noncontent-bottom", 1.0);
|
||||
tabbar_spacer->SetColor("border-bottom-color", Colorf::fromRgba8(100, 100, 100));
|
||||
tabbar_spacer->SetColor("border-bottom-color", border);
|
||||
|
||||
tabwidget_stack->SetDouble("noncontent-left", 20.0);
|
||||
tabwidget_stack->SetDouble("noncontent-top", 5.0);
|
||||
tabwidget_stack->SetDouble("noncontent-right", 20.0);
|
||||
tabwidget_stack->SetDouble("noncontent-bottom", 5.0);
|
||||
|
||||
checkbox_label->SetColor("checked-outer-border-color", Colorf::fromRgba8(100, 100, 100));
|
||||
checkbox_label->SetColor("checked-inner-border-color", Colorf::fromRgba8(51, 51, 51));
|
||||
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));
|
||||
checkbox_label->SetColor("checked-outer-border-color", border);
|
||||
checkbox_label->SetColor("checked-inner-border-color", bgMain);
|
||||
checkbox_label->SetColor("checked-color", fgMain);
|
||||
checkbox_label->SetColor("unchecked-outer-border-color", border);
|
||||
checkbox_label->SetColor("unchecked-inner-border-color", bgMain);
|
||||
|
||||
menubar->SetColor("background-color", Colorf::fromRgba8(33, 33, 33));
|
||||
toolbar->SetColor("background-color", Colorf::fromRgba8(33, 33, 33));
|
||||
statusbar->SetColor("background-color", Colorf::fromRgba8(33, 33, 33));
|
||||
menubar->SetColor("background-color", bgLight);
|
||||
toolbar->SetColor("background-color", bgLight);
|
||||
statusbar->SetColor("background-color", bgLight);
|
||||
|
||||
toolbarbutton->SetColor("hover", "background-color", Colorf::fromRgba8(78, 78, 78));
|
||||
toolbarbutton->SetColor("down", "background-color", Colorf::fromRgba8(88, 88, 88));
|
||||
toolbarbutton->SetColor("hover", "color", fgHover);
|
||||
toolbarbutton->SetColor("hover", "background-color", bgHover);
|
||||
toolbarbutton->SetColor("down", "color", fgActive);
|
||||
toolbarbutton->SetColor("down", "background-color", bgActive);
|
||||
|
||||
menubaritem->SetColor("color", Colorf::fromRgba8(226, 223, 219));
|
||||
menubaritem->SetColor("hover", "background-color", Colorf::fromRgba8(78, 78, 78));
|
||||
menubaritem->SetColor("hover", "color", Colorf::fromRgba8(0, 0, 0));
|
||||
menubaritem->SetColor("down", "background-color", Colorf::fromRgba8(88, 88, 88));
|
||||
menubaritem->SetColor("down", "color", Colorf::fromRgba8(0, 0, 0));
|
||||
menubaritem->SetColor("color", fgMain);
|
||||
menubaritem->SetColor("hover", "color", fgHover);
|
||||
menubaritem->SetColor("hover", "background-color", bgHover);
|
||||
menubaritem->SetColor("down", "color", fgActive);
|
||||
menubaritem->SetColor("down", "background-color", bgActive);
|
||||
|
||||
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));
|
||||
menu->SetColor("color", fgMain);
|
||||
menu->SetColor("background-color", bgMain);
|
||||
menu->SetColor("border-left-color", border);
|
||||
menu->SetColor("border-top-color", border);
|
||||
menu->SetColor("border-right-color", border);
|
||||
menu->SetColor("border-bottom-color", border);
|
||||
|
||||
menuitem->SetColor("hover", "background-color", Colorf::fromRgba8(78, 78, 78));
|
||||
menuitem->SetColor("down", "background-color", Colorf::fromRgba8(88, 88, 88));
|
||||
menuitem->SetColor("hover", "color", fgHover);
|
||||
menuitem->SetColor("hover", "background-color", bgHover);
|
||||
menuitem->SetColor("down", "color", fgActive);
|
||||
menuitem->SetColor("down", "background-color", bgActive);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LightWidgetTheme::LightWidgetTheme()
|
||||
{
|
||||
auto widget = RegisterStyle(std::make_unique<BasicWidgetStyle>(), "widget");
|
||||
auto textlabel = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "textlabel");
|
||||
auto pushbutton = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "pushbutton");
|
||||
auto lineedit = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "lineedit");
|
||||
auto textedit = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "textedit");
|
||||
auto listview = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "listview");
|
||||
auto dropdown = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "dropdown");
|
||||
auto scrollbar = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "scrollbar");
|
||||
auto tabbar = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "tabbar");
|
||||
auto tabbar_tab = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "tabbar-tab");
|
||||
auto tabbar_spacer = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "tabbar-spacer");
|
||||
auto tabwidget_stack = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "tabwidget-stack");
|
||||
auto checkbox_label = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "checkbox-label");
|
||||
auto menubar = RegisterStyle(std::make_unique<BasicWidgetStyle>(widget), "menubar");
|
||||
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");
|
||||
DarkWidgetTheme::DarkWidgetTheme(): WidgetTheme({
|
||||
Colorf::fromRgb(0x2A2A2A), // background
|
||||
Colorf::fromRgb(0xE2DFDB), //
|
||||
Colorf::fromRgb(0x212121), // headers / inputs
|
||||
Colorf::fromRgb(0xE2DFDB), //
|
||||
Colorf::fromRgb(0x444444), // interactive elements
|
||||
Colorf::fromRgb(0xFFFFFF), //
|
||||
Colorf::fromRgb(0xC83C00), // hover / highlight
|
||||
Colorf::fromRgb(0xFFFFFF), //
|
||||
Colorf::fromRgb(0xBBBBBB), // click
|
||||
Colorf::fromRgb(0x000000), //
|
||||
Colorf::fromRgb(0x646464), // around elements
|
||||
Colorf::fromRgb(0x555555) // between elements
|
||||
}) {};
|
||||
|
||||
widget->SetString("font-family", "NotoSans");
|
||||
widget->SetColor("color", Colorf::fromRgba8(0, 0, 0));
|
||||
widget->SetColor("window-background", Colorf::fromRgba8(240, 240, 240));
|
||||
widget->SetColor("window-border", Colorf::fromRgba8(100, 100, 100));
|
||||
widget->SetColor("window-caption-color", Colorf::fromRgba8(70, 70, 70));
|
||||
widget->SetColor("window-caption-text-color", Colorf::fromRgba8(226, 223, 219));
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pushbutton->SetDouble("noncontent-left", 10.0);
|
||||
pushbutton->SetDouble("noncontent-top", 5.0);
|
||||
pushbutton->SetDouble("noncontent-right", 10.0);
|
||||
pushbutton->SetDouble("noncontent-bottom", 5.0);
|
||||
pushbutton->SetColor("background-color", Colorf::fromRgba8(210, 210, 210));
|
||||
pushbutton->SetColor("border-left-color", Colorf::fromRgba8(155, 155, 155));
|
||||
pushbutton->SetColor("border-top-color", Colorf::fromRgba8(155, 155, 155));
|
||||
pushbutton->SetColor("border-right-color", Colorf::fromRgba8(155, 155, 155));
|
||||
pushbutton->SetColor("border-bottom-color", Colorf::fromRgba8(155, 155, 155));
|
||||
pushbutton->SetColor("hover", "background-color", Colorf::fromRgba8(200, 200, 200));
|
||||
pushbutton->SetColor("down", "background-color", Colorf::fromRgba8(190, 190, 190));
|
||||
|
||||
lineedit->SetDouble("noncontent-left", 5.0);
|
||||
lineedit->SetDouble("noncontent-top", 3.0);
|
||||
lineedit->SetDouble("noncontent-right", 5.0);
|
||||
lineedit->SetDouble("noncontent-bottom", 3.0);
|
||||
lineedit->SetColor("background-color", Colorf::fromRgba8(255, 255, 255));
|
||||
lineedit->SetColor("border-left-color", Colorf::fromRgba8(155, 155, 155));
|
||||
lineedit->SetColor("border-top-color", Colorf::fromRgba8(155, 155, 155));
|
||||
lineedit->SetColor("border-right-color", Colorf::fromRgba8(155, 155, 155));
|
||||
lineedit->SetColor("border-bottom-color", Colorf::fromRgba8(155, 155, 155));
|
||||
lineedit->SetColor("selection-color", Colorf::fromRgba8(210, 210, 255));
|
||||
lineedit->SetColor("no-focus-selection-color", Colorf::fromRgba8(240, 240, 255));
|
||||
|
||||
textedit->SetDouble("noncontent-left", 8.0);
|
||||
textedit->SetDouble("noncontent-top", 8.0);
|
||||
textedit->SetDouble("noncontent-right", 8.0);
|
||||
textedit->SetDouble("noncontent-bottom", 8.0);
|
||||
textedit->SetColor("background-color", Colorf::fromRgba8(255, 255, 255));
|
||||
textedit->SetColor("border-left-color", Colorf::fromRgba8(155, 155, 155));
|
||||
textedit->SetColor("border-top-color", Colorf::fromRgba8(155, 155, 155));
|
||||
textedit->SetColor("border-right-color", Colorf::fromRgba8(155, 155, 155));
|
||||
textedit->SetColor("border-bottom-color", Colorf::fromRgba8(155, 155, 155));
|
||||
|
||||
listview->SetDouble("noncontent-left", 10.0);
|
||||
listview->SetDouble("noncontent-top", 10.0);
|
||||
listview->SetDouble("noncontent-right", 3.0);
|
||||
listview->SetDouble("noncontent-bottom", 10.0);
|
||||
listview->SetColor("background-color", Colorf::fromRgba8(230, 230, 230));
|
||||
listview->SetColor("border-left-color", Colorf::fromRgba8(155, 155, 155));
|
||||
listview->SetColor("border-top-color", Colorf::fromRgba8(155, 155, 155));
|
||||
listview->SetColor("border-right-color", Colorf::fromRgba8(155, 155, 155));
|
||||
listview->SetColor("border-bottom-color", Colorf::fromRgba8(155, 155, 155));
|
||||
listview->SetColor("selection-color", Colorf::fromRgba8(200, 200, 200));
|
||||
|
||||
dropdown->SetDouble("noncontent-left", 5.0);
|
||||
dropdown->SetDouble("noncontent-top", 5.0);
|
||||
dropdown->SetDouble("noncontent-right", 5.0);
|
||||
dropdown->SetDouble("noncontent-bottom", 5.0);
|
||||
dropdown->SetColor("background-color", Colorf::fromRgba8(230, 230, 230));
|
||||
dropdown->SetColor("border-left-color", Colorf::fromRgba8(155, 155, 155));
|
||||
dropdown->SetColor("border-top-color", Colorf::fromRgba8(155, 155, 155));
|
||||
dropdown->SetColor("border-right-color", Colorf::fromRgba8(155, 155, 155));
|
||||
dropdown->SetColor("border-bottom-color", Colorf::fromRgba8(155, 155, 155));
|
||||
dropdown->SetColor("selection-color", Colorf::fromRgba8(200, 200, 200));
|
||||
dropdown->SetColor("arrow-color", Colorf::fromRgba8(200, 200, 200));
|
||||
|
||||
scrollbar->SetColor("track-color", Colorf::fromRgba8(210, 210, 220));
|
||||
scrollbar->SetColor("thumb-color", Colorf::fromRgba8(180, 180, 180));
|
||||
|
||||
tabbar->SetDouble("spacer-left", 20.0);
|
||||
tabbar->SetDouble("spacer-right", 20.0);
|
||||
tabbar->SetColor("background-color", Colorf::fromRgba8(210, 210, 210));
|
||||
|
||||
tabbar_tab->SetDouble("noncontent-left", 15.0);
|
||||
tabbar_tab->SetDouble("noncontent-right", 15.0);
|
||||
tabbar_tab->SetDouble("noncontent-top", 1.0);
|
||||
tabbar_tab->SetDouble("noncontent-bottom", 1.0);
|
||||
tabbar_tab->SetColor("background-color", Colorf::fromRgba8(220, 220, 220));
|
||||
tabbar_tab->SetColor("border-left-color", Colorf::fromRgba8(200, 200, 200));
|
||||
tabbar_tab->SetColor("border-top-color", Colorf::fromRgba8(200, 200, 200));
|
||||
tabbar_tab->SetColor("border-right-color", Colorf::fromRgba8(200, 200, 200));
|
||||
tabbar_tab->SetColor("border-bottom-color", Colorf::fromRgba8(155, 155, 155));
|
||||
tabbar_tab->SetColor("hover", "background-color", Colorf::fromRgba8(210, 210, 210));
|
||||
tabbar_tab->SetColor("active", "background-color", Colorf::fromRgba8(240, 240, 240));
|
||||
tabbar_tab->SetColor("active", "border-left-color", Colorf::fromRgba8(155, 155, 155));
|
||||
tabbar_tab->SetColor("active", "border-top-color", Colorf::fromRgba8(155, 155, 155));
|
||||
tabbar_tab->SetColor("active", "border-right-color", Colorf::fromRgba8(155, 155, 155));
|
||||
tabbar_tab->SetColor("active", "border-bottom-color", Colorf::transparent());
|
||||
|
||||
tabbar_spacer->SetColor("border-bottom-color", Colorf::fromRgba8(155, 155, 155));
|
||||
|
||||
tabwidget_stack->SetDouble("noncontent-left", 20.0);
|
||||
tabwidget_stack->SetDouble("noncontent-top", 5.0);
|
||||
tabwidget_stack->SetDouble("noncontent-right", 20.0);
|
||||
tabwidget_stack->SetDouble("noncontent-bottom", 5.0);
|
||||
|
||||
checkbox_label->SetColor("checked-outer-border-color", Colorf::fromRgba8(155, 155, 155));
|
||||
checkbox_label->SetColor("checked-inner-border-color", Colorf::fromRgba8(200, 200, 200));
|
||||
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));
|
||||
|
||||
menubar->SetColor("background-color", Colorf::fromRgba8(70, 70, 70));
|
||||
|
||||
menubaritem->SetColor("color", Colorf::fromRgba8(226, 223, 219));
|
||||
menubaritem->SetColor("hover", "background-color", Colorf::fromRgba8(200, 200, 200));
|
||||
menubaritem->SetColor("hover", "color", Colorf::fromRgba8(0, 0, 0));
|
||||
menubaritem->SetColor("down", "background-color", Colorf::fromRgba8(190, 190, 190));
|
||||
menubaritem->SetColor("down", "color", Colorf::fromRgba8(0, 0, 0));
|
||||
|
||||
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("background-color", Colorf::fromRgba8(255, 255, 255));
|
||||
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));
|
||||
}
|
||||
LightWidgetTheme::LightWidgetTheme(): WidgetTheme({
|
||||
Colorf::fromRgb(0xF0F0F0), // background
|
||||
Colorf::fromRgb(0x191919), //
|
||||
Colorf::fromRgb(0xFAFAFA), // headers / inputs
|
||||
Colorf::fromRgb(0x191919), //
|
||||
Colorf::fromRgb(0xC8C8C8), // interactive elements
|
||||
Colorf::fromRgb(0x000000), //
|
||||
Colorf::fromRgb(0xD2D2FF), // hover / highlight
|
||||
Colorf::fromRgb(0x000000), //
|
||||
Colorf::fromRgb(0xC7B4FF), // click
|
||||
Colorf::fromRgb(0x000000), //
|
||||
Colorf::fromRgb(0xA0A0A0), // around elements
|
||||
Colorf::fromRgb(0xB9B9B9) // between elements
|
||||
}) {};
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ void Timer::Start(int timeoutMilliseconds, bool repeat)
|
|||
{
|
||||
Stop();
|
||||
|
||||
TimerId = DisplayWindow::StartTimer(timeoutMilliseconds, [=]() {
|
||||
TimerId = DisplayWindow::StartTimer(timeoutMilliseconds, [this,repeat]() {
|
||||
if (!repeat)
|
||||
Stop();
|
||||
if (FuncExpired)
|
||||
|
|
|
|||
|
|
@ -303,10 +303,10 @@ void TrueTypeFont::LoadGlyph(TTF_SimpleGlyph& g, uint32_t glyphIndex, int compos
|
|||
reader.Seek(loca.offsets[glyphIndex]);
|
||||
|
||||
ttf_int16 numberOfContours = reader.ReadInt16();
|
||||
ttf_int16 xMin = reader.ReadInt16();
|
||||
ttf_int16 yMin = reader.ReadInt16();
|
||||
ttf_int16 xMax = reader.ReadInt16();
|
||||
ttf_int16 yMax = reader.ReadInt16();
|
||||
/*ttf_int16 xMin =*/ reader.ReadInt16();
|
||||
/*ttf_int16 yMin =*/ reader.ReadInt16();
|
||||
/*ttf_int16 xMax =*/ reader.ReadInt16();
|
||||
/*ttf_int16 yMax =*/ reader.ReadInt16();
|
||||
|
||||
if (numberOfContours > 0) // Simple glyph
|
||||
{
|
||||
|
|
@ -450,7 +450,7 @@ void TrueTypeFont::LoadGlyph(TTF_SimpleGlyph& g, uint32_t glyphIndex, int compos
|
|||
|
||||
if (transform)
|
||||
{
|
||||
for (int i = childPointsOffset; i < g.points.size(); i++)
|
||||
for (int i = childPointsOffset; i < (int)g.points.size(); i++)
|
||||
{
|
||||
float x = g.points[i].x * mat2x2[0] + g.points[i].y * mat2x2[1];
|
||||
float y = g.points[i].x * mat2x2[2] + g.points[i].y * mat2x2[3];
|
||||
|
|
@ -492,7 +492,7 @@ void TrueTypeFont::LoadGlyph(TTF_SimpleGlyph& g, uint32_t glyphIndex, int compos
|
|||
dy = g.points[parentPointIndex].y - g.points[childPointIndex].y;
|
||||
}
|
||||
|
||||
for (int i = childPointsOffset; i < g.points.size(); i++)
|
||||
for (int i = childPointsOffset; i < (int)g.points.size(); i++)
|
||||
{
|
||||
g.points[i].x += dx;
|
||||
g.points[i].y += dy;
|
||||
|
|
@ -589,9 +589,9 @@ void TrueTypeFont::LoadCharacterMapEncoding(TrueTypeFileReader& reader)
|
|||
for (ttf_uint16 c = startCode; c <= endCode; c++)
|
||||
{
|
||||
int offset = idRangeOffset / 2 + (c - startCode) - ((int)subformat.segCount - i);
|
||||
if (offset >= 0 && offset < subformat.glyphIdArray.size())
|
||||
if (offset >= 0 && offset < (int)subformat.glyphIdArray.size())
|
||||
{
|
||||
int glyphId = subformat.glyphIdArray[offset];
|
||||
ttf_uint32 glyphId = subformat.glyphIdArray[offset];
|
||||
if (firstGlyph)
|
||||
{
|
||||
range.startGlyphID = glyphId;
|
||||
|
|
@ -689,9 +689,9 @@ void TTF_CMapSubtable4::Load(TrueTypeFileReader& reader)
|
|||
language = reader.ReadUInt16();
|
||||
|
||||
segCount = reader.ReadUInt16() / 2;
|
||||
ttf_uint16 searchRange = reader.ReadUInt16();
|
||||
ttf_uint16 entrySelector = reader.ReadUInt16();
|
||||
ttf_uint16 rangeShift = reader.ReadUInt16();
|
||||
/*ttf_uint16 searchRange =*/ reader.ReadUInt16();
|
||||
/*ttf_uint16 entrySelector =*/ reader.ReadUInt16();
|
||||
/*ttf_uint16 rangeShift =*/ reader.ReadUInt16();
|
||||
|
||||
endCode.reserve(segCount);
|
||||
startCode.reserve(segCount);
|
||||
|
|
@ -746,9 +746,9 @@ void TTF_TableDirectory::Load(TrueTypeFileReader& reader)
|
|||
numTables = reader.ReadUInt16();
|
||||
|
||||
// opentype spec says we can't use these for security reasons, so we pretend they never was part of the header
|
||||
ttf_uint16 searchRange = reader.ReadUInt16();
|
||||
ttf_uint16 entrySelector = reader.ReadUInt16();
|
||||
ttf_uint16 rangeShift = reader.ReadUInt16();
|
||||
/*ttf_uint16 searchRange =*/ reader.ReadUInt16();
|
||||
/*ttf_uint16 entrySelector =*/ reader.ReadUInt16();
|
||||
/*ttf_uint16 rangeShift =*/ reader.ReadUInt16();
|
||||
|
||||
for (ttf_uint16 i = 0; i < numTables; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ unsigned int UTF8Reader::character()
|
|||
else
|
||||
{
|
||||
unsigned int ucs4 = (data[current_position] & bitmask_leadbyte_for_utf8[trailing_bytes]);
|
||||
for (std::string::size_type i = 0; i < trailing_bytes; i++)
|
||||
for (std::string::size_type i = 0; i < (size_t)trailing_bytes; i++)
|
||||
{
|
||||
if ((data[current_position + 1 + i] & 0xC0) == 0x80)
|
||||
ucs4 = (ucs4 << 6) + (data[current_position + 1 + i] & 0x3f);
|
||||
|
|
@ -94,7 +94,7 @@ std::string::size_type UTF8Reader::char_length()
|
|||
if (current_position + 1 + trailing_bytes > length)
|
||||
return 1;
|
||||
|
||||
for (std::string::size_type i = 0; i < trailing_bytes; i++)
|
||||
for (std::string::size_type i = 0; i < (size_t)trailing_bytes; i++)
|
||||
{
|
||||
if ((data[current_position + 1 + i] & 0xC0) != 0x80)
|
||||
return 1;
|
||||
|
|
@ -136,7 +136,7 @@ void UTF8Reader::move_to_leadbyte()
|
|||
lead_position--;
|
||||
|
||||
int trailing_bytes = trailing_bytes_for_utf8[data[lead_position]];
|
||||
if (lead_position + trailing_bytes >= current_position)
|
||||
if (lead_position + trailing_bytes >= (int)current_position)
|
||||
current_position = lead_position;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ Dropdown::Dropdown(Widget* parent) : Widget(parent)
|
|||
}
|
||||
|
||||
DropdownList::DropdownList(Widget* parent, Dropdown* owner) : ListView(parent), owner(owner)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
void DropdownList::OnKeyDown(InputKey key)
|
||||
{
|
||||
|
|
@ -124,7 +125,7 @@ void Dropdown::ClearItems()
|
|||
void Dropdown::SetSelectedItem(int index)
|
||||
{
|
||||
if (index < 0) index = 0;
|
||||
if (index >= (int)items.size()) index = items.size() - 1;
|
||||
if (index >= (int)items.size()) index = (int)items.size() - 1;
|
||||
|
||||
if (selectedItem == index) return;
|
||||
|
||||
|
|
@ -270,7 +271,7 @@ void Dropdown::OnGeometryChanged()
|
|||
Point pos = MapTo(Window(), Point(0,0));
|
||||
|
||||
double width = GetWidth() + GetNoncontentLeft() + GetNoncontentRight();
|
||||
double innerH = GetDisplayItems() * 25.0 + 10.0;
|
||||
double innerH = GetDisplayItems() * 20.0 + 20;
|
||||
double outerH = GetHeight();
|
||||
|
||||
pos.x -= GetNoncontentLeft();
|
||||
|
|
@ -311,14 +312,14 @@ bool Dropdown::OpenDropdown()
|
|||
|
||||
listView->SetSelectedItem(selectedItem);
|
||||
|
||||
listView->OnActivated = [=]() { OnDropdownActivated(); };
|
||||
listView->OnChanged = [=](int index) { OnDropdownActivated(); };
|
||||
listView->OnActivated = [this]() { OnDropdownActivated(); };
|
||||
listView->OnChanged = [this](int index) { OnDropdownActivated(); };
|
||||
|
||||
listView->SetFrameGeometry(
|
||||
0,
|
||||
0,
|
||||
GetWidth() + GetNoncontentLeft() + GetNoncontentRight(),
|
||||
GetDisplayItems() * 25.0 + 10.0
|
||||
GetDisplayItems() * 20.0 + 20
|
||||
);
|
||||
OnGeometryChanged();
|
||||
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ LineEdit::LineEdit(Widget* parent) : Widget(parent)
|
|||
SetStyleClass("lineedit");
|
||||
|
||||
timer = new Timer(this);
|
||||
timer->FuncExpired = [=]() { OnTimerExpired(); };
|
||||
timer->FuncExpired = [this]() { OnTimerExpired(); };
|
||||
|
||||
scroll_timer = new Timer(this);
|
||||
scroll_timer->FuncExpired = [=]() { OnScrollTimerExpired(); };
|
||||
scroll_timer->FuncExpired = [this]() { OnScrollTimerExpired(); };
|
||||
|
||||
SetCursor(StandardCursor::ibeam);
|
||||
}
|
||||
|
|
@ -90,12 +90,16 @@ int LineEdit::GetCursorPos() const
|
|||
Size LineEdit::GetTextSize()
|
||||
{
|
||||
Canvas* canvas = GetCanvas();
|
||||
if (!canvas)
|
||||
return Size(0.0, 0.0);
|
||||
return GetVisualTextSize(canvas);
|
||||
}
|
||||
|
||||
Size LineEdit::GetTextSize(const std::string& str)
|
||||
{
|
||||
Canvas* canvas = GetCanvas();
|
||||
if (!canvas)
|
||||
return Size(0.0, 0.0);
|
||||
return canvas->measureText(str).size();
|
||||
}
|
||||
|
||||
|
|
@ -674,7 +678,7 @@ bool LineEdit::InsertText(int pos, const std::string& str)
|
|||
}
|
||||
|
||||
// checking if insert exceeds max length
|
||||
if (UTF8Reader::utf8_length(text) + UTF8Reader::utf8_length(str) > max_length)
|
||||
if (UTF8Reader::utf8_length(text) + UTF8Reader::utf8_length(str) > (size_t)max_length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -757,6 +761,9 @@ int LineEdit::GetCharacterIndex(double mouse_x)
|
|||
}
|
||||
|
||||
Canvas* canvas = GetCanvas();
|
||||
if (!canvas)
|
||||
return 0;
|
||||
|
||||
UTF8Reader utf8_reader(text.data(), text.length());
|
||||
|
||||
int seek_start = clip_start_offset;
|
||||
|
|
@ -808,7 +815,7 @@ void LineEdit::UpdateTextClipping()
|
|||
if (!canvas)
|
||||
return;
|
||||
|
||||
Size text_size = GetVisualTextSize(canvas, clip_start_offset, (int)text.size() - clip_start_offset);
|
||||
// Size text_size = GetVisualTextSize(canvas, clip_start_offset, (int)text.size() - clip_start_offset);
|
||||
|
||||
if (cursor_pos < clip_start_offset)
|
||||
clip_start_offset = cursor_pos;
|
||||
|
|
@ -822,7 +829,7 @@ void LineEdit::UpdateTextClipping()
|
|||
utf8_reader.set_position(clip_start_offset);
|
||||
utf8_reader.next();
|
||||
clip_start_offset = (int)utf8_reader.position();
|
||||
if (clip_start_offset == text.size())
|
||||
if (clip_start_offset == (int)text.size())
|
||||
break;
|
||||
cursor_rect = GetCursorRect();
|
||||
}
|
||||
|
|
@ -837,7 +844,7 @@ void LineEdit::UpdateTextClipping()
|
|||
|
||||
utf8_reader.set_position(midpoint);
|
||||
utf8_reader.move_to_leadbyte();
|
||||
if (midpoint != utf8_reader.position())
|
||||
if (midpoint != (int)utf8_reader.position())
|
||||
utf8_reader.next();
|
||||
midpoint = (int)utf8_reader.position();
|
||||
|
||||
|
|
@ -862,6 +869,8 @@ void LineEdit::UpdateTextClipping()
|
|||
Rect LineEdit::GetCursorRect()
|
||||
{
|
||||
Canvas* canvas = GetCanvas();
|
||||
if (!canvas)
|
||||
return Rect::xywh(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
int substr_end = cursor_pos - clip_start_offset;
|
||||
if (substr_end < 0)
|
||||
|
|
@ -890,6 +899,8 @@ Rect LineEdit::GetCursorRect()
|
|||
Rect LineEdit::GetSelectionRect()
|
||||
{
|
||||
Canvas* canvas = GetCanvas();
|
||||
if (!canvas)
|
||||
return Rect::xywh(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
// text before selection:
|
||||
|
||||
|
|
@ -949,6 +960,8 @@ void LineEdit::OnTimerExpired()
|
|||
void LineEdit::OnGeometryChanged()
|
||||
{
|
||||
Canvas* canvas = GetCanvas();
|
||||
if (!canvas)
|
||||
return;
|
||||
|
||||
vertical_text_align = canvas->verticalTextAlign();
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ ListView::ListView(Widget* parent) : Widget(parent)
|
|||
SetStyleClass("listview");
|
||||
|
||||
scrollbar = new Scrollbar(this);
|
||||
scrollbar->FuncScroll = [=]() { OnScrollbarScroll(); };
|
||||
scrollbar->FuncScroll = [this]() { OnScrollbarScroll(); };
|
||||
|
||||
SetColumnWidths({ 0.0 });
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ void ListView::SetColumnWidths(const std::vector<double>& widths)
|
|||
|
||||
void ListView::AddItem(const std::string& text, int index, int column)
|
||||
{
|
||||
if (column < 0 || column >= columnwidths.size())
|
||||
if (column < 0 || column >= (int)columnwidths.size())
|
||||
return;
|
||||
|
||||
std::vector<std::string> newEntry;
|
||||
|
|
@ -47,10 +47,10 @@ void ListView::AddItem(const std::string& text, int index, int column)
|
|||
newEntry[column] = text;
|
||||
if (index >= 0)
|
||||
{
|
||||
if (index >= items.size())
|
||||
if (index >= (int)items.size())
|
||||
{
|
||||
newEntry[column] = "";
|
||||
while (items.size() < index)
|
||||
while ((int)items.size() < index)
|
||||
items.push_back(newEntry);
|
||||
|
||||
newEntry[column] = text;
|
||||
|
|
@ -71,7 +71,7 @@ void ListView::AddItem(const std::string& text, int index, int column)
|
|||
|
||||
void ListView::UpdateItem(const std::string& text, int index, int column)
|
||||
{
|
||||
if (index < 0 || index >= items.size() || column < 0 || column >= columnwidths.size())
|
||||
if (index < 0 || index >= (int)items.size() || column < 0 || column >= (int)columnwidths.size())
|
||||
return;
|
||||
|
||||
items[index][column] = text;
|
||||
|
|
@ -80,7 +80,7 @@ void ListView::UpdateItem(const std::string& text, int index, int column)
|
|||
|
||||
void ListView::RemoveItem(int index)
|
||||
{
|
||||
if (!items.size() || index >= items.size())
|
||||
if (!items.size() || index >= (int)items.size())
|
||||
return;
|
||||
|
||||
if (index < 0)
|
||||
|
|
@ -102,7 +102,7 @@ void ListView::Activate()
|
|||
|
||||
void ListView::SetSelectedItem(int index)
|
||||
{
|
||||
if (selectedItem != index && index >= 0 && index < items.size())
|
||||
if (selectedItem != index && index >= 0 && index < (int)items.size())
|
||||
{
|
||||
selectedItem = index;
|
||||
if (OnChanged) OnChanged(selectedItem);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ void Menubar::ShowMenu(MenubarItem* item)
|
|||
if (item->GetOpenCallback())
|
||||
{
|
||||
openMenu = new Menu(this);
|
||||
openMenu->onCloseMenu = [=]() { CloseMenu(); };
|
||||
openMenu->onCloseMenu = [this]() { CloseMenu(); };
|
||||
item->GetOpenCallback()(openMenu);
|
||||
if (item->AlignRight)
|
||||
openMenu->SetRightPosition(item->MapToGlobal(Point(item->GetWidth(), item->GetHeight())));
|
||||
|
|
@ -215,7 +215,7 @@ void Menubar::OnKeyDown(InputKey key)
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MenubarItem::MenubarItem(Menubar* menubar, std::string text, bool alignRight) : Widget(menubar), menubar(menubar), text(text), AlignRight(alignRight)
|
||||
MenubarItem::MenubarItem(Menubar* menubar, std::string text, bool alignRight) : Widget(menubar), AlignRight(alignRight), menubar(menubar), text(text)
|
||||
{
|
||||
SetStyleClass("menubaritem");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,16 @@
|
|||
#include "core/colorf.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#define HIDE_SMALL_BAR false
|
||||
#define HIDE_SMALL_THUMB true
|
||||
|
||||
Scrollbar::Scrollbar(Widget* parent) : Widget(parent)
|
||||
{
|
||||
SetStyleClass("scrollbar");
|
||||
UpdatePartPositions();
|
||||
|
||||
mouse_down_timer = new Timer(this);
|
||||
mouse_down_timer->FuncExpired = [=]() { OnTimerExpired(); };
|
||||
mouse_down_timer->FuncExpired = [this]() { OnTimerExpired(); };
|
||||
}
|
||||
|
||||
Scrollbar::~Scrollbar()
|
||||
|
|
@ -295,7 +298,15 @@ void Scrollbar::OnPaint(Canvas* canvas)
|
|||
part_button_increment.render_box(canvas, rect_button_increment);
|
||||
*/
|
||||
|
||||
canvas->fillRect(Rect::shrink(Rect::xywh(0.0, 0.0, GetWidth(), GetHeight()), 4.0, 0.0, 4.0, 0.0), GetStyleColor("track-color"));
|
||||
auto height = GetHeight();
|
||||
auto paint = rect_thumb.height < height;
|
||||
|
||||
if (HIDE_SMALL_BAR && !paint) return;
|
||||
|
||||
canvas->fillRect(Rect::shrink(Rect::xywh(0.0, 0.0, GetWidth(), height), 4.0, 0.0, 4.0, 0.0), GetStyleColor("track-color"));
|
||||
|
||||
if (HIDE_SMALL_THUMB && !paint) return;
|
||||
|
||||
canvas->fillRect(Rect::shrink(rect_thumb, 4.0, 0.0, 4.0, 0.0), GetStyleColor("thumb-color"));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ TabWidget::TabWidget(Widget* parent) : Widget(parent)
|
|||
Bar = new TabBar(this);
|
||||
PageStack = new TabWidgetStack(this);
|
||||
|
||||
Bar->OnCurrentChanged = [=]() { OnBarCurrentChanged(); };
|
||||
Bar->OnCurrentChanged = [this]() { OnBarCurrentChanged(); };
|
||||
}
|
||||
|
||||
int TabWidget::AddTab(Widget* page, const std::string& label)
|
||||
|
|
@ -127,7 +127,7 @@ int TabBar::AddTab(const std::shared_ptr<Image>& icon, const std::string& label)
|
|||
TabBarTab* tab = new TabBarTab(this);
|
||||
tab->SetIcon(icon);
|
||||
tab->SetText(label);
|
||||
tab->OnClick = [=]() { OnTabClicked(tab); };
|
||||
tab->OnClick = [this,tab]() { OnTabClicked(tab); };
|
||||
int pageIndex = (int)Tabs.size();
|
||||
Tabs.push_back(tab);
|
||||
if (CurrentIndex == -1)
|
||||
|
|
|
|||
|
|
@ -13,11 +13,14 @@ TextEdit::TextEdit(Widget* parent) : Widget(parent)
|
|||
{
|
||||
SetStyleClass("textedit");
|
||||
|
||||
selectionBG = GetStyleColor("selection-color");
|
||||
selectionFG = GetStyleColor("color");
|
||||
|
||||
timer = new Timer(this);
|
||||
timer->FuncExpired = [=]() { OnTimerExpired(); };
|
||||
timer->FuncExpired = [this]() { OnTimerExpired(); };
|
||||
|
||||
scroll_timer = new Timer(this);
|
||||
scroll_timer->FuncExpired = [=]() { OnScrollTimerExpired(); };
|
||||
scroll_timer->FuncExpired = [this]() { OnScrollTimerExpired(); };
|
||||
|
||||
SetCursor(StandardCursor::ibeam);
|
||||
|
||||
|
|
@ -175,13 +178,13 @@ void TextEdit::SetText(const std::string& text)
|
|||
std::string::size_type end = text.find('\n');
|
||||
while (end != std::string::npos)
|
||||
{
|
||||
TextEdit::Line line;
|
||||
TextEdit::Line line{this};
|
||||
line.text = text.substr(start, end - start);
|
||||
lines.push_back(line);
|
||||
start = end + 1;
|
||||
end = text.find('\n', start);
|
||||
}
|
||||
TextEdit::Line line;
|
||||
TextEdit::Line line{this};
|
||||
line.text = text.substr(start);
|
||||
lines.push_back(line);
|
||||
|
||||
|
|
@ -197,13 +200,13 @@ void TextEdit::AddText(const std::string& text)
|
|||
std::string::size_type end = text.find('\n');
|
||||
while (end != std::string::npos)
|
||||
{
|
||||
TextEdit::Line line;
|
||||
TextEdit::Line line{this};
|
||||
line.text = text.substr(start, end - start);
|
||||
lines.push_back(line);
|
||||
start = end + 1;
|
||||
end = text.find('\n', start);
|
||||
}
|
||||
TextEdit::Line line;
|
||||
TextEdit::Line line{this};
|
||||
line.text = text.substr(start);
|
||||
lines.push_back(line);
|
||||
|
||||
|
|
@ -434,7 +437,7 @@ void TextEdit::OnKeyDown(InputKey key)
|
|||
if (GetKeyState(InputKey::Shift) && selection_length == 0)
|
||||
selection_start = cursor_pos;
|
||||
|
||||
if (cursor_pos.y < lines.size() - 1)
|
||||
if (cursor_pos.y < (int)lines.size() - 1)
|
||||
{
|
||||
cursor_pos.y++;
|
||||
cursor_pos.x = std::min(lines[cursor_pos.y].text.size(), (size_t)cursor_pos.x);
|
||||
|
|
@ -578,7 +581,7 @@ void TextEdit::OnLostFocus()
|
|||
void TextEdit::CreateComponents()
|
||||
{
|
||||
vert_scrollbar = new Scrollbar(this);
|
||||
vert_scrollbar->FuncScroll = [=]() { OnVerticalScroll(); };
|
||||
vert_scrollbar->FuncScroll = [this]() { OnVerticalScroll(); };
|
||||
vert_scrollbar->SetVisible(false);
|
||||
vert_scrollbar->SetVertical();
|
||||
}
|
||||
|
|
@ -714,10 +717,10 @@ TextEdit::ivec2 TextEdit::FindNextBreakCharacter(ivec2 search_start)
|
|||
if (search_start.x >= int(lines[search_start.y].text.size()) - 1)
|
||||
return ivec2(lines[search_start.y].text.size(), search_start.y);
|
||||
|
||||
int pos = lines[search_start.y].text.find_first_of(break_characters, search_start.x);
|
||||
size_t pos = lines[search_start.y].text.find_first_of(break_characters, search_start.x);
|
||||
if (pos == std::string::npos)
|
||||
return ivec2(lines[search_start.y].text.size(), search_start.y);
|
||||
return ivec2(pos, search_start.y);
|
||||
return ivec2((int)pos, search_start.y);
|
||||
}
|
||||
|
||||
TextEdit::ivec2 TextEdit::FindPreviousBreakCharacter(ivec2 search_start)
|
||||
|
|
@ -725,10 +728,10 @@ TextEdit::ivec2 TextEdit::FindPreviousBreakCharacter(ivec2 search_start)
|
|||
search_start.x--;
|
||||
if (search_start.x <= 0)
|
||||
return ivec2(0, search_start.y);
|
||||
int pos = lines[search_start.y].text.find_last_of(break_characters, search_start.x);
|
||||
size_t pos = lines[search_start.y].text.find_last_of(break_characters, search_start.x);
|
||||
if (pos == std::string::npos)
|
||||
return ivec2(0, search_start.y);
|
||||
return ivec2(pos, search_start.y);
|
||||
return ivec2((int)pos, search_start.y);
|
||||
}
|
||||
|
||||
void TextEdit::InsertText(ivec2 pos, const std::string& str)
|
||||
|
|
@ -741,7 +744,7 @@ void TextEdit::InsertText(ivec2 pos, const std::string& str)
|
|||
}
|
||||
|
||||
// checking if insert exceeds max length
|
||||
if (ToOffset(ivec2(lines[lines.size() - 1].text.size(), lines.size() - 1)) + str.length() > max_length)
|
||||
if (ToOffset(ivec2((int)lines[lines.size() - 1].text.size(), (int)lines.size() - 1)) + str.length() > (size_t)max_length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -759,7 +762,7 @@ void TextEdit::InsertText(ivec2 pos, const std::string& str)
|
|||
|
||||
pos.x += next_newline - start;
|
||||
|
||||
Line line;
|
||||
Line line{this};
|
||||
line.text = lines[pos.y].text.substr(pos.x);
|
||||
lines.insert(lines.begin() + pos.y + 1, line);
|
||||
lines[pos.y].text = lines[pos.y].text.substr(0, pos.x);
|
||||
|
|
@ -836,9 +839,9 @@ void TextEdit::Del()
|
|||
lines[cursor_pos.y].invalidated = true;
|
||||
Update();
|
||||
}
|
||||
else if (cursor_pos.y + 1 < lines.size())
|
||||
else if (cursor_pos.y + 1 < (int)lines.size())
|
||||
{
|
||||
selection_start = ivec2(lines[cursor_pos.y].text.length(), cursor_pos.y);
|
||||
selection_start = ivec2((int)lines[cursor_pos.y].text.length(), cursor_pos.y);
|
||||
selection_length = 1;
|
||||
DeleteSelectedText();
|
||||
}
|
||||
|
|
@ -904,7 +907,7 @@ bool TextEdit::InputMaskAcceptsInput(ivec2 cursor_pos, const std::string& str)
|
|||
|
||||
std::string::size_type TextEdit::ToOffset(ivec2 pos) const
|
||||
{
|
||||
if (pos.y < lines.size())
|
||||
if (pos.y < (int)lines.size())
|
||||
{
|
||||
std::string::size_type offset = 0;
|
||||
for (int line = 0; line < pos.y; line++)
|
||||
|
|
@ -927,7 +930,7 @@ std::string::size_type TextEdit::ToOffset(ivec2 pos) const
|
|||
TextEdit::ivec2 TextEdit::FromOffset(std::string::size_type offset) const
|
||||
{
|
||||
int line_offset = 0;
|
||||
for (int line = 0; line < lines.size(); line++)
|
||||
for (int line = 0; line < (int)lines.size(); line++)
|
||||
{
|
||||
if (offset <= line_offset + lines[line].text.size())
|
||||
{
|
||||
|
|
@ -984,9 +987,9 @@ void TextEdit::LayoutLines(Canvas* canvas)
|
|||
line.invalidated = false;
|
||||
}
|
||||
|
||||
if (sel_start != sel_end && sel_start.y <= i && sel_end.y >= i)
|
||||
if (sel_start != sel_end && sel_start.y <= (int)i && sel_end.y >= (int)i)
|
||||
{
|
||||
line.layout.SetSelectionRange(sel_start.y < i ? 0 : sel_start.x, sel_end.y > i ? line.text.size() : sel_end.x);
|
||||
line.layout.SetSelectionRange(sel_start.y < (int)i ? 0 : sel_start.x, sel_end.y > (int)i ? line.text.size() : sel_end.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -996,7 +999,7 @@ void TextEdit::LayoutLines(Canvas* canvas)
|
|||
line.layout.HideCursor();
|
||||
if (HasFocus())
|
||||
{
|
||||
if (cursor_blink_visible && cursor_pos.y == i)
|
||||
if (cursor_blink_visible && cursor_pos.y == (int)i)
|
||||
{
|
||||
line.layout.SetCursorPos(cursor_pos.x);
|
||||
line.layout.SetCursorColor(textColor);
|
||||
|
|
@ -1035,6 +1038,7 @@ TextEdit::ivec2 TextEdit::GetCharacterIndex(Point mouse_wincoords)
|
|||
return ivec2(clamp(result.offset, (size_t)0, line.text.size()), i);
|
||||
case SpanLayout::HitTestResult::outside_left:
|
||||
return ivec2(0, i);
|
||||
default:
|
||||
case SpanLayout::HitTestResult::outside_right:
|
||||
return ivec2(line.text.size(), i);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,8 +73,7 @@ std::vector<std::string> SDL2DisplayWindow::GetVulkanInstanceExtensions()
|
|||
VkSurfaceKHR SDL2DisplayWindow::CreateVulkanSurface(VkInstance instance)
|
||||
{
|
||||
VkSurfaceKHR surfaceHandle = {};
|
||||
SDL_Vulkan_CreateSurface(Handle.window, instance, &surfaceHandle);
|
||||
if (surfaceHandle)
|
||||
if (SDL_Vulkan_CreateSurface(Handle.window, instance, &surfaceHandle) != SDL_TRUE)
|
||||
throw std::runtime_error("Could not create vulkan surface");
|
||||
return surfaceHandle;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "win32_display_window.h"
|
||||
#include "core/widget.h"
|
||||
#include <stdexcept>
|
||||
#include <exception>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
|
@ -14,6 +15,65 @@ Win32OpenFileDialog::Win32OpenFileDialog(Win32DisplayWindow* owner) : owner(owne
|
|||
|
||||
bool Win32OpenFileDialog::Show()
|
||||
{
|
||||
// For some reason this can hang deep inside Win32 if we do it on the calling thread!
|
||||
bool done = false;
|
||||
std::mutex mutex;
|
||||
std::condition_variable condvar;
|
||||
bool showResult = false;
|
||||
std::exception_ptr exception;
|
||||
|
||||
std::thread thread([&]() {
|
||||
|
||||
try
|
||||
{
|
||||
showResult = ShowWorkerThread();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
exception = std::current_exception();
|
||||
}
|
||||
|
||||
std::unique_lock lock(mutex);
|
||||
done = true;
|
||||
condvar.notify_all();
|
||||
|
||||
});
|
||||
|
||||
std::unique_lock lock(mutex);
|
||||
while (!done)
|
||||
{
|
||||
DisplayBackend::Get()->ProcessEvents();
|
||||
using namespace std::chrono_literals;
|
||||
condvar.wait_for(lock, 50ms, [&]() { return done; });
|
||||
}
|
||||
lock.unlock();
|
||||
thread.join();
|
||||
|
||||
if (exception)
|
||||
std::rethrow_exception(exception);
|
||||
|
||||
return showResult;
|
||||
}
|
||||
|
||||
bool Win32OpenFileDialog::ShowWorkerThread()
|
||||
{
|
||||
class InitCOM
|
||||
{
|
||||
public:
|
||||
InitCOM()
|
||||
{
|
||||
HRESULT result = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
if (FAILED(result))
|
||||
throw std::runtime_error("CoInitializeEx(COINIT_APARTMENTTHREADED) failed");
|
||||
}
|
||||
|
||||
~InitCOM()
|
||||
{
|
||||
CoUninitialize();
|
||||
}
|
||||
};
|
||||
InitCOM initCOM;
|
||||
|
||||
std::wstring title16 = to_utf16(title);
|
||||
std::wstring initial_directory16 = to_utf16(initial_directory);
|
||||
|
||||
|
|
@ -92,35 +152,10 @@ bool Win32OpenFileDialog::Show()
|
|||
}
|
||||
}
|
||||
|
||||
// For some reason this can hang deep inside Win32 if we do it on the calling thread!
|
||||
{
|
||||
bool done = false;
|
||||
std::mutex mutex;
|
||||
std::condition_variable condvar;
|
||||
|
||||
std::thread thread([&]() {
|
||||
|
||||
if (owner)
|
||||
result = open_dialog->Show(owner->WindowHandle.hwnd);
|
||||
else
|
||||
result = open_dialog->Show(0);
|
||||
|
||||
std::unique_lock lock(mutex);
|
||||
done = true;
|
||||
condvar.notify_all();
|
||||
|
||||
});
|
||||
|
||||
std::unique_lock lock(mutex);
|
||||
while (!done)
|
||||
{
|
||||
DisplayBackend::Get()->ProcessEvents();
|
||||
using namespace std::chrono_literals;
|
||||
condvar.wait_for(lock, 50ms, [&]() { return done; });
|
||||
}
|
||||
lock.unlock();
|
||||
thread.join();
|
||||
}
|
||||
if (owner)
|
||||
result = open_dialog->Show(owner->WindowHandle.hwnd);
|
||||
else
|
||||
result = open_dialog->Show(0);
|
||||
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ public:
|
|||
void SetDefaultExtension(const std::string& extension) override;
|
||||
|
||||
private:
|
||||
bool ShowWorkerThread();
|
||||
void throw_if_failed(HRESULT result, const std::string& error);
|
||||
|
||||
Win32DisplayWindow* owner = nullptr;
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ class X11Connection
|
|||
public:
|
||||
X11Connection()
|
||||
{
|
||||
// If we ever want to support windows on multiple threads:
|
||||
// XInitThreads();
|
||||
// This is required by vulkan
|
||||
XInitThreads();
|
||||
|
||||
display = XOpenDisplay(nullptr);
|
||||
if (!display)
|
||||
|
|
@ -35,6 +35,47 @@ public:
|
|||
XSetLocaleModifiers("@im=none");
|
||||
xim = XOpenIM(display, 0, 0, 0);
|
||||
}
|
||||
|
||||
// Look for XInput support
|
||||
int event = 0, error = 0;
|
||||
if (XQueryExtension(display, "XInputExtension", &XInputOpcode, &event, &error))
|
||||
{
|
||||
// We need XInput 2.0 support
|
||||
int major = 2, minor = 0;
|
||||
if (XIQueryVersion(display, &major, &minor) != BadRequest)
|
||||
{
|
||||
// And we need a master pointer ID
|
||||
int ndevices = 0;
|
||||
XIDeviceInfo *devices = XIQueryDevice(display, XIAllDevices, &ndevices);
|
||||
if (devices)
|
||||
{
|
||||
for (int i = 0; i < ndevices; i++)
|
||||
{
|
||||
if (devices[i].use == XIMasterPointer)
|
||||
{
|
||||
MasterPointerID = devices[i].deviceid;
|
||||
XInput2Supported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XIFreeDeviceInfo(devices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This XInput API is the gift that just keeps on giving. Instead of routing events to the
|
||||
// focus window it sends it to the root window. Thanks!
|
||||
if (XInput2Supported)
|
||||
{
|
||||
unsigned char mask[3] = { 0 };
|
||||
XISetMask(mask, XI_RawMotion);
|
||||
XIEventMask eventmask;
|
||||
eventmask.deviceid = MasterPointerID;
|
||||
eventmask.mask_len = sizeof(mask);
|
||||
eventmask.mask = mask;
|
||||
Window root = XRootWindow(display, XDefaultScreen(display));
|
||||
XISelectEvents(display, root, &eventmask, 1);
|
||||
}
|
||||
}
|
||||
|
||||
~X11Connection()
|
||||
|
|
@ -53,6 +94,9 @@ public:
|
|||
bool ExitRunLoop = false;
|
||||
|
||||
XIM xim = nullptr;
|
||||
bool XInput2Supported = false;
|
||||
int XInputOpcode = 0;
|
||||
int MasterPointerID = 0;
|
||||
};
|
||||
|
||||
static X11Connection* GetX11Connection()
|
||||
|
|
@ -75,18 +119,22 @@ static Atom GetAtom(const std::string& name)
|
|||
|
||||
X11DisplayWindow::X11DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, X11DisplayWindow* owner, RenderAPI renderAPI) : windowHost(windowHost), owner(owner)
|
||||
{
|
||||
display = GetX11Connection()->display;
|
||||
auto connection = GetX11Connection();
|
||||
display = connection->display;
|
||||
|
||||
screen = XDefaultScreen(display);
|
||||
depth = XDefaultDepth(display, screen);
|
||||
visual = XDefaultVisual(display, screen);
|
||||
colormap = XDefaultColormap(display, screen);
|
||||
|
||||
int disp_width_px = XDisplayWidth(display, screen);
|
||||
int disp_height_px = XDisplayHeight(display, screen);
|
||||
int disp_width_mm = XDisplayWidthMM(display, screen);
|
||||
double ppi = (disp_width_mm < 24) ? 96.0 : (25.4 * static_cast<double>(disp_width_px) / static_cast<double>(disp_width_mm));
|
||||
dpiScale = std::round(ppi / 96.0 * 4.0) / 4.0; // 100%, 125%, 150%, 175%, 200%, etc.
|
||||
if (char* value = XGetDefault(display, "Xft", "dpi"))
|
||||
{
|
||||
int dpi = std::atoi(value);
|
||||
if (dpi != 0)
|
||||
{
|
||||
dpiScale = dpi / 96.0;
|
||||
}
|
||||
}
|
||||
|
||||
XSetWindowAttributes attributes = {};
|
||||
attributes.backing_store = Always;
|
||||
|
|
@ -94,14 +142,32 @@ X11DisplayWindow::X11DisplayWindow(DisplayWindowHost* windowHost, bool popupWind
|
|||
attributes.save_under = popupWindow ? True : False;
|
||||
attributes.colormap = colormap;
|
||||
attributes.event_mask =
|
||||
KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
|
||||
EnterWindowMask | LeaveWindowMask | PointerMotionMask | KeymapStateMask |
|
||||
KeyPressMask | KeyReleaseMask |
|
||||
EnterWindowMask | LeaveWindowMask | KeymapStateMask |
|
||||
ExposureMask | StructureNotifyMask | FocusChangeMask | PropertyChangeMask;
|
||||
|
||||
if (!connection->XInput2Supported)
|
||||
{
|
||||
attributes.event_mask |= ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
|
||||
}
|
||||
|
||||
unsigned long mask = CWBackingStore | CWSaveUnder | CWEventMask | CWOverrideRedirect;
|
||||
|
||||
window = XCreateWindow(display, XRootWindow(display, screen), 0, 0, 100, 100, 0, depth, InputOutput, visual, mask, &attributes);
|
||||
GetX11Connection()->windows[window] = this;
|
||||
connection->windows[window] = this;
|
||||
|
||||
if (connection->XInput2Supported)
|
||||
{
|
||||
unsigned char mask[1] = { 0 };
|
||||
XISetMask(mask, XI_ButtonPress);
|
||||
XISetMask(mask, XI_ButtonRelease);
|
||||
XISetMask(mask, XI_Motion);
|
||||
XIEventMask eventmask;
|
||||
eventmask.deviceid = connection->MasterPointerID;
|
||||
eventmask.mask_len = sizeof(mask);
|
||||
eventmask.mask = mask;
|
||||
XISelectEvents(display, window, &eventmask, 1);
|
||||
}
|
||||
|
||||
if (owner)
|
||||
{
|
||||
|
|
@ -158,10 +224,10 @@ X11DisplayWindow::X11DisplayWindow(DisplayWindowHost* windowHost, bool popupWind
|
|||
}
|
||||
|
||||
// Create input context
|
||||
if (GetX11Connection()->xim)
|
||||
if (connection->xim)
|
||||
{
|
||||
xic = XCreateIC(
|
||||
GetX11Connection()->xim,
|
||||
connection->xim,
|
||||
XNInputStyle,
|
||||
XIMPreeditNothing | XIMStatusNothing,
|
||||
XNClientWindow, window,
|
||||
|
|
@ -378,7 +444,7 @@ Rect X11DisplayWindow::GetWindowFrame() const
|
|||
unsigned int height = 0;
|
||||
unsigned int borderwidth = 0;
|
||||
unsigned int depth = 0;
|
||||
Status status = XGetGeometry(display, window, &root, &x, &y, &width, &height, &borderwidth, &depth);
|
||||
/*Status status =*/ XGetGeometry(display, window, &root, &x, &y, &width, &height, &borderwidth, &depth);
|
||||
|
||||
return Rect::xywh(x / dpiscale, y / dpiscale, width / dpiscale, height / dpiscale);
|
||||
}
|
||||
|
|
@ -394,7 +460,7 @@ Size X11DisplayWindow::GetClientSize() const
|
|||
unsigned int height = 0;
|
||||
unsigned int borderwidth = 0;
|
||||
unsigned int depth = 0;
|
||||
Status status = XGetGeometry(display, window, &root, &x, &y, &width, &height, &borderwidth, &depth);
|
||||
/*Status status =*/ XGetGeometry(display, window, &root, &x, &y, &width, &height, &borderwidth, &depth);
|
||||
|
||||
return Size(width / dpiscale, height / dpiscale);
|
||||
}
|
||||
|
|
@ -408,7 +474,7 @@ int X11DisplayWindow::GetPixelWidth() const
|
|||
unsigned int height = 0;
|
||||
unsigned int borderwidth = 0;
|
||||
unsigned int depth = 0;
|
||||
Status status = XGetGeometry(display, window, &root, &x, &y, &width, &height, &borderwidth, &depth);
|
||||
/*Status status =*/ XGetGeometry(display, window, &root, &x, &y, &width, &height, &borderwidth, &depth);
|
||||
return width;
|
||||
}
|
||||
|
||||
|
|
@ -421,7 +487,7 @@ int X11DisplayWindow::GetPixelHeight() const
|
|||
unsigned int height = 0;
|
||||
unsigned int borderwidth = 0;
|
||||
unsigned int depth = 0;
|
||||
Status status = XGetGeometry(display, window, &root, &x, &y, &width, &height, &borderwidth, &depth);
|
||||
/*Status status =*/ XGetGeometry(display, window, &root, &x, &y, &width, &height, &borderwidth, &depth);
|
||||
return height;
|
||||
}
|
||||
|
||||
|
|
@ -486,8 +552,8 @@ void X11DisplayWindow::SetCaptionTextColor(uint32_t bgra8)
|
|||
std::vector<uint8_t> X11DisplayWindow::GetWindowProperty(Atom property, Atom &actual_type, int &actual_format, unsigned long &item_count)
|
||||
{
|
||||
long read_bytes = 0;
|
||||
Atom _actual_type = actual_type;
|
||||
int _actual_format = actual_format;
|
||||
//Atom _actual_type = actual_type;
|
||||
//int _actual_format = actual_format;
|
||||
unsigned long _item_count = item_count;
|
||||
unsigned long bytes_remaining = 0;
|
||||
unsigned char *read_data = nullptr;
|
||||
|
|
@ -565,7 +631,7 @@ Point X11DisplayWindow::MapFromGlobal(const Point& pos) const
|
|||
int srcy = (int)std::round(pos.y * dpiscale);
|
||||
int destx = 0;
|
||||
int desty = 0;
|
||||
Bool result = XTranslateCoordinates(display, root, window, srcx, srcy, &destx, &desty, &child);
|
||||
/*Bool result =*/ XTranslateCoordinates(display, root, window, srcx, srcy, &destx, &desty, &child);
|
||||
return Point(destx / dpiscale, desty / dpiscale);
|
||||
}
|
||||
|
||||
|
|
@ -578,7 +644,7 @@ Point X11DisplayWindow::MapToGlobal(const Point& pos) const
|
|||
int srcy = (int)std::round(pos.y * dpiscale);
|
||||
int destx = 0;
|
||||
int desty = 0;
|
||||
Bool result = XTranslateCoordinates(display, window, root, srcx, srcy, &destx, &desty, &child);
|
||||
/*Bool result =*/ XTranslateCoordinates(display, window, root, srcx, srcy, &destx, &desty, &child);
|
||||
return Point(destx / dpiscale, desty / dpiscale);
|
||||
}
|
||||
|
||||
|
|
@ -652,6 +718,23 @@ void X11DisplayWindow::ExitLoop()
|
|||
void X11DisplayWindow::DispatchEvent(XEvent* event)
|
||||
{
|
||||
X11Connection* connection = GetX11Connection();
|
||||
|
||||
if (connection->XInput2Supported)
|
||||
{
|
||||
// XInput sends all raw input to the root window. We want it routed to the focused window
|
||||
if (event->xcookie.type == GenericEvent &&
|
||||
event->xcookie.extension == connection->XInputOpcode &&
|
||||
XGetEventData(connection->display, &event->xcookie))
|
||||
{
|
||||
for (auto& it : connection->windows)
|
||||
{
|
||||
X11DisplayWindow* window = it.second;
|
||||
window->OnXInputEvent(event);
|
||||
}
|
||||
XFreeEventData(connection->display, &event->xcookie);
|
||||
}
|
||||
}
|
||||
|
||||
auto it = connection->windows.find(event->xany.window);
|
||||
if (it != connection->windows.end())
|
||||
{
|
||||
|
|
@ -731,11 +814,13 @@ void X11DisplayWindow::OnFocusIn(XEvent* event)
|
|||
if (xic)
|
||||
XSetICFocus(xic);
|
||||
|
||||
RawInput.Focused = true;
|
||||
windowHost->OnWindowActivated();
|
||||
}
|
||||
|
||||
void X11DisplayWindow::OnFocusOut(XEvent* event)
|
||||
{
|
||||
RawInput.Focused = false;
|
||||
windowHost->OnWindowDeactivated();
|
||||
}
|
||||
|
||||
|
|
@ -949,6 +1034,8 @@ void X11DisplayWindow::OnKeyRelease(XEvent* event)
|
|||
|
||||
void X11DisplayWindow::OnButtonPress(XEvent* event)
|
||||
{
|
||||
// Note: this only gets called if XInput is not available
|
||||
|
||||
InputKey key = GetInputKey(event);
|
||||
keyState[key] = true;
|
||||
windowHost->OnWindowMouseDown(GetMousePos(event), key);
|
||||
|
|
@ -958,6 +1045,8 @@ void X11DisplayWindow::OnButtonPress(XEvent* event)
|
|||
|
||||
void X11DisplayWindow::OnButtonRelease(XEvent* event)
|
||||
{
|
||||
// Note: this only gets called if XInput is not available
|
||||
|
||||
InputKey key = GetInputKey(event);
|
||||
keyState[key] = false;
|
||||
windowHost->OnWindowMouseUp(GetMousePos(event), key);
|
||||
|
|
@ -965,6 +1054,8 @@ void X11DisplayWindow::OnButtonRelease(XEvent* event)
|
|||
|
||||
void X11DisplayWindow::OnMotionNotify(XEvent* event)
|
||||
{
|
||||
// Note: this only gets called if XInput is not available
|
||||
|
||||
double dpiScale = GetDpiScale();
|
||||
int x = event->xmotion.x;
|
||||
int y = event->xmotion.y;
|
||||
|
|
@ -974,18 +1065,127 @@ void X11DisplayWindow::OnMotionNotify(XEvent* event)
|
|||
}
|
||||
else
|
||||
{
|
||||
MouseX = ClientSizeX / 2;
|
||||
MouseY = ClientSizeY / 2;
|
||||
|
||||
if (MouseX != -1 && MouseY != -1)
|
||||
int dx = x - RawInput.LastX;
|
||||
int dy = y - RawInput.LastY;
|
||||
RawInput.LastX = x;
|
||||
RawInput.LastY = y;
|
||||
int centerX = ClientSizeX / 2;
|
||||
int centerY = ClientSizeY / 2;
|
||||
if (x != centerX || y != centerY)
|
||||
{
|
||||
windowHost->OnWindowRawMouseMove(x - MouseX, y - MouseY);
|
||||
// We still have to contain the mouse even if we are using XInput.
|
||||
// Maybe we can do that in a simpler way if XInput is available?
|
||||
XWarpPointer(display, window, window, 0, 0, ClientSizeX, ClientSizeY, centerX, centerY);
|
||||
|
||||
// Use the accelerated mouse cursor if there's no XInput 2.0 support
|
||||
if (!GetX11Connection()->XInput2Supported)
|
||||
{
|
||||
if (dx != 0 || dy != 0)
|
||||
windowHost->OnWindowRawMouseMove(dx, dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void X11DisplayWindow::OnXInputEvent(XEvent* event)
|
||||
{
|
||||
// This API is so horrible it makes Win32 look attractive!
|
||||
if (event->xcookie.evtype == XI_ButtonPress || event->xcookie.evtype == XI_ButtonRelease)
|
||||
{
|
||||
auto deviceEvent = (XIDeviceEvent*)event->xcookie.data;
|
||||
if (deviceEvent->event != window)
|
||||
return;
|
||||
|
||||
InputKey key = {};
|
||||
switch (deviceEvent->detail)
|
||||
{
|
||||
case 1: key = InputKey::LeftMouse; break;
|
||||
case 2: key = InputKey::MiddleMouse; break;
|
||||
case 3: key = InputKey::RightMouse; break;
|
||||
case 4: key = InputKey::MouseWheelUp; break;
|
||||
case 5: key = InputKey::MouseWheelDown; break;
|
||||
// case 6: key = InputKey::XButton1; break;
|
||||
// case 7: key = InputKey::XButton2; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
// Warp pointer to the center of the window
|
||||
XWarpPointer(display, window, window, 0, 0, ClientSizeX, ClientSizeY, ClientSizeX / 2, ClientSizeY / 2);
|
||||
}
|
||||
double dpiScale = GetDpiScale();
|
||||
int x = (int)std::round(deviceEvent->event_x);
|
||||
int y = (int)std::round(deviceEvent->event_y);
|
||||
Point mousePos(x / dpiScale, y / dpiScale);
|
||||
|
||||
if (!isCursorEnabled)
|
||||
{
|
||||
// Raw input gets blocked until we ungrab the pointer. Worst design EVER.
|
||||
XUngrabPointer(display, deviceEvent->time);
|
||||
}
|
||||
|
||||
if (event->xcookie.evtype == XI_ButtonPress)
|
||||
{
|
||||
keyState[key] = true;
|
||||
windowHost->OnWindowMouseDown(mousePos, key);
|
||||
// if (lastClickWithin400ms)
|
||||
// windowHost->OnWindowMouseDoubleclick(GetMousePos(event), InputKey::LeftMouse);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyState[key] = false;
|
||||
windowHost->OnWindowMouseUp(mousePos, key);
|
||||
}
|
||||
}
|
||||
else if (event->xcookie.evtype == XI_Motion)
|
||||
{
|
||||
auto deviceEvent = (XIDeviceEvent*)event->xcookie.data;
|
||||
if (deviceEvent->event != window)
|
||||
return;
|
||||
|
||||
if (isCursorEnabled)
|
||||
{
|
||||
double dpiScale = GetDpiScale();
|
||||
int x = (int)std::round(deviceEvent->event_x);
|
||||
int y = (int)std::round(deviceEvent->event_y);
|
||||
Point mousePos(x / dpiScale, y / dpiScale);
|
||||
windowHost->OnWindowMouseMove(Point(x / dpiScale, y / dpiScale));
|
||||
}
|
||||
else if (RawInput.Focused)
|
||||
{
|
||||
int x = (int)std::round(deviceEvent->event_x);
|
||||
int y = (int)std::round(deviceEvent->event_y);
|
||||
int centerX = ClientSizeX / 2;
|
||||
int centerY = ClientSizeY / 2;
|
||||
if (x != centerX || y != centerY)
|
||||
{
|
||||
// We still have to contain the mouse even if we are using XInput.
|
||||
// Maybe we can do that in a simpler way?
|
||||
XWarpPointer(display, window, window, 0, 0, ClientSizeX, ClientSizeY, centerX, centerY);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!isCursorEnabled && RawInput.Focused && event->xcookie.evtype == XI_RawMotion)
|
||||
{
|
||||
std::vector<double> values;
|
||||
values.reserve(2);
|
||||
|
||||
auto rawEvent = (XIRawEvent*)event->xcookie.data;
|
||||
double *rawValuator = rawEvent->raw_values;
|
||||
for (int i = 0; i < rawEvent->valuators.mask_len * 8; i++)
|
||||
{
|
||||
if (XIMaskIsSet(rawEvent->valuators.mask, i))
|
||||
{
|
||||
values.push_back(*rawValuator);
|
||||
rawValuator++;
|
||||
}
|
||||
}
|
||||
|
||||
if (values.size() >= 2)
|
||||
{
|
||||
// Values seems to be integers for my mouse. Is that always the case?
|
||||
int dx = (int)std::round(values[0]);
|
||||
int dy = (int)std::round(values[1]);
|
||||
if (dx != 0 || dy != 0)
|
||||
windowHost->OnWindowRawMouseMove(dx, dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void X11DisplayWindow::OnLeaveNotify(XEvent* event)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <X11/cursorfont.h>
|
||||
#include <X11/keysymdef.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#include <map>
|
||||
|
||||
class X11DisplayWindow : public DisplayWindow
|
||||
|
|
@ -85,6 +86,7 @@ private:
|
|||
void OnSelectionClear(XEvent* event);
|
||||
void OnSelectionNotify(XEvent* event);
|
||||
void OnSelectionRequest(XEvent* event);
|
||||
void OnXInputEvent(XEvent* event);
|
||||
|
||||
void CreateBackbuffer(int width, int height);
|
||||
void DestroyBackbuffer();
|
||||
|
|
@ -117,8 +119,13 @@ private:
|
|||
|
||||
int ClientSizeX = 0;
|
||||
int ClientSizeY = 0;
|
||||
int MouseX = -1;
|
||||
int MouseY = -1;
|
||||
|
||||
struct
|
||||
{
|
||||
int LastX = -1;
|
||||
int LastY = -1;
|
||||
bool Focused = false;
|
||||
} RawInput;
|
||||
|
||||
Pixmap cursor_bitmap = None;
|
||||
Cursor hidden_cursor = None;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue