summaryrefslogtreecommitdiff
path: root/src/components/chatinput.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/chatinput.cpp')
-rw-r--r--src/components/chatinput.cpp204
1 files changed, 199 insertions, 5 deletions
diff --git a/src/components/chatinput.cpp b/src/components/chatinput.cpp
index c3eca32..6afdd82 100644
--- a/src/components/chatinput.cpp
+++ b/src/components/chatinput.cpp
@@ -1,6 +1,10 @@
#include "chatinput.hpp"
+#include "abaddon.hpp"
+#include "constants.hpp"
+#include <filesystem>
+#include <utility>
-ChatInput::ChatInput() {
+ChatInputText::ChatInputText() {
get_style_context()->add_class("message-input");
set_propagate_natural_height(true);
set_min_content_height(20);
@@ -20,22 +24,26 @@ ChatInput::ChatInput() {
add(m_textview);
}
-void ChatInput::InsertText(const Glib::ustring &text) {
+void ChatInputText::InsertText(const Glib::ustring &text) {
GetBuffer()->insert_at_cursor(text);
m_textview.grab_focus();
}
-Glib::RefPtr<Gtk::TextBuffer> ChatInput::GetBuffer() {
+Glib::RefPtr<Gtk::TextBuffer> ChatInputText::GetBuffer() {
return m_textview.get_buffer();
}
// this isnt connected directly so that the chat window can handle stuff like the completer first
-bool ChatInput::ProcessKeyPress(GdkEventKey *event) {
+bool ChatInputText::ProcessKeyPress(GdkEventKey *event) {
if (event->keyval == GDK_KEY_Escape) {
m_signal_escape.emit();
return true;
}
+ if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_v) {
+ return CheckHandleClipboardPaste();
+ }
+
if (event->keyval == GDK_KEY_Return) {
if (event->state & GDK_SHIFT_MASK)
return false;
@@ -53,10 +61,196 @@ bool ChatInput::ProcessKeyPress(GdkEventKey *event) {
return false;
}
-void ChatInput::on_grab_focus() {
+void ChatInputText::on_grab_focus() {
m_textview.grab_focus();
}
+bool ChatInputText::CheckHandleClipboardPaste() {
+ auto clip = Gtk::Clipboard::get();
+ if (!clip->wait_is_image_available()) return false;
+
+ const auto pb = clip->wait_for_image();
+ std::array<char, L_tmpnam> dest_name {};
+ if (std::tmpnam(dest_name.data()) == nullptr) {
+ fprintf(stderr, "failed to get temporary path\n");
+ return true;
+ }
+
+ // stinky
+ std::filesystem::path part1(std::filesystem::temp_directory_path() / "abaddon-cache");
+ std::filesystem::path part2(dest_name.data());
+ const auto dest_path = (part1 / part2.relative_path()).string();
+
+ try {
+ pb->save(dest_path, "png");
+ } catch (...) {
+ fprintf(stderr, "pasted image save error\n");
+ return true;
+ }
+
+ m_signal_image_paste.emit(pb, dest_path);
+
+ return true;
+}
+
+ChatInputText::type_signal_submit ChatInputText::signal_submit() {
+ return m_signal_submit;
+}
+
+ChatInputText::type_signal_escape ChatInputText::signal_escape() {
+ return m_signal_escape;
+}
+
+ChatInputText::type_signal_image_paste ChatInputText::signal_image_paste() {
+ return m_signal_image_paste;
+}
+
+ChatInputAttachmentContainer::ChatInputAttachmentContainer()
+ : m_box(Gtk::ORIENTATION_HORIZONTAL) {
+ get_style_context()->add_class("attachment-container");
+
+ add(m_box);
+ m_box.show();
+
+ set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_NEVER);
+ set_vexpand(true);
+ set_size_request(-1, AttachmentItemSize + 10);
+}
+
+void ChatInputAttachmentContainer::Clear() {
+ for (auto *x : m_attachments)
+ delete x;
+ m_attachments.clear();
+}
+
+bool ChatInputAttachmentContainer::AddImage(const Glib::RefPtr<Gdk::Pixbuf> &pb, const std::string &path) {
+ if (m_attachments.size() == 10) return false;
+
+ auto *item = Gtk::make_managed<ChatInputAttachmentItem>(path, pb);
+ item->show();
+ item->set_valign(Gtk::ALIGN_CENTER);
+ m_box.add(*item);
+
+ m_attachments.insert(item);
+
+ item->signal_remove().connect([this, item] {
+ m_attachments.erase(item);
+ delete item;
+ if (m_attachments.empty())
+ m_signal_emptied.emit();
+ });
+
+ return true;
+}
+
+std::vector<std::string> ChatInputAttachmentContainer::GetFilePaths() const {
+ std::vector<std::string> ret;
+ for (auto *x : m_attachments)
+ ret.push_back(x->GetPath());
+ return ret;
+}
+
+ChatInputAttachmentContainer::type_signal_emptied ChatInputAttachmentContainer::signal_emptied() {
+ return m_signal_emptied;
+}
+
+ChatInputAttachmentItem::ChatInputAttachmentItem(std::string path, const Glib::RefPtr<Gdk::Pixbuf> &pb)
+ : m_path(std::move(path))
+ , m_img(Gtk::make_managed<Gtk::Image>()) {
+ get_style_context()->add_class("attachment-item");
+
+ int outw, outh;
+ GetImageDimensions(pb->get_width(), pb->get_height(), outw, outh, AttachmentItemSize, AttachmentItemSize);
+ m_img->property_pixbuf() = pb->scale_simple(outw, outh, Gdk::INTERP_BILINEAR);
+
+ set_size_request(AttachmentItemSize, AttachmentItemSize);
+ m_box.add(*m_img);
+ add(m_box);
+ show_all_children();
+
+ SetupMenu();
+}
+
+std::string ChatInputAttachmentItem::GetPath() const {
+ return m_path;
+}
+
+void ChatInputAttachmentItem::SetupMenu() {
+ m_menu_remove.set_label("Remove");
+ m_menu_remove.signal_activate().connect([this] {
+ m_signal_remove.emit();
+ });
+
+ m_menu.add(m_menu_remove);
+ m_menu.show_all();
+
+ signal_button_press_event().connect([this](GdkEventButton *ev) -> bool {
+ if (ev->button == GDK_BUTTON_SECONDARY) {
+ m_menu.popup_at_pointer(reinterpret_cast<GdkEvent *>(ev));
+ return true;
+ }
+
+ return false;
+ });
+}
+
+ChatInputAttachmentItem::type_signal_remove ChatInputAttachmentItem::signal_remove() {
+ return m_signal_remove;
+}
+
+ChatInput::ChatInput()
+ : Gtk::Box(Gtk::ORIENTATION_VERTICAL) {
+ m_input.signal_escape().connect([this] {
+ m_attachments.Clear();
+ m_attachments_revealer.set_reveal_child(false);
+ m_signal_escape.emit();
+ });
+ m_input.signal_submit().connect([this](const Glib::ustring &input) -> bool {
+ const auto attachments = m_attachments.GetFilePaths();
+ bool b = m_signal_submit.emit(input, attachments);
+ if (b) {
+ m_attachments.Clear();
+ m_attachments_revealer.set_reveal_child(false);
+ }
+ return b;
+ });
+
+ m_attachments.set_vexpand(false);
+
+ m_attachments_revealer.set_transition_type(Gtk::REVEALER_TRANSITION_TYPE_SLIDE_UP);
+ m_attachments_revealer.add(m_attachments);
+ add(m_attachments_revealer);
+ add(m_input);
+ show_all_children();
+
+ m_input.signal_image_paste().connect([this](const Glib::RefPtr<Gdk::Pixbuf> &pb, const std::string &path) {
+ if (m_attachments.AddImage(pb, path))
+ m_attachments_revealer.set_reveal_child(true);
+ });
+
+ // double hack !
+ auto cb = [this](GdkEventKey *e) -> bool {
+ return event(reinterpret_cast<GdkEvent *>(e));
+ };
+ m_input.signal_key_press_event().connect(cb, false);
+
+ m_attachments.signal_emptied().connect([this] {
+ m_attachments_revealer.set_reveal_child(false);
+ });
+}
+
+void ChatInput::InsertText(const Glib::ustring &text) {
+ m_input.InsertText(text);
+}
+
+Glib::RefPtr<Gtk::TextBuffer> ChatInput::GetBuffer() {
+ return m_input.GetBuffer();
+}
+
+bool ChatInput::ProcessKeyPress(GdkEventKey *event) {
+ return m_input.ProcessKeyPress(event);
+}
+
ChatInput::type_signal_submit ChatInput::signal_submit() {
return m_signal_submit;
}