Merge commit '6356d87438'
This commit is contained in:
commit
b7d9ddb6a3
8 changed files with 252 additions and 56 deletions
|
|
@ -244,6 +244,12 @@ else()
|
|||
endif()
|
||||
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})
|
||||
|
|
@ -251,7 +257,51 @@ 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)
|
||||
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} SDL2::SDL2)
|
||||
endif()
|
||||
|
||||
set_target_properties(zwidget_example PROPERTIES CXX_STANDARD 17)
|
||||
|
||||
if(MSVC)
|
||||
set_property(TARGET zwidget_example PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -63,9 +63,17 @@ public:
|
|||
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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,14 +7,25 @@
|
|||
#include "../../core/widget.h"
|
||||
#include "../../widgets/listview/listview.h"
|
||||
|
||||
class DropdownList : public ListView
|
||||
{
|
||||
public:
|
||||
DropdownList(Widget* parent, Dropdown* owner);
|
||||
protected:
|
||||
void OnKeyDown(InputKey key) override;
|
||||
Dropdown* owner;
|
||||
};
|
||||
|
||||
class Dropdown : public Widget
|
||||
{
|
||||
public:
|
||||
Dropdown(Widget* parent);
|
||||
|
||||
void AddItem(const std::string& text);
|
||||
void RemoveItem(int index);
|
||||
void AddItem(const std::string& text, int index = -1);
|
||||
bool UpdateItem(const std::string& text, int index);
|
||||
bool RemoveItem(int index = -1);
|
||||
void ClearItems();
|
||||
const std::string& GetItem(int index);
|
||||
|
||||
void SetMaxDisplayItems(int items);
|
||||
void SetDropdownDirection(bool below);
|
||||
|
|
@ -22,9 +33,6 @@ public:
|
|||
int GetSelectedItem() const { return selectedItem; }
|
||||
void SetSelectedItem(int index);
|
||||
|
||||
std::string GetSelectedText() const;
|
||||
std::string GetText() const { return text; }
|
||||
|
||||
double GetPreferredHeight() const;
|
||||
double GetPreferredWidth() const;
|
||||
|
||||
|
|
@ -39,8 +47,9 @@ protected:
|
|||
void Notify(Widget* source, const WidgetEvent type) override;
|
||||
|
||||
private:
|
||||
void OpenDropdown();
|
||||
void CloseDropdown();
|
||||
void ItemsChanged();
|
||||
bool OpenDropdown();
|
||||
bool CloseDropdown();
|
||||
void OnDropdownActivated();
|
||||
|
||||
size_t GetDisplayItems();
|
||||
|
|
@ -51,8 +60,10 @@ private:
|
|||
|
||||
bool dropdownOpen = false;
|
||||
Widget* dropdown = nullptr;
|
||||
ListView* listView = nullptr;
|
||||
DropdownList* listView = nullptr;
|
||||
|
||||
int maxDisplayItems = 0;
|
||||
bool dropdownDirection = true;
|
||||
|
||||
friend DropdownList;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <functional>
|
||||
|
||||
class Scrollbar;
|
||||
class Dropdown;
|
||||
|
||||
class ListView : public Widget
|
||||
{
|
||||
|
|
@ -47,4 +48,6 @@ protected:
|
|||
std::vector<std::vector<std::string>> items;
|
||||
std::vector<double> columnwidths;
|
||||
int selectedItem = 0;
|
||||
|
||||
friend Dropdown;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,14 @@ Dropdown::Dropdown(Widget* parent) : Widget(parent)
|
|||
p->Subscribe(this);
|
||||
}
|
||||
|
||||
DropdownList::DropdownList(Widget* parent, Dropdown* owner) : ListView(parent), owner(owner)
|
||||
{}
|
||||
|
||||
void DropdownList::OnKeyDown(InputKey key)
|
||||
{
|
||||
owner->OnKeyDown(key);
|
||||
}
|
||||
|
||||
void Dropdown::Notify(Widget* source, const WidgetEvent type)
|
||||
{
|
||||
if (type != WidgetEvent::VisibilityChange) return;
|
||||
|
|
@ -28,20 +36,63 @@ void Dropdown::Notify(Widget* source, const WidgetEvent type)
|
|||
}
|
||||
}
|
||||
|
||||
void Dropdown::AddItem(const std::string& text)
|
||||
void Dropdown::ItemsChanged()
|
||||
{
|
||||
items.push_back(text);
|
||||
if (selectedItem == -1 && !items.empty())
|
||||
if (!CloseDropdown())
|
||||
{
|
||||
SetSelectedItem(0);
|
||||
Update();
|
||||
}
|
||||
Update();
|
||||
}
|
||||
|
||||
void Dropdown::RemoveItem(int index)
|
||||
void Dropdown::AddItem(const std::string& text, int index)
|
||||
{
|
||||
if (index < 0 || (size_t)index >= items.size())
|
||||
return;
|
||||
if (index < 0)
|
||||
{
|
||||
items.push_back(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
items.insert(items.begin() + index, text);
|
||||
}
|
||||
|
||||
if (selectedItem == -1 && !items.empty())
|
||||
SetSelectedItem(0);
|
||||
|
||||
ItemsChanged();
|
||||
}
|
||||
|
||||
bool Dropdown::UpdateItem(const std::string& text, int index)
|
||||
{
|
||||
if (!items.size() || index >= (int)items.size())
|
||||
return false;
|
||||
|
||||
if (index < 0)
|
||||
index = static_cast<int>(items.size()) - 1;
|
||||
|
||||
items[index] = text;
|
||||
|
||||
if (selectedItem == index)
|
||||
{
|
||||
this->text = text;
|
||||
}
|
||||
|
||||
ItemsChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string & Dropdown::GetItem(int index)
|
||||
{
|
||||
return items[index];
|
||||
}
|
||||
|
||||
bool Dropdown::RemoveItem(int index)
|
||||
{
|
||||
if (!items.size() || index >= (int)items.size())
|
||||
return false;
|
||||
|
||||
if (index < 0)
|
||||
index = static_cast<int>(items.size()) - 1;
|
||||
|
||||
items.erase(items.begin() + index);
|
||||
|
||||
|
|
@ -57,38 +108,34 @@ void Dropdown::RemoveItem(int index)
|
|||
{
|
||||
SetSelectedItem(selectedItem - 1);
|
||||
}
|
||||
Update();
|
||||
|
||||
ItemsChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Dropdown::ClearItems()
|
||||
{
|
||||
items.clear();
|
||||
SetSelectedItem(-1);
|
||||
Update();
|
||||
ItemsChanged();
|
||||
}
|
||||
|
||||
void Dropdown::SetSelectedItem(int index)
|
||||
{
|
||||
if (index >= (int)items.size())
|
||||
index = (int)items.size() - 1;
|
||||
if (index < 0) index = 0;
|
||||
if (index >= (int)items.size()) index = items.size() - 1;
|
||||
|
||||
if (selectedItem != index)
|
||||
{
|
||||
selectedItem = index;
|
||||
text = (selectedItem != -1) ? items[selectedItem] : "";
|
||||
if (selectedItem == index) return;
|
||||
|
||||
if (OnChanged)
|
||||
OnChanged(selectedItem);
|
||||
selectedItem = index;
|
||||
text = (selectedItem != -1) ? items[selectedItem] : "";
|
||||
|
||||
Update();
|
||||
}
|
||||
}
|
||||
if (OnChanged) OnChanged(selectedItem);
|
||||
|
||||
std::string Dropdown::GetSelectedText() const
|
||||
{
|
||||
if (selectedItem >= 0 && (size_t)selectedItem < items.size())
|
||||
return items[selectedItem];
|
||||
return {};
|
||||
if (dropdownOpen) listView->ScrollToItem(listView->selectedItem = selectedItem);
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
double Dropdown::GetPreferredHeight() const
|
||||
|
|
@ -144,7 +191,7 @@ bool Dropdown::OnMouseDown(const Point& pos, InputKey key)
|
|||
{
|
||||
if (dropdownOpen)
|
||||
{
|
||||
// this set focus call will close the popup
|
||||
CloseDropdown();
|
||||
SetFocus();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -160,28 +207,48 @@ bool Dropdown::OnMouseDown(const Point& pos, InputKey key)
|
|||
|
||||
void Dropdown::OnKeyDown(InputKey key)
|
||||
{
|
||||
if (key == InputKey::Down)
|
||||
{
|
||||
if (selectedItem + 1 < (int)items.size())
|
||||
SetSelectedItem(selectedItem + 1);
|
||||
}
|
||||
else if (key == InputKey::Up)
|
||||
{
|
||||
if (selectedItem > 0)
|
||||
SetSelectedItem(selectedItem - 1);
|
||||
}
|
||||
else if (key == InputKey::Enter || key == InputKey::Space)
|
||||
switch (key)
|
||||
{
|
||||
case InputKey::Enter:
|
||||
case InputKey::Space:
|
||||
if (dropdownOpen)
|
||||
CloseDropdown();
|
||||
else
|
||||
OpenDropdown();
|
||||
break;
|
||||
|
||||
case InputKey::Up:
|
||||
SetSelectedItem(selectedItem - 1);
|
||||
break;
|
||||
|
||||
case InputKey::Down:
|
||||
SetSelectedItem(selectedItem + 1);
|
||||
break;
|
||||
|
||||
case InputKey::Home:
|
||||
SetSelectedItem(0);
|
||||
break;
|
||||
|
||||
case InputKey::End:
|
||||
SetSelectedItem((int)items.size());
|
||||
break;
|
||||
|
||||
case InputKey::PageUp:
|
||||
SetSelectedItem(selectedItem - (maxDisplayItems? maxDisplayItems: (int)items.size()));
|
||||
break;
|
||||
|
||||
case InputKey::PageDown:
|
||||
SetSelectedItem(selectedItem + (maxDisplayItems? maxDisplayItems: (int)items.size()));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Dropdown::SetMaxDisplayItems(int items)
|
||||
{
|
||||
maxDisplayItems = items;
|
||||
maxDisplayItems = std::max<int>(0, items);
|
||||
}
|
||||
|
||||
size_t Dropdown::GetDisplayItems()
|
||||
|
|
@ -200,7 +267,7 @@ void Dropdown::OnGeometryChanged()
|
|||
{
|
||||
if (dropdownOpen)
|
||||
{
|
||||
Point pos = MapToGlobal(Point(0.0, 0.0));
|
||||
Point pos = MapTo(Window(), Point(0,0));
|
||||
|
||||
double width = GetWidth() + GetNoncontentLeft() + GetNoncontentRight();
|
||||
double innerH = GetDisplayItems() * 25.0 + 10.0;
|
||||
|
|
@ -229,14 +296,14 @@ void Dropdown::OnLostFocus()
|
|||
CloseDropdown();
|
||||
}
|
||||
|
||||
void Dropdown::OpenDropdown()
|
||||
bool Dropdown::OpenDropdown()
|
||||
{
|
||||
if (dropdownOpen || items.empty()) return;
|
||||
if (dropdownOpen || items.empty()) return false;
|
||||
|
||||
dropdownOpen = true;
|
||||
|
||||
dropdown = new Widget(Window());
|
||||
listView = new ListView(dropdown);
|
||||
listView = new DropdownList(dropdown, this);
|
||||
for (const auto& item : items)
|
||||
{
|
||||
listView->AddItem(item);
|
||||
|
|
@ -258,11 +325,13 @@ void Dropdown::OpenDropdown()
|
|||
dropdown->Show();
|
||||
|
||||
listView->ScrollToItem(selectedItem);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Dropdown::CloseDropdown()
|
||||
bool Dropdown::CloseDropdown()
|
||||
{
|
||||
if (!dropdownOpen || !dropdown) return;
|
||||
if (!dropdownOpen || !dropdown) return false;
|
||||
|
||||
dropdown->Close();
|
||||
dropdown = nullptr;
|
||||
|
|
@ -270,6 +339,8 @@ void Dropdown::CloseDropdown()
|
|||
dropdownOpen = false;
|
||||
|
||||
Update();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Dropdown::OnDropdownActivated()
|
||||
|
|
|
|||
|
|
@ -607,11 +607,12 @@ Size WaylandDisplayBackend::GetScreenSize()
|
|||
|
||||
void* WaylandDisplayBackend::StartTimer(int timeoutMilliseconds, std::function<void()> onTimer)
|
||||
{
|
||||
return nullptr;
|
||||
throw std::logic_error("unimplemented: WaylandDisplayBackend::StartTimer");
|
||||
}
|
||||
|
||||
void WaylandDisplayBackend::StopTimer(void* timerID)
|
||||
{
|
||||
throw std::logic_error("unimplemented: WaylandDisplayBackend::StopTimer");
|
||||
}
|
||||
|
||||
#ifdef USE_DBUS
|
||||
|
|
|
|||
|
|
@ -28,6 +28,57 @@
|
|||
#define RIDEV_INPUTSINK (0x100)
|
||||
#endif
|
||||
|
||||
// Code for delay loading DPI related functions, needed for continued Windows 7 compatibility.
|
||||
typedef BOOL (WINAPI *PFN_AdjustWindowRectExForDpi)(
|
||||
LPRECT lpRect,
|
||||
DWORD dwStyle,
|
||||
BOOL bMenu,
|
||||
DWORD dwExStyle,
|
||||
UINT dpi
|
||||
);
|
||||
|
||||
typedef UINT (WINAPI *PFN_GetDpiForWindow)(HWND hwnd);
|
||||
|
||||
static PFN_AdjustWindowRectExForDpi pAdjustWindowRectExForDpi = nullptr;
|
||||
static PFN_GetDpiForWindow pGetDpiForWindow = nullptr;
|
||||
|
||||
static void DPIDelayLoad()
|
||||
{
|
||||
HMODULE hUser32 = GetModuleHandleW(L"user32.dll");
|
||||
if (hUser32) {
|
||||
pAdjustWindowRectExForDpi = (PFN_AdjustWindowRectExForDpi)
|
||||
GetProcAddress(hUser32, "AdjustWindowRectExForDpi");
|
||||
pGetDpiForWindow = (PFN_GetDpiForWindow)
|
||||
GetProcAddress(hUser32, "GetDpiForWindow");
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL DelayLoadAdjustWindowRectExForDpi(
|
||||
LPRECT lpRect,
|
||||
DWORD dwStyle,
|
||||
BOOL bMenu,
|
||||
DWORD dwExStyle,
|
||||
HWND hwnd
|
||||
) {
|
||||
DPIDelayLoad();
|
||||
if (pAdjustWindowRectExForDpi) {
|
||||
return pAdjustWindowRectExForDpi(lpRect, dwStyle, bMenu, dwExStyle,
|
||||
pGetDpiForWindow(hwnd));
|
||||
} else {
|
||||
return AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
|
||||
}
|
||||
}
|
||||
|
||||
static double DelayLoadGetDpiScale(HWND hwnd)
|
||||
{
|
||||
DPIDelayLoad();
|
||||
if (pGetDpiForWindow) {
|
||||
return pGetDpiForWindow(hwnd) / 96.0;
|
||||
} else {
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
Win32DisplayWindow::Win32DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, Win32DisplayWindow* owner, RenderAPI renderAPI) : WindowHost(windowHost), PopupWindow(popupWindow)
|
||||
{
|
||||
Windows.push_front(this);
|
||||
|
|
@ -113,7 +164,7 @@ void Win32DisplayWindow::SetClientFrame(const Rect& box)
|
|||
|
||||
DWORD style = (DWORD)GetWindowLongPtr(WindowHandle.hwnd, GWL_STYLE);
|
||||
DWORD exstyle = (DWORD)GetWindowLongPtr(WindowHandle.hwnd, GWL_EXSTYLE);
|
||||
AdjustWindowRectExForDpi(&rect, style, FALSE, exstyle, GetDpiForWindow(WindowHandle.hwnd));
|
||||
DelayLoadAdjustWindowRectExForDpi(&rect, style, FALSE, exstyle, WindowHandle.hwnd);
|
||||
|
||||
SetWindowPos(WindowHandle.hwnd, nullptr, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOZORDER);
|
||||
}
|
||||
|
|
@ -291,7 +342,7 @@ int Win32DisplayWindow::GetPixelHeight() const
|
|||
|
||||
double Win32DisplayWindow::GetDpiScale() const
|
||||
{
|
||||
return GetDpiForWindow(WindowHandle.hwnd) / 96.0;
|
||||
return DelayLoadGetDpiScale(WindowHandle.hwnd);
|
||||
}
|
||||
|
||||
std::string Win32DisplayWindow::GetClipboardText()
|
||||
|
|
|
|||
|
|
@ -1084,11 +1084,12 @@ Size X11DisplayWindow::GetScreenSize()
|
|||
|
||||
void* X11DisplayWindow::StartTimer(int timeoutMilliseconds, std::function<void()> onTimer)
|
||||
{
|
||||
return nullptr;
|
||||
throw std::logic_error("unimplemented: X11DisplayWindow::StartTimer");
|
||||
}
|
||||
|
||||
void X11DisplayWindow::StopTimer(void* timerID)
|
||||
{
|
||||
throw std::logic_error("unimplemented: X11DisplayWindow::StopTimer");
|
||||
}
|
||||
|
||||
// This is to avoid needing all the Vulkan headers and the volk binding library just for this:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue