-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7c52147
commit 0dafb45
Showing
9 changed files
with
582 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
// 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 "gfx/hsv.h" | ||
#include "gfx/rect.h" | ||
#include "gfx/rgb.h" | ||
#include "os/dnd.h" | ||
#include "os/draw_text.h" | ||
#include "os/os.h" | ||
|
||
#include <algorithm> | ||
#include <cstdarg> | ||
#include <cstdio> | ||
#include <map> | ||
#include <memory> | ||
#include <vector> | ||
|
||
using Boxes = std::vector<gfx::Rect>; | ||
|
||
struct WindowData { | ||
Boxes boxes; | ||
bool dragEnter; | ||
bool dragLeave; | ||
int drag; | ||
bool acceptDrop = true; | ||
base::paths paths; | ||
}; | ||
|
||
static std::map<const os::Window*, WindowData> windowData; | ||
|
||
static void redraw_window(os::Window* window); | ||
|
||
class DragTarget : public os::DragTarget { | ||
public: | ||
DragTarget(const os::WindowRef& window) : m_window(window) { | ||
|
||
} | ||
void dragEnter(os::DragEvent& ev) override { | ||
auto& data = windowData[ev.target()]; | ||
|
||
if (!data.acceptDrop || !ev.sourceSupports(os::DropOperation::Copy)) | ||
ev.dropResult(os::DropOperation::None); | ||
else if (ev.sourceSupports(os::DropOperation::Copy)) | ||
ev.dropResult(os::DropOperation::Copy); | ||
|
||
data.dragEnter = true; | ||
data.dragLeave = false; | ||
data.drag = 0; | ||
redraw_window(ev.target()); | ||
ev.target()->invalidate(); | ||
} | ||
void dragLeave(os::DragEvent& ev) override { | ||
auto& data = windowData[ev.target()]; | ||
data.dragEnter = false; | ||
data.dragLeave = true; | ||
redraw_window(ev.target()); | ||
ev.target()->invalidate(); | ||
} | ||
void drag(os::DragEvent& ev) override { | ||
++windowData[ev.target()].drag; | ||
redraw_window(ev.target()); | ||
ev.target()->invalidate(); | ||
} | ||
void drop(os::DragEvent& ev) override { | ||
auto& data = windowData[ev.target()]; | ||
data.dragEnter = false; | ||
data.dragLeave = false; | ||
if (data.acceptDrop) | ||
data.paths = ev.data()->getItems<os::DragDataItemType::Paths>()[0]; | ||
ev.acceptDrop(data.acceptDrop); | ||
redraw_window(ev.target()); | ||
ev.target()->invalidate(); | ||
} | ||
|
||
private: | ||
os::WindowRef m_window; | ||
}; | ||
|
||
class DragSource : public os::DragSource { | ||
public: | ||
|
||
}; | ||
|
||
static os::WindowRef windowA; | ||
static os::WindowRef windowB; | ||
|
||
const char* lines[] = { | ||
"T: Enable/disable acting as drag and drop target", | ||
"S: Enable/disable acting as drag and drop source", | ||
"A: Accept drop switch", | ||
}; | ||
|
||
static void redraw_window(os::Window* window) | ||
{ | ||
os::Surface* s = window->surface(); | ||
os::Paint paint; | ||
paint.color(gfx::rgba(0, 0, 0)); | ||
s->drawRect(window->bounds(), paint); | ||
|
||
paint.color(gfx::rgba(255, 255, 255)); | ||
|
||
char buf[256]; | ||
int y = 12; | ||
|
||
for (auto line : lines) { | ||
y += 12; | ||
os::draw_text(s, nullptr, line, gfx::Point(0, y), &paint); | ||
} | ||
|
||
const WindowData& data = windowData[window]; | ||
y += 12; | ||
std::snprintf(buf, sizeof(buf), "Drag Enter = %s", data.dragEnter ? "true" : "false"); | ||
os::draw_text(s, nullptr, buf, gfx::Point(0, y), &paint); | ||
y += 12; | ||
std::snprintf(buf, sizeof(buf), "Drag = %d", data.drag); | ||
os::draw_text(s, nullptr, buf, gfx::Point(0, y), &paint); | ||
y += 12; | ||
std::snprintf(buf, sizeof(buf), "Drag Leave = %s", data.dragLeave ? "true" : "false"); | ||
os::draw_text(s, nullptr, buf, gfx::Point(0, y), &paint); | ||
y += 12; | ||
std::snprintf(buf, sizeof(buf), "Accept drop = %s", data.acceptDrop ? "true" : "false"); | ||
os::draw_text(s, nullptr, buf, gfx::Point(0, y), &paint); | ||
|
||
if (!data.paths.empty()) { | ||
y += 12; | ||
std::snprintf(buf, sizeof(buf), "Paths = %lu", data.paths.size()); | ||
os::draw_text(s, nullptr, buf, gfx::Point(0, y), &paint); | ||
for (const auto& path : data.paths) { | ||
y += 12; | ||
std::snprintf(buf, sizeof(buf), "%s", path.c_str()); | ||
os::draw_text(s, nullptr, buf, gfx::Point(12, y), &paint); | ||
} | ||
} | ||
|
||
paint.style(os::Paint::Style::Stroke); | ||
s->drawRect(window->bounds(), paint); | ||
|
||
paint.color(gfx::rgba(100, 255, 100)); | ||
for (const auto& box : data.boxes) { | ||
paint.style(os::Paint::Style::Stroke); | ||
s->drawRect(box, paint); | ||
paint.style(os::Paint::Style::Fill); | ||
os::draw_text(s, nullptr, "Drag me!", box.center(), &paint, os::TextAlign::Center); | ||
} | ||
} | ||
|
||
static void create_box(const os::Window* window, const gfx::Rect& box) | ||
{ | ||
windowData[window].boxes.push_back(box); | ||
} | ||
|
||
static os::WindowRef create_window(const std::string& title, | ||
const os::WindowSpec& spec, | ||
const std::vector<gfx::Rect>& initialBoxes) | ||
{ | ||
os::WindowRef newWindow = os::instance()->makeWindow(spec); | ||
newWindow->setCursor(os::NativeCursor::Arrow); | ||
newWindow->setTitle(title); | ||
newWindow->setVisible(true); | ||
newWindow->setDragTarget(std::make_unique<DragTarget>(newWindow)); | ||
for (const auto& box : initialBoxes) { | ||
create_box(newWindow.get(), box); | ||
} | ||
|
||
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; | ||
|
||
// Create two windows that can act as Drag and Drop target and/or source. | ||
auto screen = system->mainScreen(); | ||
os::WindowSpec spec; | ||
spec.titled(true); | ||
spec.position(os::WindowSpec::Position::Frame); | ||
auto frame = screen->workarea()/2; | ||
spec.frame(frame); | ||
spec.screen(screen); | ||
windowA = create_window("A", spec, {{32, frame.h - 64 - 40, 64, 64}}); | ||
frame.offset(frame.w, 0); | ||
spec.frame(frame); | ||
windowB = create_window("B", spec, {}); | ||
|
||
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()); | ||
ev.window()->invalidate(); | ||
break; | ||
|
||
case os::Event::KeyDown: | ||
switch (ev.scancode()) { | ||
|
||
case os::kKeyT: | ||
break; | ||
|
||
case os::kKeyS: | ||
break; | ||
|
||
case os::kKeyA: | ||
windowData[ev.window().get()].acceptDrop = !windowData[ev.window().get()].acceptDrop; | ||
redraw_window(ev.window().get()); | ||
ev.window()->invalidate(); | ||
break; | ||
} | ||
break; | ||
|
||
default: | ||
// Do nothing | ||
break; | ||
} | ||
} | ||
|
||
return 0; | ||
} |
Oops, something went wrong.