Merge commit '87689ccb5f' into theme
This commit is contained in:
commit
27a934ee70
27 changed files with 925 additions and 519 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,14 +253,70 @@ 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)
|
||||
else()
|
||||
set(CXX_WARNING_FLAGS -Wall -Wpedantic)
|
||||
endif()
|
||||
|
||||
add_library(zwidget STATIC ${ZWIDGET_SOURCES} ${ZWIDGET_INCLUDES})
|
||||
target_compile_options(zwidget PRIVATE ${ZWIDGET_COMPILE_OPTIONS})
|
||||
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)
|
||||
set_property(TARGET zwidget PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
endif()
|
||||
|
||||
option(ZWIDGET_BUILD_EXAMPLE "Build the zwidget example application" ON)
|
||||
|
||||
if(ZWIDGET_BUILD_EXAMPLE)
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_package(SDL2 REQUIRED)
|
||||
endif()
|
||||
|
||||
add_executable(zwidget_example WIN32
|
||||
example/example.cpp
|
||||
example/picopng.cpp
|
||||
example/picopng.h
|
||||
)
|
||||
target_compile_options(zwidget_example PRIVATE ${CXX_WARNING_FLAGS})
|
||||
|
||||
add_custom_command(
|
||||
TARGET zwidget_example POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/example/banner.png"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/banner.png"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/example/OpenSans.ttf"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/OpenSans.ttf"
|
||||
)
|
||||
|
||||
target_include_directories(zwidget_example PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/example)
|
||||
target_link_libraries(zwidget_example PRIVATE zwidget)
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(zwidget_example PRIVATE UNICODE _UNICODE)
|
||||
target_link_libraries(zwidget_example PRIVATE gdi32 user32 shell32 comdlg32)
|
||||
elseif(APPLE)
|
||||
target_link_libraries(zwidget_example PRIVATE "-framework Cocoa -framework OpenGL")
|
||||
else()
|
||||
target_link_libraries(zwidget_example PRIVATE ${ZWIDGET_LIBS})
|
||||
endif()
|
||||
|
||||
set_target_properties(zwidget_example PROPERTIES CXX_STANDARD 20)
|
||||
|
||||
if(MSVC)
|
||||
set_property(TARGET zwidget_example PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -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