Skip to content

Commit

Permalink
Merge branch 'dnd'
Browse files Browse the repository at this point in the history
  • Loading branch information
dacap committed May 29, 2024
2 parents 695bb59 + 53de63b commit cb15528
Show file tree
Hide file tree
Showing 29 changed files with 1,606 additions and 106 deletions.
22 changes: 17 additions & 5 deletions base/win/comptr.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ namespace base {
std::swap(m_ptr, tmp.m_ptr);
}

explicit ComPtr(T* p) : m_ptr(p) {
if (m_ptr)
m_ptr->AddRef();
}

~ComPtr() {
reset();
}
Expand All @@ -41,11 +46,18 @@ namespace base {

// Add new reference using operator=()
ComPtr<T>& operator=(const ComPtr<T>& p) {
if (m_ptr)
m_ptr->Release();
m_ptr = p.m_ptr;
if (m_ptr)
m_ptr->AddRef();
if (this != &p) {
if (m_ptr)
m_ptr->Release();
m_ptr = p.m_ptr;
if (m_ptr)
m_ptr->AddRef();
}
return *this;
}

ComPtr<T>& operator=(ComPtr<T>&& p) noexcept {
std::swap(m_ptr, p.m_ptr);
return *this;
}

Expand Down
2 changes: 1 addition & 1 deletion clip
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ if(LAF_BACKEND STREQUAL "skia")
laf_add_example(base64 CONSOLE)
laf_add_example(complextextlayout GUI)
laf_add_example(custom_window GUI)
laf_add_example(drag_and_drop GUI)
laf_add_example(floating_window GUI)
laf_add_example(hello_laf GUI)
laf_add_example(listfonts CONSOLE)
Expand Down
215 changes: 215 additions & 0 deletions examples/drag_and_drop.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
// LAF Library
// Copyright (c) 2024 Igara Studio S.A.
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#include "base/paths.h"
#include "os/os.h"

#include <cstdio>
#include <string>

struct WindowData {
bool dragEnter;
bool dragLeave;
int drag;
base::paths paths;
os::SurfaceRef image;
std::string url;
gfx::Point dragPosition;
gfx::Rect dropZone;
};

static WindowData windowData;

static void redraw_window(os::Window* window);

class DragTarget : public os::DragTarget {
public:
void dragEnter(os::DragEvent& ev) override {
if (!windowData.dropZone.contains(ev.position()) ||
!ev.sourceSupports(os::DropOperation::Copy)) {
ev.dropResult(os::DropOperation::None);
}
else if (ev.sourceSupports(os::DropOperation::Copy)) {
ev.dropResult(os::DropOperation::Copy);
}

windowData.dragEnter = true;
windowData.dragLeave = false;
windowData.drag = 0;
windowData.dragPosition = ev.position();
redraw_window(ev.target());
}

void dragLeave(os::DragEvent& ev) override {
windowData.dragEnter = false;
windowData.dragLeave = true;
windowData.dragPosition = ev.position();
redraw_window(ev.target());
}

void drag(os::DragEvent& ev) override {
++windowData.drag;
windowData.dragPosition = ev.position();
redraw_window(ev.target());
}

void drop(os::DragEvent& ev) override {
windowData.dragEnter = false;
windowData.dragLeave = false;
windowData.dragPosition = { 0, 0 };
ev.acceptDrop(windowData.dropZone.contains(ev.position()));

if (ev.acceptDrop()) {
if (ev.dataProvider()->contains(os::DragDataItemType::Paths))
windowData.paths = ev.dataProvider()->getPaths();
#if CLIP_ENABLE_IMAGE
if (ev.dataProvider()->contains(os::DragDataItemType::Image))
windowData.image = ev.dataProvider()->getImage();
#endif
if (ev.dataProvider()->contains(os::DragDataItemType::Url))
windowData.url = ev.dataProvider()->getUrl();
}

redraw_window(ev.target());
}
};

static void redraw_window(os::Window* window)
{
os::Surface* s = window->surface();
const gfx::Rect rc = s->bounds();

os::Paint paint;
paint.color(gfx::rgba(32, 32, 32, 255));
s->drawRect(rc, paint);

paint.color(gfx::rgba(255, 255, 200, 255));

char buf[2049];
int y = 12;
std::snprintf(buf, sizeof(buf), "Drag Position = [%d, %d]", windowData.dragPosition.x, windowData.dragPosition.y);
os::draw_text(s, nullptr, buf, gfx::Point(0, y), &paint);
y += 12;
std::snprintf(buf, sizeof(buf), "Drag Enter = %s", windowData.dragEnter ? "true" : "false");
os::draw_text(s, nullptr, buf, gfx::Point(0, y), &paint);
y += 12;
std::snprintf(buf, sizeof(buf), "Drag = %d", windowData.drag);
os::draw_text(s, nullptr, buf, gfx::Point(0, y), &paint);
y += 12;
std::snprintf(buf, sizeof(buf), "Drag Leave = %s", windowData.dragLeave ? "true" : "false");
os::draw_text(s, nullptr, buf, gfx::Point(0, y), &paint);

if (!windowData.paths.empty()) {
y += 12;
std::snprintf(buf, sizeof(buf), "Paths = %lu", windowData.paths.size());
os::draw_text(s, nullptr, buf, gfx::Point(0, y), &paint);
for (const auto& path : windowData.paths) {
y += 12;
std::snprintf(buf, sizeof(buf), "%s", path.c_str());
os::draw_text(s, nullptr, buf, gfx::Point(12, y), &paint);
}
}

if (!windowData.url.empty()) {
y += 12;
std::snprintf(buf, sizeof(buf), "URL:");
os::draw_text(s, nullptr, buf, gfx::Point(0, y), &paint);
y += 12;
std::snprintf(buf, sizeof(buf), "%s", windowData.url.c_str());
os::draw_text(s, nullptr, buf, gfx::Point(12, y), &paint);
}

if (windowData.image) {
y += 12;
s->drawRgbaSurface(windowData.image.get(), 0, y);
}

paint.style(os::Paint::Style::Stroke);
s->drawRect(rc, paint);

auto zoneColor = paint.color();
auto textColor = zoneColor;

windowData.dropZone.x = rc.w - windowData.dropZone.w - 12;
if (windowData.dropZone.contains(windowData.dragPosition)) {
paint.style(os::Paint::Style::Fill);
paint.color(zoneColor);
s->drawRect(windowData.dropZone, paint);
textColor = gfx::rgba(0, 0, 0);
}

paint.color(zoneColor);
paint.style(os::Paint::Style::Stroke);
s->drawRect(windowData.dropZone, paint);

paint.color(textColor);
paint.style(os::Paint::Style::Fill);
os::draw_text(s, nullptr, "Drop here!", windowData.dropZone.center(), &paint, os::TextAlign::Center);

if (window->isVisible())
window->invalidateRegion(gfx::Region(rc));
else
window->setVisible(true);
}

static os::WindowRef create_window(os::DragTarget& dragTarget)
{
auto screen = os::instance()->mainScreen();
os::WindowSpec spec;
spec.titled(true);
spec.position(os::WindowSpec::Position::Frame);
spec.frame(screen->workarea()/2);
spec.screen(screen);
spec.scale(2);

os::WindowRef newWindow = os::instance()->makeWindow(spec);
newWindow->setCursor(os::NativeCursor::Arrow);
newWindow->setTitle("Drag & Drop example");
newWindow->setDragTarget(&dragTarget);

windowData.dropZone = gfx::Rect(spec.frame().w-64-12, 12, 64, 64);
redraw_window(newWindow.get());
return newWindow;
}

int app_main(int argc, char* argv[])
{
auto system = os::make_system();
system->setAppMode(os::AppMode::GUI);
system->handleWindowResize = redraw_window;

DragTarget dragTarget;
os::WindowRef window = create_window(dragTarget);

bool running = true;

system->finishLaunching();
system->activateApp();

os::EventQueue* queue = system->eventQueue();
os::Event ev;
while (running) {
queue->getEvent(ev);

switch (ev.type()) {

case os::Event::CloseApp:
case os::Event::CloseWindow:
running = false;
break;

case os::Event::ResizeWindow:
redraw_window(ev.window().get());
break;

default:
// Do nothing
break;
}
}

return 0;
}
6 changes: 5 additions & 1 deletion os/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# LAF OS
# Copyright (C) 2018-2023 Igara Studio S.A.
# Copyright (C) 2018-2024 Igara Studio S.A.
# Copyright (C) 2012-2018 David Capello

######################################################################
Expand All @@ -8,11 +8,14 @@
set(LAF_OS_SOURCES
common/event_queue.cpp
common/main.cpp
common/system.cpp
dnd.cpp
system.cpp
window.cpp)
if(WIN32)
list(APPEND LAF_OS_SOURCES
win/color_space.cpp
win/dnd.cpp
win/event_queue.cpp
win/keys.cpp
win/native_dialogs.cpp
Expand All @@ -28,6 +31,7 @@ elseif(APPLE)
list(APPEND LAF_OS_SOURCES
osx/app.mm
osx/app_delegate.mm
osx/dnd.mm
osx/color_space.mm
osx/event_queue.mm
osx/keys.mm
Expand Down
Loading

0 comments on commit cb15528

Please sign in to comment.