164
src/App.cpp
164
src/App.cpp
@@ -191,6 +191,8 @@ auto App::run() -> void
|
|||||||
while (m_running) {
|
while (m_running) {
|
||||||
pump_events();
|
pump_events();
|
||||||
tick();
|
tick();
|
||||||
|
m_kbd.typing.clear();
|
||||||
|
m_kbd.clear_transients();
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,19 +251,23 @@ auto App::init_wayland() -> void
|
|||||||
close(fd);
|
close(fd);
|
||||||
} };
|
} };
|
||||||
|
|
||||||
auto kb_enter { [](void *, wl_keyboard *, u32, wl_surface *,
|
auto kb_enter { [](void *data, wl_keyboard *, u32 serial, wl_surface *,
|
||||||
wl_array *) -> void { } };
|
wl_array *) -> void {
|
||||||
|
static_cast<App *>(data)->m_last_serial = serial;
|
||||||
|
} };
|
||||||
auto kb_leave
|
auto kb_leave
|
||||||
= [](void *data, wl_keyboard *, u32, wl_surface *) -> void {
|
= [](void *data, wl_keyboard *, u32, wl_surface *) -> void {
|
||||||
static_cast<App *>(data)->m_kbd.held.clear();
|
static_cast<App *>(data)->m_kbd.held.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto kb_key { [](void *data, wl_keyboard *, u32, u32, u32 key,
|
auto kb_key { [](void *data, wl_keyboard *, u32 serial, u32, u32 key,
|
||||||
u32 state) -> void {
|
u32 state) -> void {
|
||||||
auto *app { static_cast<App *>(data) };
|
auto *app { static_cast<App *>(data) };
|
||||||
if (!app->m_kbd.xkb_state_v)
|
if (!app->m_kbd.xkb_state_v)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
app->m_last_serial = serial;
|
||||||
|
|
||||||
xkb_keycode_t kc = key + 8;
|
xkb_keycode_t kc = key + 8;
|
||||||
|
|
||||||
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||||
@@ -308,6 +314,11 @@ auto App::init_wayland() -> void
|
|||||||
app->m_kbd.typing.push_back('\n');
|
app->m_kbd.typing.push_back('\n');
|
||||||
handled = true;
|
handled = true;
|
||||||
break;
|
break;
|
||||||
|
case XKB_KEY_v:
|
||||||
|
case XKB_KEY_V:
|
||||||
|
app->m_kbd.typing.push_back('v');
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
case XKB_KEY_w:
|
case XKB_KEY_w:
|
||||||
case XKB_KEY_W:
|
case XKB_KEY_W:
|
||||||
if (ctrl) {
|
if (ctrl) {
|
||||||
@@ -490,6 +501,99 @@ auto App::init_wayland() -> void
|
|||||||
registry, name, &zwp_text_input_manager_v3_interface, 1));
|
registry, name, &zwp_text_input_manager_v3_interface, 1));
|
||||||
app->m_ime.supported = true;
|
app->m_ime.supported = true;
|
||||||
ensure_text_input(app);
|
ensure_text_input(app);
|
||||||
|
} else if (std::strcmp(interface, wl_data_device_manager_interface.name)
|
||||||
|
== 0) {
|
||||||
|
app->m_wayland.ddm
|
||||||
|
= static_cast<wl_data_device_manager *>(wl_registry_bind(
|
||||||
|
registry, name, &wl_data_device_manager_interface,
|
||||||
|
std::min<uint32_t>(version, 3)));
|
||||||
|
if (app->m_wayland.ddm && !app->m_wayland.ddev) {
|
||||||
|
app->m_wayland.ddev = wl_data_device_manager_get_data_device(
|
||||||
|
app->m_wayland.ddm, app->m_wayland.seat);
|
||||||
|
static wl_data_device_listener const ddev_l = {
|
||||||
|
.data_offer =
|
||||||
|
[](void *data, wl_data_device *, wl_data_offer *offer) {
|
||||||
|
auto *app = static_cast<App *>(data);
|
||||||
|
static wl_data_offer_listener const offer_l = {
|
||||||
|
.offer =
|
||||||
|
[](void *data, wl_data_offer *,
|
||||||
|
char const *mime) {
|
||||||
|
auto *app = static_cast<App *>(data);
|
||||||
|
(void)app;
|
||||||
|
(void)mime;
|
||||||
|
},
|
||||||
|
#if WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION
|
||||||
|
.source_actions
|
||||||
|
= [](void *, wl_data_offer *, uint32_t) {},
|
||||||
|
.action
|
||||||
|
= [](void *, wl_data_offer *, uint32_t) {}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
wl_data_offer_add_listener(offer, &offer_l, app);
|
||||||
|
// swap old
|
||||||
|
if (app->m_wayland.curr_offer
|
||||||
|
&& app->m_wayland.curr_offer != offer)
|
||||||
|
wl_data_offer_destroy(
|
||||||
|
app->m_wayland.curr_offer);
|
||||||
|
app->m_wayland.curr_offer = offer;
|
||||||
|
},
|
||||||
|
.enter
|
||||||
|
= [](void *, wl_data_device *, uint32_t, wl_surface *,
|
||||||
|
wl_fixed_t, wl_fixed_t, wl_data_offer *) {},
|
||||||
|
.leave = [](void *, wl_data_device *) {},
|
||||||
|
.motion = [](void *, wl_data_device *, uint32_t, wl_fixed_t,
|
||||||
|
wl_fixed_t) {},
|
||||||
|
.drop = [](void *, wl_data_device *) {},
|
||||||
|
.selection =
|
||||||
|
[](void *data, wl_data_device *, wl_data_offer *offer) {
|
||||||
|
auto *app = static_cast<App *>(data);
|
||||||
|
if (!offer) {
|
||||||
|
app->m_clipboard_cache.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char const *mime_utf8 = "text/plain;charset=utf-8";
|
||||||
|
char const *mime_plain = "text/plain";
|
||||||
|
int fds[2];
|
||||||
|
if (pipe(fds) != 0)
|
||||||
|
return;
|
||||||
|
wl_data_offer_receive(offer, mime_utf8, fds[1]);
|
||||||
|
wl_display_flush(app->m_wayland.display);
|
||||||
|
close(fds[1]);
|
||||||
|
std::string data_utf8;
|
||||||
|
char buf[4096];
|
||||||
|
for (;;) {
|
||||||
|
ssize_t n = read(fds[0], buf, sizeof(buf));
|
||||||
|
if (n > 0)
|
||||||
|
data_utf8.append(buf, buf + n);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
close(fds[0]);
|
||||||
|
|
||||||
|
if (data_utf8.empty()) {
|
||||||
|
if (pipe(fds) != 0)
|
||||||
|
return;
|
||||||
|
wl_data_offer_receive(
|
||||||
|
offer, mime_plain, fds[1]);
|
||||||
|
wl_display_flush(app->m_wayland.display);
|
||||||
|
close(fds[1]);
|
||||||
|
std::string data_plain;
|
||||||
|
for (;;) {
|
||||||
|
ssize_t n = read(fds[0], buf, sizeof(buf));
|
||||||
|
if (n > 0)
|
||||||
|
data_plain.append(buf, buf + n);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
close(fds[0]);
|
||||||
|
app->m_clipboard_cache = std::move(data_plain);
|
||||||
|
} else {
|
||||||
|
app->m_clipboard_cache = std::move(data_utf8);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
wl_data_device_add_listener(app->m_wayland.ddev, &ddev_l, app);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -981,3 +1085,57 @@ auto App::pump_events() -> void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto App::clipboard(std::string_view const &str) -> void
|
||||||
|
{
|
||||||
|
if (!m_wayland.ddm || !m_wayland.ddev || !m_wayland.seat)
|
||||||
|
return;
|
||||||
|
if (m_last_serial == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_wayland.curr_source) {
|
||||||
|
wl_data_source_destroy(m_wayland.curr_source);
|
||||||
|
m_wayland.curr_source = nullptr;
|
||||||
|
}
|
||||||
|
m_wayland.curr_source
|
||||||
|
= wl_data_device_manager_create_data_source(m_wayland.ddm);
|
||||||
|
|
||||||
|
static wl_data_source_listener const src_l = {
|
||||||
|
.target = [](void *, wl_data_source *, char const *) {},
|
||||||
|
.send =
|
||||||
|
[](void *data, wl_data_source *, char const *mime, int32_t fd) {
|
||||||
|
auto *app = static_cast<App *>(data);
|
||||||
|
(void)mime;
|
||||||
|
size_t off = 0;
|
||||||
|
while (off < app->m_clipboard_cache.size()) {
|
||||||
|
ssize_t n = write(fd, app->m_clipboard_cache.data() + off,
|
||||||
|
app->m_clipboard_cache.size() - off);
|
||||||
|
if (n <= 0)
|
||||||
|
break;
|
||||||
|
off += static_cast<size_t>(n);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
},
|
||||||
|
.cancelled =
|
||||||
|
[](void *data, wl_data_source *src) {
|
||||||
|
auto *app = static_cast<App *>(data);
|
||||||
|
if (app->m_wayland.curr_source == src)
|
||||||
|
app->m_wayland.curr_source = nullptr;
|
||||||
|
wl_data_source_destroy(src);
|
||||||
|
},
|
||||||
|
#if WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION
|
||||||
|
.dnd_drop_performed = [](void *, wl_data_source *) {},
|
||||||
|
.dnd_finished = [](void *, wl_data_source *) {},
|
||||||
|
.action = [](void *, wl_data_source *, uint32_t) {}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
wl_data_source_add_listener(m_wayland.curr_source, &src_l, this);
|
||||||
|
wl_data_source_offer(m_wayland.curr_source, "text/plain;charset=utf-8");
|
||||||
|
wl_data_source_offer(m_wayland.curr_source, "text/plain");
|
||||||
|
|
||||||
|
m_clipboard_cache.assign(str.begin(), str.end());
|
||||||
|
|
||||||
|
wl_data_device_set_selection(
|
||||||
|
m_wayland.ddev, m_wayland.curr_source, m_last_serial);
|
||||||
|
wl_display_flush(m_wayland.display);
|
||||||
|
}
|
||||||
|
|||||||
17
src/App.hpp
17
src/App.hpp
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <libportal/portal.h>
|
#include <libportal/portal.h>
|
||||||
|
#include <wayland-client-protocol.h>
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "blur-client-protocol.h"
|
#include "blur-client-protocol.h"
|
||||||
#define namespace namespace_
|
#define namespace namespace_
|
||||||
@@ -50,13 +51,19 @@ private:
|
|||||||
auto ensure_egl_surface() -> void;
|
auto ensure_egl_surface() -> void;
|
||||||
auto update_blur_region() -> void;
|
auto update_blur_region() -> void;
|
||||||
auto process_pending_text_input() -> void;
|
auto process_pending_text_input() -> void;
|
||||||
auto update_text_input_state(std::pmr::string const &text, usize id,
|
auto update_text_input_state(
|
||||||
Rectangle field_rect) -> void;
|
std::pmr::string const &text, usize id, Rectangle field_rect) -> void;
|
||||||
auto theme() const -> ColorScheme const &
|
auto theme() const -> ColorScheme const &
|
||||||
{
|
{
|
||||||
return m_themes[m_active_theme];
|
return m_themes[m_active_theme];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto clipboard() const -> std::pmr::string const &
|
||||||
|
{
|
||||||
|
return m_clipboard_cache;
|
||||||
|
}
|
||||||
|
auto clipboard(std::string_view const &str) -> void;
|
||||||
|
|
||||||
static void on_settings_changed(XdpSettings * /*self*/, char const *ns,
|
static void on_settings_changed(XdpSettings * /*self*/, char const *ns,
|
||||||
char const *key, GVariant * /*value*/, gpointer data);
|
char const *key, GVariant * /*value*/, gpointer data);
|
||||||
|
|
||||||
@@ -75,7 +82,13 @@ private:
|
|||||||
org_kde_kwin_blur *kde_blur {};
|
org_kde_kwin_blur *kde_blur {};
|
||||||
zwp_text_input_manager_v3 *text_input_mgr {};
|
zwp_text_input_manager_v3 *text_input_mgr {};
|
||||||
zwp_text_input_v3 *text_input {};
|
zwp_text_input_v3 *text_input {};
|
||||||
|
wl_data_device_manager *ddm {};
|
||||||
|
wl_data_device *ddev {};
|
||||||
|
wl_data_offer *curr_offer {};
|
||||||
|
wl_data_source *curr_source {};
|
||||||
} m_wayland;
|
} m_wayland;
|
||||||
|
std::pmr::string m_clipboard_cache;
|
||||||
|
u32 m_last_serial { 0 };
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
EGLDisplay edpy { EGL_NO_DISPLAY };
|
EGLDisplay edpy { EGL_NO_DISPLAY };
|
||||||
|
|||||||
135
src/ImGui.cpp
135
src/ImGui.cpp
@@ -19,67 +19,52 @@ struct CodepointSpan {
|
|||||||
usize end {};
|
usize end {};
|
||||||
};
|
};
|
||||||
|
|
||||||
auto decode_utf8(std::string_view text) -> std::vector<CodepointSpan>
|
constexpr auto utf8_rune_from_first(char const *s) -> u32
|
||||||
|
{
|
||||||
|
u8 b0 = static_cast<u8>(s[0]);
|
||||||
|
if (b0 < 0x80)
|
||||||
|
return b0;
|
||||||
|
|
||||||
|
if ((b0 & 0xE0) == 0xC0)
|
||||||
|
return ((b0 & 0x1F) << 6) | (static_cast<u8>(s[1]) & 0x3F);
|
||||||
|
|
||||||
|
if ((b0 & 0xF0) == 0xE0)
|
||||||
|
return ((b0 & 0x0F) << 12) | ((static_cast<u8>(s[1]) & 0x3F) << 6)
|
||||||
|
| (static_cast<u8>(s[2]) & 0x3F);
|
||||||
|
|
||||||
|
if ((b0 & 0xF8) == 0xF0)
|
||||||
|
return ((b0 & 0x07) << 18) | ((static_cast<u8>(s[1]) & 0x3F) << 12)
|
||||||
|
| ((static_cast<u8>(s[2]) & 0x3F) << 6)
|
||||||
|
| (static_cast<u8>(s[3]) & 0x3F);
|
||||||
|
|
||||||
|
return 0xFFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto decode_utf8(std::string_view text) -> std::vector<CodepointSpan>
|
||||||
{
|
{
|
||||||
std::vector<CodepointSpan> spans;
|
std::vector<CodepointSpan> spans;
|
||||||
usize i = 0;
|
usize i = 0;
|
||||||
spans.reserve(text.size());
|
spans.reserve(text.size());
|
||||||
|
|
||||||
while (i < text.size()) {
|
while (i < text.size()) {
|
||||||
u8 const byte = static_cast<u8>(text[i]);
|
u8 b = static_cast<u8>(text[i]);
|
||||||
usize const start = i;
|
usize len = 1;
|
||||||
usize length = 1;
|
|
||||||
u32 cp = 0xFFFD;
|
|
||||||
|
|
||||||
if (byte < 0x80) {
|
if (b < 0x80)
|
||||||
cp = byte;
|
len = 1;
|
||||||
} else if ((byte & 0xE0) == 0xC0) {
|
else if ((b & 0xE0) == 0xC0)
|
||||||
if (i + 1 < text.size()) {
|
len = 2;
|
||||||
u8 const b1 = static_cast<u8>(text[i + 1]);
|
else if ((b & 0xF0) == 0xE0)
|
||||||
if ((b1 & 0xC0) == 0x80) {
|
len = 3;
|
||||||
u32 const t = ((static_cast<u32>(byte) & 0x1F) << 6)
|
else if ((b & 0xF8) == 0xF0)
|
||||||
| (static_cast<u32>(b1) & 0x3F);
|
len = 4;
|
||||||
if (t >= 0x80) {
|
|
||||||
cp = t;
|
|
||||||
length = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ((byte & 0xF0) == 0xE0) {
|
|
||||||
if (i + 2 < text.size()) {
|
|
||||||
u8 const b1 = static_cast<u8>(text[i + 1]);
|
|
||||||
u8 const b2 = static_cast<u8>(text[i + 2]);
|
|
||||||
if ((b1 & 0xC0) == 0x80 && (b2 & 0xC0) == 0x80) {
|
|
||||||
u32 const t = ((static_cast<u32>(byte) & 0x0F) << 12)
|
|
||||||
| ((static_cast<u32>(b1) & 0x3F) << 6)
|
|
||||||
| (static_cast<u32>(b2) & 0x3F);
|
|
||||||
if (t >= 0x800 && (t < 0xD800 || t > 0xDFFF)) {
|
|
||||||
cp = t;
|
|
||||||
length = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ((byte & 0xF8) == 0xF0) {
|
|
||||||
if (i + 3 < text.size()) {
|
|
||||||
u8 const b1 = static_cast<u8>(text[i + 1]);
|
|
||||||
u8 const b2 = static_cast<u8>(text[i + 2]);
|
|
||||||
u8 const b3 = static_cast<u8>(text[i + 3]);
|
|
||||||
if ((b1 & 0xC0) == 0x80 && (b2 & 0xC0) == 0x80
|
|
||||||
&& (b3 & 0xC0) == 0x80) {
|
|
||||||
u32 const t = ((static_cast<u32>(byte) & 0x07) << 18)
|
|
||||||
| ((static_cast<u32>(b1) & 0x3F) << 12)
|
|
||||||
| ((static_cast<u32>(b2) & 0x3F) << 6)
|
|
||||||
| (static_cast<u32>(b3) & 0x3F);
|
|
||||||
if (t >= 0x10000 && t <= 0x10FFFF) {
|
|
||||||
cp = t;
|
|
||||||
length = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spans.push_back(CodepointSpan { cp, start, start + length });
|
if (i + len > text.size())
|
||||||
i += length;
|
len = 1; // avoid overflow
|
||||||
|
|
||||||
|
u32 cp = utf8_rune_from_first(text.data() + i);
|
||||||
|
spans.push_back({ cp, i, i + len });
|
||||||
|
i += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return spans;
|
return spans;
|
||||||
@@ -158,14 +143,25 @@ ImGui::ImGui(std::shared_ptr<TextRenderer> text_renderer)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui::begin(u32 const rune, bool ctrl, bool shift)
|
void ImGui::begin(u32 const rune, bool ctrl, bool shift,
|
||||||
|
std::string_view const clipboard,
|
||||||
|
std::function<void(std::string_view const &)> clipboard_set)
|
||||||
{
|
{
|
||||||
m_rune = rune;
|
m_rune = rune;
|
||||||
m_ctrl = ctrl;
|
m_ctrl = ctrl;
|
||||||
m_shift = shift;
|
m_shift = shift;
|
||||||
|
m_clipboard = clipboard;
|
||||||
|
m_clipboard_set = clipboard_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui::end() { }
|
void ImGui::end()
|
||||||
|
{
|
||||||
|
m_rune = false;
|
||||||
|
m_ctrl = false;
|
||||||
|
m_shift = false;
|
||||||
|
m_clipboard = {};
|
||||||
|
m_clipboard_set = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void ImGui::set_font(FontHandle font) { m_font = font; }
|
void ImGui::set_font(FontHandle font) { m_font = font; }
|
||||||
|
|
||||||
@@ -289,6 +285,15 @@ void ImGui::ime_clear_preedit()
|
|||||||
state.caret_timer = 0.0;
|
state.caret_timer = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t utf8_length(std::string_view const &s)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
for (unsigned char c : s)
|
||||||
|
if ((c & 0xC0) != 0x80) // continuation bytes
|
||||||
|
++count;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
auto ImGui::text_input(usize id, std::pmr::string &str, Rectangle rec,
|
auto ImGui::text_input(usize id, std::pmr::string &str, Rectangle rec,
|
||||||
TextInputOptions options) -> std::bitset<2>
|
TextInputOptions options) -> std::bitset<2>
|
||||||
{
|
{
|
||||||
@@ -479,6 +484,26 @@ auto ImGui::text_input(usize id, std::pmr::string &str, Rectangle rec,
|
|||||||
submitted = true;
|
submitted = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'v':
|
||||||
|
if (m_ctrl && !m_clipboard.empty()) {
|
||||||
|
if (!options.multiline) {
|
||||||
|
std::string clipboard_no_newlines;
|
||||||
|
for (auto const &ch : m_clipboard) {
|
||||||
|
if (ch == '\n' || ch == '\r')
|
||||||
|
continue;
|
||||||
|
clipboard_no_newlines.push_back(ch);
|
||||||
|
}
|
||||||
|
str.insert(caret_byte, clipboard_no_newlines);
|
||||||
|
state.current_rune_idx
|
||||||
|
+= utf8_length(clipboard_no_newlines);
|
||||||
|
} else {
|
||||||
|
str.insert(caret_byte, m_clipboard);
|
||||||
|
state.current_rune_idx += utf8_length(m_clipboard);
|
||||||
|
}
|
||||||
|
changed = true;
|
||||||
|
request_refresh = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if (m_rune >= 0x20) {
|
if (m_rune >= 0x20) {
|
||||||
auto encoded { encode_utf8(m_rune) };
|
auto encoded { encode_utf8(m_rune) };
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ struct ImGui {
|
|||||||
ImGui(ImGui &&) = default;
|
ImGui(ImGui &&) = default;
|
||||||
auto operator=(ImGui &&) -> ImGui & = default;
|
auto operator=(ImGui &&) -> ImGui & = default;
|
||||||
|
|
||||||
void begin(u32 const rune, bool ctrl, bool shift);
|
void begin(u32 const rune, bool ctrl, bool shift,
|
||||||
|
std::string_view const clipboard,
|
||||||
|
std::function<void(std::string_view const &)> clipboard_set);
|
||||||
void end();
|
void end();
|
||||||
|
|
||||||
// Bit 0 -> Submitted
|
// Bit 0 -> Submitted
|
||||||
@@ -127,6 +129,8 @@ private:
|
|||||||
u32 m_rune {}; // 1234 <-> hjkl arrow keys
|
u32 m_rune {}; // 1234 <-> hjkl arrow keys
|
||||||
bool m_ctrl {};
|
bool m_ctrl {};
|
||||||
bool m_shift {};
|
bool m_shift {};
|
||||||
|
std::string_view m_clipboard {};
|
||||||
|
std::function<void(std::string_view const &)> m_clipboard_set;
|
||||||
|
|
||||||
std::queue<Style> m_styles { { Style {} } };
|
std::queue<Style> m_styles { { Style {} } };
|
||||||
|
|
||||||
@@ -136,10 +140,11 @@ private:
|
|||||||
|
|
||||||
struct ImGuiGuard {
|
struct ImGuiGuard {
|
||||||
ImGuiGuard(std::shared_ptr<ImGui> imgui, u32 const rune, bool const ctrl,
|
ImGuiGuard(std::shared_ptr<ImGui> imgui, u32 const rune, bool const ctrl,
|
||||||
bool const shift)
|
bool const shift, std::string_view const clipboard,
|
||||||
|
std::function<void(std::string_view const &)> clipboard_set)
|
||||||
: m_imgui(imgui)
|
: m_imgui(imgui)
|
||||||
{
|
{
|
||||||
m_imgui->begin(rune, ctrl, shift);
|
m_imgui->begin(rune, ctrl, shift, clipboard, clipboard_set);
|
||||||
}
|
}
|
||||||
~ImGuiGuard() { m_imgui->end(); }
|
~ImGuiGuard() { m_imgui->end(); }
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ auto App::tick() -> void
|
|||||||
rune = m_kbd.typing.back();
|
rune = m_kbd.typing.back();
|
||||||
m_kbd.typing.clear();
|
m_kbd.typing.clear();
|
||||||
}
|
}
|
||||||
ImGuiGuard gui_scope(m_gui, rune, m_kbd.ctrl(), m_kbd.shift());
|
ImGuiGuard gui_scope(m_gui, rune, m_kbd.ctrl(), m_kbd.shift(),
|
||||||
|
clipboard(),
|
||||||
|
[this](std::string_view const &str) { clipboard(str); });
|
||||||
|
|
||||||
Rectangle const input_rect {
|
Rectangle const input_rect {
|
||||||
0.0f,
|
0.0f,
|
||||||
@@ -63,6 +65,4 @@ auto App::tick() -> void
|
|||||||
EndDrawing();
|
EndDrawing();
|
||||||
|
|
||||||
eglSwapBuffers(m_gl.edpy, m_gl.esurf);
|
eglSwapBuffers(m_gl.edpy, m_gl.esurf);
|
||||||
m_kbd.typing.clear();
|
|
||||||
m_kbd.clear_transients();
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user