From a535703add6bf29878845cb270997514489cfc16 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 31 Oct 2018 18:12:49 +0100 Subject: Start with images/gif, resize chat input --- css/style.css | 28 ++++++++++++++++++++ depends/dchat_core | 2 +- include/Cache.hpp | 16 ------------ include/ChannelDataType.hpp | 2 +- include/ChatMessage.hpp | 7 +++-- include/ChatWindow.hpp | 5 ++-- include/GlobalCache.hpp | 8 ++++++ include/GtkGif.hpp | 24 +++++++++++++++++ include/env.hpp | 59 ------------------------------------------ include/types.hpp | 22 ---------------- src/Cache.cpp | 63 --------------------------------------------- src/ChatMessage.cpp | 32 +++++++++++++++++++++-- src/ChatWindow.cpp | 59 +++++++++++++++++++++++++++++++++++++----- src/GlobalCache.cpp | 18 +++++++++++++ src/GtkGif.cpp | 31 ++++++++++++++++++++++ src/Window.cpp | 8 +++++- 16 files changed, 208 insertions(+), 176 deletions(-) delete mode 100644 include/Cache.hpp create mode 100644 include/GlobalCache.hpp create mode 100644 include/GtkGif.hpp delete mode 100644 include/env.hpp delete mode 100644 include/types.hpp delete mode 100644 src/Cache.cpp create mode 100644 src/GlobalCache.cpp create mode 100644 src/GtkGif.cpp diff --git a/css/style.css b/css/style.css index ad354f8..65cc83d 100644 --- a/css/style.css +++ b/css/style.css @@ -19,6 +19,24 @@ label { color: #f7f7f7; } +scrolledwindow { + border-style: none; +} + +grid { + border-style: none; +} + +paned { + border-style: none; +} + +scrollbar { + background-color: transparent; + border-style: none; + outline-style: none; +} + button { background-image: none; background-color: #2f3136; @@ -170,6 +188,12 @@ textview text { #chat-scroll-view { background-color: #444444; + margin-top: 15px; + margin-bottom: 15px; + margin-left: 20px; + margin-right: 20px; + box-shadow: 0px 0px 5px #1d1d1d; + padding: 10px; /*padding: 10px 10px 10px 10px;*/ } /* @@ -178,6 +202,10 @@ textview text { } */ +#chat-input { + font-size: 14px; +} + .window-notification { background-color: #aa3030; } diff --git a/depends/dchat_core b/depends/dchat_core index 645efbf..699811d 160000 --- a/depends/dchat_core +++ b/depends/dchat_core @@ -1 +1 @@ -Subproject commit 645efbfe3120d1f02edb7f35eefe0dde7533c6b0 +Subproject commit 699811dbcc8194c95ffe7874ac8d2fb97e039410 diff --git a/include/Cache.hpp b/include/Cache.hpp deleted file mode 100644 index 97ef495..0000000 --- a/include/Cache.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -namespace dchat -{ - class Cache - { - public: - Cache(); - ~Cache(); - - // Creates directory if it doesn't exist (recursively). Throws boost exception on failure - static boost::filesystem::path getDchatDir(); - }; -} diff --git a/include/ChannelDataType.hpp b/include/ChannelDataType.hpp index 398e716..21e828d 100644 --- a/include/ChannelDataType.hpp +++ b/include/ChannelDataType.hpp @@ -1,6 +1,6 @@ #pragma once -#include "types.hpp" +#include namespace dchat { diff --git a/include/ChatMessage.hpp b/include/ChatMessage.hpp index 271aa5f..c13db9d 100644 --- a/include/ChatMessage.hpp +++ b/include/ChatMessage.hpp @@ -1,6 +1,6 @@ #pragma once -#include "types.hpp" +#include #include #include @@ -11,10 +11,13 @@ namespace dchat { public: ChatMessage(const Glib::ustring &username, const Glib::ustring &text, uint32_t timestampSeconds, const User *user); - + + Gtk::Grid avatar; Gtk::Label username; Gtk::Label text; uint32_t timestampSeconds; const User *user; + private: + bool updateContent(const Cairo::RefPtr &cairo); }; } \ No newline at end of file diff --git a/include/ChatWindow.hpp b/include/ChatWindow.hpp index b10af2b..0b58506 100644 --- a/include/ChatWindow.hpp +++ b/include/ChatWindow.hpp @@ -38,8 +38,8 @@ namespace dchat Gtk::Grid leftPanelChannels; Gtk::Grid leftPanelUsers; Gtk::Label currentChannelTitle; - Gtk::ScrolledWindow chatArea; - Gtk::Grid chatAreaLayout; + Gtk::ScrolledWindow messageArea; + Gtk::Grid messageAreaLayout; Gtk::TextView chatInput; struct ChannelData @@ -53,5 +53,6 @@ namespace dchat std::vector users; ChatMessage *lastMessage; + int chatPrevNumLines; }; } \ No newline at end of file diff --git a/include/GlobalCache.hpp b/include/GlobalCache.hpp new file mode 100644 index 0000000..0b48e1c --- /dev/null +++ b/include/GlobalCache.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace dchat +{ + Cache& getGlobalCache(); +} \ No newline at end of file diff --git a/include/GtkGif.hpp b/include/GtkGif.hpp new file mode 100644 index 0000000..91b3a12 --- /dev/null +++ b/include/GtkGif.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +namespace dchat +{ + class GtkGif : public Gif, public Gtk::DrawingArea + { + public: + GtkGif(StringView fileContent); + virtual ~GtkGif(){} + protected: + // Return false if texture creation failed + bool createTexture(int width, int height) override; + // Size of texture data is same as the size that the texture was created with (also same size returned by @getSize function) + void updateTexture(void *textureData) override; + private: + bool on_draw(const Cairo::RefPtr &cairo) override; + private: + Cairo::RefPtr surface; + }; +} \ No newline at end of file diff --git a/include/env.hpp b/include/env.hpp deleted file mode 100644 index 57ae068..0000000 --- a/include/env.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#define OS_FAMILY_WINDOWS 0 -#define OS_FAMILY_POSIX 1 - -#define OS_TYPE_WINDOWS 0 -#define OS_TYPE_LINUX 1 - -#if defined(_WIN32) || defined(_WIN64) - #if defined(_WIN64) - #define SYS_ENV_64BIT - #else - #define SYS_ENV_32BIT - #endif - #define OS_FAMILY OS_FAMILY_WINDOWS - #define OS_TYPE OS_TYPE_WINDOWS - - #ifndef UNICODE - #define UNICODE - #endif - - #ifndef _UNICODE - #define _UNICODE - #endif - - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #endif - - #include -#endif - -#if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(_POSIX_VERSION) - #define OS_FAMILY OS_FAMILY_POSIX -#endif - -#ifdef __linux__ - #define OS_TYPE OS_TYPE_LINUX -#endif - -#if defined(__GNUC__) - #if defined(__x86_64__) || defined(__pc64__) - #define SYS_ENV_64BIT - #else - #define SYS_ENV_32BIT - #endif -#endif - -#if !defined(SYS_ENV_32BIT) && !defined(SYS_ENV_64BIT) - #error "System is not detected as either 32-bit or 64-bit" -#endif - -#if !defined(OS_FAMILY) - #error "System not supported. Only Windows and Posix systems supported right now" -#endif - -#if !defined(OS_TYPE) - #error "System not supported. Only Windows and linux systems supported right now" -#endif diff --git a/include/types.hpp b/include/types.hpp deleted file mode 100644 index 762dab1..0000000 --- a/include/types.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -namespace dchat -{ - typedef int8_t i8; - typedef int16_t i16; - typedef int32_t i32; - typedef int64_t i64; - - typedef uint8_t u8; - typedef uint16_t u16; - typedef uint32_t u32; - typedef uint64_t u64; - - typedef float f32; - typedef double f64; - - typedef intptr_t ssize; - typedef uintptr_t usize; -} diff --git a/src/Cache.cpp b/src/Cache.cpp deleted file mode 100644 index d4c19fb..0000000 --- a/src/Cache.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "../include/Cache.hpp" -#include "../include/env.hpp" -#include - -#if OS_FAMILY == OS_FAMILY_POSIX -#include -#else -#include -#endif - -using namespace std; - -namespace dchat -{ - static boost::filesystem::path getHomeDir() - { - #if OS_FAMILY == OS_FAMILY_POSIX - const char *homeDir = getenv("HOME"); - if(!homeDir) - { - passwd *pw = getpwuid(getuid()); - homeDir = pw->pw_dir; - } - return boost::filesystem::path(homeDir); - #elif OS_FAMILY == OS_FAMILY_WINDOWS - BOOL ret; - HANDLE hToken; - std::wstring homeDir; - DWORD homeDirLen = MAX_PATH; - homeDir.resize(homeDirLen); - - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken)) - return Result::Err("Failed to open process token"); - - if (!GetUserProfileDirectory(hToken, &homeDir[0], &homeDirLen)) - { - CloseHandle(hToken); - return Result::Err("Failed to get home directory"); - } - - CloseHandle(hToken); - homeDir.resize(wcslen(homeDir.c_str())); - return boost::filesystem::path(homeDir); - #endif - } - - Cache::Cache() - { - - } - - Cache::~Cache() - { - - } - - boost::filesystem::path Cache::getDchatDir() - { - boost::filesystem::path dchatHomeDir = getHomeDir() / ".local" / "share" / "dchat"; - boost::filesystem::create_directories(dchatHomeDir); - return dchatHomeDir; - } -} diff --git a/src/ChatMessage.cpp b/src/ChatMessage.cpp index db5fad2..93b52e9 100644 --- a/src/ChatMessage.cpp +++ b/src/ChatMessage.cpp @@ -1,4 +1,6 @@ #include "../include/ChatMessage.hpp" +#include "../include/GlobalCache.hpp" +#include "../include/GtkGif.hpp" namespace dchat { @@ -8,6 +10,9 @@ namespace dchat timestampSeconds(_timestampSeconds), user(_user) { + avatar.set_halign(Gtk::ALIGN_START); + avatar.set_valign(Gtk::ALIGN_START); + username.set_selectable(true); username.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_START); username.get_style_context()->add_class("chat-message-username"); @@ -18,8 +23,31 @@ namespace dchat text.set_line_wrap_mode(Pango::WRAP_WORD_CHAR); text.get_style_context()->add_class("chat-message-text"); - attach(username, 0, 0, 1, 1); - attach(text, 0, 1, 1, 1); + attach(avatar, 0, 0, 1, 2); + attach_next_to(username, avatar, Gtk::POS_RIGHT, 1, 1); + attach_next_to(text, username, Gtk::POS_BOTTOM, 1, 1); get_style_context()->add_class("chat-message"); + + signal_draw().connect(sigc::mem_fun(*this, &ChatMessage::updateContent)); + } + + bool ChatMessage::updateContent(const Cairo::RefPtr &cairo) + { + #if 0 + auto result = getGlobalCache().getContentByUrl("https://discordemoji.com/assets/emoji/3644_epicKirby.gif"); + printf("result type: %d\n", result.type); + if(result.type == ContentByUrlResult::Type::CACHED && result.gif) + { + Gtk::Widget *child = avatar.get_child_at(0, 0); + if(!child) + { + printf("add gif!\n"); + //GtkGif *gif = new GtkGif(GtkGif*)result.gif; + //gif->copy + //avatar.attach(*(GtkGif*)result.gif, 0, 0, 1, 1); + } + } + #endif + return true; } } \ No newline at end of file diff --git a/src/ChatWindow.cpp b/src/ChatWindow.cpp index b0bb696..041d2c3 100644 --- a/src/ChatWindow.cpp +++ b/src/ChatWindow.cpp @@ -1,6 +1,8 @@ #include "../include/ChatWindow.hpp" #include "../include/ChatMessage.hpp" #include +#include +#include #include namespace dchat @@ -82,23 +84,66 @@ namespace dchat void ChatWindow::setupMessageArea(Gtk::Grid *rightPanel) { - chatArea.set_vexpand(true); - chatArea.set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_AUTOMATIC); - rightPanel->attach(chatArea, 0, 0, 1, 2); + //messageArea.set_valign(Gtk::ALIGN_START); + messageArea.set_vexpand(true); + messageArea.set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_AUTOMATIC); + rightPanel->attach(messageArea, 0, 0, 1, 2); - chatAreaLayout.set_name("chat-area-layout"); - chatArea.add(chatAreaLayout); + messageAreaLayout.set_name("chat-area-layout"); + messageArea.add(messageAreaLayout); } void ChatWindow::setupChatInput(Gtk::Grid *rightPanel) { + Gtk::Grid *chatArea = Gtk::manage(new Gtk::Grid()); + rightPanel->attach_next_to(*chatArea, messageArea, Gtk::POS_BOTTOM, 1, 1); + Gtk::ScrolledWindow *chatScrollWindow = Gtk::manage(new Gtk::ScrolledWindow()); + chatScrollWindow->set_hexpand(true); + chatScrollWindow->set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_NEVER); chatScrollWindow->set_name("chat-scroll-view"); - rightPanel->attach_next_to(*chatScrollWindow, chatArea, Gtk::POS_BOTTOM, 1, 1); + chatArea->attach(*chatScrollWindow, 0, 0, 1, 1); chatInput.set_hexpand(true); chatInput.set_name("chat-input"); chatInput.set_wrap_mode(Gtk::WrapMode::WRAP_WORD_CHAR); + + double fontSize = 18.5;//PANGO_PIXELS(chatInput.get_style_context()->get_font().get_size()); + chatPrevNumLines = 1; + chatInput.get_buffer()->signal_changed().connect([this, chatScrollWindow, fontSize] + { + int numLines = chatInput.get_buffer()->get_line_count(); + numLines = std::min(numLines, 10); + if(numLines != chatPrevNumLines) + { + chatPrevNumLines = numLines; + chatScrollWindow->set_min_content_height(fontSize * numLines); + + auto adj = chatScrollWindow->get_vadjustment(); + if(chatInput.get_buffer()->get_line_count() <= 10) + { + chatScrollWindow->set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_NEVER); + adj->set_value(0); + } + else + { + chatScrollWindow->set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_ALWAYS); + } + } + }); + chatScrollWindow->get_vadjustment()->signal_value_changed().connect([this, chatScrollWindow]() + { + auto adj = chatScrollWindow->get_vadjustment(); + if(chatInput.get_buffer()->get_line_count() <= 11) + { + chatScrollWindow->set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_NEVER); + adj->set_value(0); + } + else + { + chatScrollWindow->set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_ALWAYS); + } + }); chatScrollWindow->add(chatInput); } @@ -143,7 +188,7 @@ namespace dchat message->set_valign(Gtk::Align::ALIGN_START); message->set_hexpand(true); message->show_all(); - chatAreaLayout.attach(*message, 0, it->second.messageCount, 1, 1); + messageAreaLayout.attach(*message, 0, it->second.messageCount, 1, 1); ++it->second.messageCount; } diff --git a/src/GlobalCache.cpp b/src/GlobalCache.cpp new file mode 100644 index 0000000..e627a33 --- /dev/null +++ b/src/GlobalCache.cpp @@ -0,0 +1,18 @@ +#include "../include/GlobalCache.hpp" +#include "../include/GtkGif.hpp" + +namespace dchat +{ + static Cache *cache = nullptr; + Cache& getGlobalCache() + { + if(!cache) + { + cache = new Cache([](StringView fileContent) + { + return new GtkGif(fileContent); + }); + } + return *cache; + } +} \ No newline at end of file diff --git a/src/GtkGif.cpp b/src/GtkGif.cpp new file mode 100644 index 0000000..1da48a8 --- /dev/null +++ b/src/GtkGif.cpp @@ -0,0 +1,31 @@ +#include "../include/GtkGif.hpp" + +namespace dchat +{ + GtkGif::GtkGif(StringView fileContent) : + Gif(fileContent) + { + //signal_draw().connect(sigc::mem_fun(*this, &GtkGif::updateContent)); + set_app_paintable(true); + } + + bool GtkGif::createTexture(int width, int height) + { + surface = Cairo::ImageSurface::create(Cairo::Format::FORMAT_ARGB32, width, height); + return true; + } + + void GtkGif::updateTexture(void *textureData) + { + unsigned char *pixels = surface->get_data(); + memcpy(pixels, textureData, surface->get_stride() * surface->get_height()); + } + + bool GtkGif::on_draw(const Cairo::RefPtr &cairo) + { + update(); + cairo->set_source(surface, 0.0, 0.0); + cairo->fill(); + return true; + } +} \ No newline at end of file diff --git a/src/Window.cpp b/src/Window.cpp index b1efc20..6a0ab64 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -1,7 +1,7 @@ #include "../include/Window.hpp" -#include "../include/Cache.hpp" #include "../include/ChannelDataType.hpp" #include "../include/WindowNotification.hpp" +#include #include #include #include @@ -181,6 +181,7 @@ namespace dchat prevTimeMillis = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count() - 5000; drawBackgroundConnection = signal_draw().connect(sigc::mem_fun(*this, &Window::drawBackground)); set_size_request(640, 480); + //set_app_paintable(true); } Window::~Window() @@ -201,6 +202,11 @@ namespace dchat { int windowWidth, windowHeight; get_size(windowWidth, windowHeight); + + //cairo->set_source_rgb(0.1843137254901961, 0.19215686274509805, 0.21176470588235294); + //cairo->rectangle(0.0, 0.0, windowWidth, windowHeight); + //cairo->fill(); + cairo->set_source_rgb(0.5, 0.5, 0.5); int currentTimeMillis = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); -- cgit v1.2.3