Skip to content

Commit

Permalink
Add DisplayBackend for customizing the active backend
Browse files Browse the repository at this point in the history
Add X11 backend
Add line drawing to bitmap canvas
  • Loading branch information
dpjudas committed Jun 4, 2024
1 parent 0887201 commit b927a53
Show file tree
Hide file tree
Showing 7 changed files with 1,734 additions and 40 deletions.
12 changes: 9 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ set(ZWIDGET_SDL2_SOURCES
src/window/sdl2/sdl2displaywindow.h
)

set(ZWIDGET_X11_SOURCES
src/window/x11/x11displaywindow.cpp
src/window/x11/x11displaywindow.h
)

source_group("src" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/.+")
source_group("src\\core" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/core/.+")
source_group("src\\core\\picopng" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/core/picopng/.+")
Expand Down Expand Up @@ -123,6 +128,7 @@ source_group("include\\widgets\\tabwidget" REGULAR_EXPRESSION "${CMAKE_CURRENT_S
source_group("include\\window" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/.+")
source_group("include\\window\\win32" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/win32/.+")
source_group("include\\window\\sdl2" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/sdl2/.+")
source_group("include\\window\\x11" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/window/x11/.+")
source_group("include\\systemdialogs" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zwidget/systemdialogs/.+")

include_directories(include include/zwidget src)
Expand All @@ -136,9 +142,9 @@ elseif(APPLE)
add_definitions(-DUNIX -D_UNIX)
add_link_options(-pthread)
else()
set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_SDL2_SOURCES})
set(ZWIDGET_LIBS ${CMAKE_DL_LIBS} -ldl)
add_definitions(-DUNIX -D_UNIX)
set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_SDL2_SOURCES} ${ZWIDGET_X11_SOURCES})
set(ZWIDGET_LIBS ${CMAKE_DL_LIBS} -ldl -lX11)
add_definitions(-DUNIX -D_UNIX -DUSE_SDL2 -DUSE_X11)
add_link_options(-pthread)
endif()

Expand Down
24 changes: 24 additions & 0 deletions include/zwidget/window/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,27 @@ class DisplayWindow

virtual void* GetNativeHandle() = 0;
};

class DisplayBackend
{
public:
static DisplayBackend* Get();
static void Set(std::unique_ptr<DisplayBackend> instance);

static std::unique_ptr<DisplayBackend> TryCreateWin32();
static std::unique_ptr<DisplayBackend> TryCreateSDL2();
static std::unique_ptr<DisplayBackend> TryCreateX11();
static std::unique_ptr<DisplayBackend> TryCreateWayland();

virtual ~DisplayBackend() = default;

virtual std::unique_ptr<DisplayWindow> Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner) = 0;
virtual void ProcessEvents() = 0;
virtual void RunLoop() = 0;
virtual void ExitLoop() = 0;

virtual void* StartTimer(int timeoutMilliseconds, std::function<void()> onTimer) = 0;
virtual void StopTimer(void* timerID) = 0;

virtual Size GetScreenSize() = 0;
};
119 changes: 118 additions & 1 deletion src/core/canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ class BitmapCanvas : public Canvas
void drawImage(const std::shared_ptr<Image>& image, const Point& pos) override;

void drawLineUnclipped(const Point& p0, const Point& p1, const Colorf& color);
void drawLineAntialiased(float x0, float y0, float x1, float y1, Colorf color);
void plot(float x, float y, float alpha, const Colorf& color);

void fillTile(float x, float y, float width, float height, Colorf color);
void drawTile(CanvasTexture* texture, float x, float y, float width, float height, float u, float v, float uvwidth, float uvheight, Colorf color);
Expand Down Expand Up @@ -503,7 +505,122 @@ void BitmapCanvas::drawLineUnclipped(const Point& p0, const Point& p1, const Col
}
else
{
// To do: draw line using bresenham
drawLineAntialiased((float)(p0.x * uiscale), (float)(p0.y * uiscale), (float)(p1.x * uiscale), (float)(p1.y * uiscale), color);
}
}

static float fpart(float x)
{
return x - std::floor(x);
}

static float rfpart(float x)
{
return 1 - fpart(x);
}

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 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);
uint32_t cblue = (int32_t)clamp(color.b * 256.0f, 0.0f, 256.0f);
uint32_t calpha = (int32_t)clamp(color.a * alpha * 256.0f, 0.0f, 256.0f);
uint32_t invalpha = 256 - calpha;

uint32_t dpixel = *dest;
uint32_t dalpha = dpixel >> 24;
uint32_t dred = (dpixel >> 16) & 0xff;
uint32_t dgreen = (dpixel >> 8) & 0xff;
uint32_t dblue = dpixel & 0xff;

// dest.rgba = color.rgba + dest.rgba * (1-color.a)
uint32_t a = (calpha * calpha + dalpha * invalpha + 127) >> 8;
uint32_t r = (cred * calpha + dred * invalpha + 127) >> 8;
uint32_t g = (cgreen * calpha + dgreen * invalpha + 127) >> 8;
uint32_t b = (cblue * calpha + dblue * invalpha + 127) >> 8;
*dest = (a << 24) | (r << 16) | (g << 8) | b;
}

void BitmapCanvas::drawLineAntialiased(float x0, float y0, float x1, float y1, Colorf color)
{
bool steep = std::abs(y1 - y0) > std::abs(x1 - x0);

if (steep)
{
std::swap(x0, y0);
std::swap(x1, y1);
}

if (x0 > x1)
{
std::swap(x0, x1);
std::swap(y0, y1);
}

float dx = x1 - x0;
float dy = y1 - y0;
float gradient = (dx == 0.0f) ? 1.0f : dy / dx;

// handle first endpoint
float xend = std::round(x0);
float yend = y0 + gradient * (xend - x0);
float xgap = rfpart(x0 + 0.5f);
float xpxl1 = xend; // this will be used in the main loop
float ypxl1 = std::floor(yend);
if (steep)
{
plot(ypxl1, xpxl1, rfpart(yend) * xgap, color);
plot(ypxl1 + 1, xpxl1, fpart(yend) * xgap, color);
}
else
{
plot(xpxl1, ypxl1, rfpart(yend) * xgap, color);
plot(xpxl1, ypxl1 + 1, fpart(yend) * xgap, color);
}
float intery = yend + gradient; // first y-intersection for the main loop

// handle second endpoint
xend = std::floor(x1 + 0.5f);
yend = y1 + gradient * (xend - x1);
xgap = fpart(x1 + 0.5f);
float xpxl2 = xend; // this will be used in the main loop
float ypxl2 = std::floor(yend);
if (steep)
{
plot(ypxl2, xpxl2, rfpart(yend) * xgap, color);
plot(ypxl2 + 1.0f, xpxl2, fpart(yend) * xgap, color);
}
else
{
plot(xpxl2, ypxl2, rfpart(yend) * xgap, color);
plot(xpxl2, ypxl2 + 1.0f, fpart(yend) * xgap, color);
}

// main loop
if (steep)
{
for (float x = xpxl1 + 1.0f; x <= xpxl2 - 1.0f; x++)
{
plot(std::floor(intery), x, rfpart(intery), color);
plot(std::floor(intery) + 1.0f, x, fpart(intery), color);
intery = intery + gradient;
}
}
else
{
for (float x = xpxl1 + 1.0f; x <= xpxl2 - 1.0f; x++)
{
plot(x, std::floor(intery), rfpart(intery), color);
plot(x, std::floor(intery) + 1, fpart(intery), color);
intery = intery + gradient;
}
}
}

Expand Down
152 changes: 151 additions & 1 deletion src/systemdialogs/open_file_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,11 +276,161 @@ std::unique_ptr<OpenFileDialog> OpenFileDialog::Create(Widget* owner)
return std::make_unique<OpenFileDialogImpl>(owner);
}

#elif defined(__APPLE__)

class OpenFileDialogImpl : public OpenFileDialog
{
public:
OpenFileDialogImpl(Widget* owner)
{
}

std::string Filename() const override
{
return {};
}

std::vector<std::string> Filenames() const override
{
return {};
}

void SetMultiSelect(bool multiselect) override
{
}

void SetFilename(const std::string &filename) override
{
}

void SetDefaultExtension(const std::string& extension) override
{
}

void AddFilter(const std::string &filter_description, const std::string &filter_extension) override
{
}

void ClearFilters() override
{
}

void SetFilterIndex(int filter_index) override
{
}

void SetInitialDirectory(const std::string &path) override
{
}

void SetTitle(const std::string &title) override
{
}

bool Show() override
{
return false;
}
};

std::unique_ptr<OpenFileDialog> OpenFileDialog::Create(Widget* owner)
{
return std::make_unique<OpenFileDialogImpl>(owner);
}

#else

class OpenFileDialogImpl : public OpenFileDialog
{
public:
OpenFileDialogImpl(Widget* owner) : owner(owner)
{
}

std::string Filename() const override
{
return outputFilenames.empty() ? std::string() : outputFilenames.front();
}

std::vector<std::string> Filenames() const override
{
return outputFilenames;
}

void SetMultiSelect(bool multiselect) override
{
this->multiSelect = multiSelect;
}

void SetFilename(const std::string &filename) override
{
inputFilename = filename;
}

void SetDefaultExtension(const std::string& extension) override
{
defaultExt = extension;
}

void AddFilter(const std::string &filter_description, const std::string &filter_extension) override
{
filters.push_back({ filter_description, filter_extension });
}

void ClearFilters() override
{
filters.clear();
}

void SetFilterIndex(int filter_index) override
{
this->filter_index = filter_index;
}

void SetInitialDirectory(const std::string &path) override
{
initialDirectory = path;
}

void SetTitle(const std::string &title) override
{
this->title = title;
}

bool Show() override
{
// To do: do a bunch of d-bus stuff. See the following sources:
// https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.FileChooser.html
// https://github.com/makercrew/dbus-sample
//
// To do: create a way to detect if the window is x11 vs wayland
unsigned long x11windowhandle = 0;
if (owner)
x11windowhandle = reinterpret_cast<unsigned long>(owner->GetNativeHandle());

return false;
}

Widget* owner = nullptr;
std::string title;
std::string initialDirectory;
std::string inputFilename;
std::string defaultExt;
std::vector<std::string> outputFilenames;
bool multiSelect = false;

struct Filter
{
std::string description;
std::string extension;
};
std::vector<Filter> filters;
int filter_index = 0;
};

std::unique_ptr<OpenFileDialog> OpenFileDialog::Create(Widget* owner)
{
return {};
return std::make_unique<OpenFileDialogImpl>(owner);
}

#endif
Loading

0 comments on commit b927a53

Please sign in to comment.