aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2018-05-08 18:06:43 +0200
committerdec05eba <dec05eba@protonmail.com>2018-05-08 18:06:51 +0200
commit15c4434de0c2cd12e09c2f41e898c0b124194a97 (patch)
tree0bf01cd49a22b7aa79304ed0e9d34ac265d8393c
parent4f6c843523f45708d8bbed25b3677f69c4208a38 (diff)
Add context menu, add context menu to delete message
-rw-r--r--.gitignore1
m---------depends/odhtdb0
-rw-r--r--include/Channel.hpp9
-rw-r--r--include/ColorScheme.hpp4
-rw-r--r--include/ContextMenu.hpp45
-rw-r--r--include/GlobalContextMenu.hpp19
-rw-r--r--include/Message.hpp7
-rw-r--r--include/MessageBoard.hpp15
-rw-r--r--include/Text.hpp3
-rw-r--r--src/Channel.cpp42
-rw-r--r--src/ColorScheme.cpp7
-rw-r--r--src/ContextMenu.cpp128
-rw-r--r--src/GlobalContextMenu.cpp42
-rw-r--r--src/Message.cpp3
-rw-r--r--src/MessageBoard.cpp98
-rw-r--r--src/Text.cpp10
-rw-r--r--src/main.cpp21
17 files changed, 383 insertions, 71 deletions
diff --git a/.gitignore b/.gitignore
index 9288f91..eb4564f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
sibs-build/
dchat.kdev4/
+.gdb_history
diff --git a/depends/odhtdb b/depends/odhtdb
-Subproject f3b18e0309ca2dbb997908583f1d44d13d9fc83
+Subproject e3b6538c17884b5985a78e3d7c507d02b7af2e7
diff --git a/include/Channel.hpp b/include/Channel.hpp
index 1acfcd1..7d4cb08 100644
--- a/include/Channel.hpp
+++ b/include/Channel.hpp
@@ -9,6 +9,7 @@
#include <odhtdb/DatabaseNode.hpp>
#include <odhtdb/Signature.hpp>
#include <odhtdb/Group.hpp>
+#include <odhtdb/Hash.hpp>
namespace odhtdb
{
@@ -19,7 +20,9 @@ namespace dchat
{
enum class ChannelDataType : u8
{
- MESSAGE,
+ ADD_MESSAGE,
+ EDIT_MESSAGE,
+ DELETE_MESSAGE,
NICKNAME_CHANGE
};
@@ -42,7 +45,11 @@ namespace dchat
// If timestamp is 0, then current time is used
void addLocalMessage(const std::string &msg, User *owner, u64 timestampSeconds = 0);
+ void addLocalMessage(const std::string &msg, User *owner, u64 timestampSeconds, const odhtdb::Hash &id);
void addMessage(const std::string &msg);
+ void deleteLocalMessage(const odhtdb::Hash &id);
+ void deleteMessage(const odhtdb::Hash &id);
+
void addUserLocally(User *user);
bool addUser(const odhtdb::Signature::PublicKey &userId, const std::string &groupId);
void replaceLocalUser(User *newLocalUser);
diff --git a/include/ColorScheme.hpp b/include/ColorScheme.hpp
index 64dbeec..93aa640 100644
--- a/include/ColorScheme.hpp
+++ b/include/ColorScheme.hpp
@@ -19,5 +19,9 @@ namespace dchat
static sf::Color getBackgroundColor();
static sf::Color getPanelColor();
static sf::Color getTextRegularColor();
+
+ static sf::Color getContextMenuBackgroundColor();
+ static sf::Color getContextMenuTextColor();
+ static sf::Color getContextMenuSelectedItemBackgroundColor();
};
}
diff --git a/include/ContextMenu.hpp b/include/ContextMenu.hpp
new file mode 100644
index 0000000..1e08d7d
--- /dev/null
+++ b/include/ContextMenu.hpp
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "types.hpp"
+#include <string>
+#include <vector>
+#include <SFML/Window/Event.hpp>
+#include <SFML/Graphics/Text.hpp>
+#include <SFML/Graphics/RenderWindow.hpp>
+#include <functional>
+
+namespace dchat
+{
+ class ContextMenuItem;
+ using MenuItemClickCallbackFunc = std::function<void(ContextMenuItem *menuItem)>;
+
+ class ContextMenuItem
+ {
+ public:
+ ContextMenuItem(const std::string &text, MenuItemClickCallbackFunc clickCallbackFunc);
+
+ sf::Text text;
+ MenuItemClickCallbackFunc clickCallbackFunc;
+ };
+
+ class ContextMenu
+ {
+ public:
+ ContextMenu();
+
+ void addItem(const ContextMenuItem &item);
+ void setPosition(const sf::Vector2f &position);
+ void setVisible(bool visible);
+
+ ContextMenuItem& getItemByIndex(usize index);
+
+ void processEvent(const sf::Event &event);
+ void draw(sf::RenderWindow &window);
+ private:
+ std::vector<ContextMenuItem> menuItems;
+ sf::Vector2f position;
+ int focusedItem;
+ int pressedItem;
+ bool visible;
+ };
+}
diff --git a/include/GlobalContextMenu.hpp b/include/GlobalContextMenu.hpp
new file mode 100644
index 0000000..ab45e50
--- /dev/null
+++ b/include/GlobalContextMenu.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "ContextMenu.hpp"
+#include <SFML/Window/Event.hpp>
+#include <SFML/Graphics/RenderWindow.hpp>
+
+namespace dchat
+{
+ class GlobalContextMenu
+ {
+ public:
+ static ContextMenu* getEditMessageContextMenu();
+ static void setClickEditMessageCallbackFunc(MenuItemClickCallbackFunc callbackFunc);
+ static void setClickDeleteMessageCallbackFunc(MenuItemClickCallbackFunc callbackFunc);
+
+ static void processEvent(const sf::Event &event);
+ static void draw(sf::RenderWindow &window);
+ };
+}
diff --git a/include/Message.hpp b/include/Message.hpp
index 2e52603..8c7f57a 100644
--- a/include/Message.hpp
+++ b/include/Message.hpp
@@ -10,11 +10,18 @@ namespace dchat
class Message
{
public:
+ enum class Type
+ {
+ REGULAR,
+ EDITED
+ };
+
// If timestamp is 0, then timestamp is not used
Message(User *user, const std::string &text, u64 timestampSeconds = 0);
const User *user;
Text text;
const u64 timestampSeconds;
+ Type type;
};
}
diff --git a/include/MessageBoard.hpp b/include/MessageBoard.hpp
index a4dc5a6..a6867d2 100644
--- a/include/MessageBoard.hpp
+++ b/include/MessageBoard.hpp
@@ -6,7 +6,9 @@
#include <SFML/Graphics/RenderTexture.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Event.hpp>
+#include <odhtdb/Hash.hpp>
#include <stdexcept>
+#include <mutex>
namespace dchat
{
@@ -16,25 +18,23 @@ namespace dchat
{
friend class Channel;
public:
- MessageBoard(const sf::Vector2u &size);
+ MessageBoard(Channel *channel);
~MessageBoard();
void processEvent(const sf::Event &event);
void draw(sf::RenderWindow &window, Cache &cache);
private:
void updateStaticContentTexture(const sf::Vector2u &newSize);
- void addMessage(Message *message);
+ void addMessage(Message *message, const odhtdb::Hash &id);
+ void deleteMessage(const odhtdb::Hash &id);
void drawDefault(sf::RenderWindow &window, Cache &cache);
void drawSimple(sf::RenderWindow &window, Cache &cache);
private:
- sf::RenderTexture staticContentTexture;
+ Channel *channel;
bool dirty;
- bool selectingText;
- bool leftMouseButtonPressed;
- sf::Vector2f mousePos;
- sf::Vector2f selectingTextStart;
std::vector<Message*> messages;
+ odhtdb::MapHash<Message*> messageIdMap;
double scroll;
double scrollSpeed;
sf::Clock frameTimer;
@@ -43,5 +43,6 @@ namespace dchat
sf::Vector2f backgroundSizeWithoutPadding;
sf::Vector2f backgroundSize;
sf::Vector2f backgroundPos;
+ std::mutex messageProcessMutex;
};
}
diff --git a/include/Text.hpp b/include/Text.hpp
index d2809de..d7d1e06 100644
--- a/include/Text.hpp
+++ b/include/Text.hpp
@@ -40,7 +40,10 @@ namespace dchat
void setPosition(float x, float y);
void setPosition(const sf::Vector2f &position);
+ sf::Vector2f getPosition() const;
+
void setMaxWidth(float maxWidth);
+ float getMaxWidth() const;
void setCharacterSize(unsigned int characterSize);
unsigned int getCharacterSize() const;
diff --git a/src/Channel.cpp b/src/Channel.cpp
index e433aee..678dddd 100644
--- a/src/Channel.cpp
+++ b/src/Channel.cpp
@@ -15,15 +15,15 @@ namespace dchat
database(_database),
databaseNodeInfo(_databaseNodeInfo),
name(_name),
- messageBoard(sf::Vector2u(1.0f, 1.0f)),
+ messageBoard(this),
localUser(_localUser ? _localUser : new OfflineUser("You"))
{
addUserLocally(localUser);
localUser->avatarUrl = "https://discordemoji.com/assets/emoji/HanekawaSmug.gif";
- addLocalMessage(u8"[emoji](https://discordemoji.com/assets/emoji/PepeDab.gif) deaf [emoji](https://discordemoji.com/assets/emoji/COGGERS.gif)", &systemUser);
- addLocalMessage(u8"[emoji](https://discordemoji.com/assets/emoji/PepeDab.gif)[emoji](https://discordemoji.com/assets/emoji/COGGERS.gif)", &systemUser);
- addLocalMessage(u8"pepedab https://discordemoji.com/assets/emoji/PepeDab.gif coggers https://discordemoji.com/assets/emoji/COGGERS.gif check out this url http://www.grandtournation.com/6808/start-date-of-the-grand-tour-season-3-confirmed-mark-your-calendars/ owo", &systemUser);
+ addLocalMessage(u8"[emoji](https://discordemoji.com/assets/emoji/PepeDab.gif) deaf [emoji](https://discordemoji.com/assets/emoji/COGGERS.gif)", &systemUser, 0, odhtdb::Hash());
+ addLocalMessage(u8"[emoji](https://discordemoji.com/assets/emoji/PepeDab.gif)[emoji](https://discordemoji.com/assets/emoji/COGGERS.gif)", &systemUser, 0, odhtdb::Hash());
+ addLocalMessage(u8"pepedab https://discordemoji.com/assets/emoji/PepeDab.gif coggers https://discordemoji.com/assets/emoji/COGGERS.gif check out this url http://www.grandtournation.com/6808/start-date-of-the-grand-tour-season-3-confirmed-mark-your-calendars/ owo", &systemUser, 0, odhtdb::Hash());
if(database)
database->seed(databaseNodeInfo);
@@ -80,12 +80,17 @@ namespace dchat
void Channel::addLocalMessage(const std::string &msg, User *owner, u64 timestampSeconds)
{
+ addLocalMessage(msg, owner, timestampSeconds, odhtdb::Hash());
+ }
+
+ void Channel::addLocalMessage(const std::string &msg, User *owner, u64 timestampSeconds, const odhtdb::Hash &id)
+ {
assert(owner);
if(timestampSeconds == 0)
{
timestampSeconds = time(NULL);
}
- messageBoard.addMessage(new Message(owner, msg, timestampSeconds));
+ messageBoard.addMessage(new Message(owner, msg, timestampSeconds), id);
}
void Channel::addMessage(const std::string &msg)
@@ -96,14 +101,37 @@ namespace dchat
assert(localOnlineUser->databaseUser->getType() == odhtdb::User::Type::LOCAL);
sibs::SafeSerializer serializer;
- serializer.add(ChannelDataType::MESSAGE);
+ serializer.add(ChannelDataType::ADD_MESSAGE);
serializer.add((const u8*)msg.data(), msg.size());
database->addData(databaseNodeInfo, static_cast<const odhtdb::LocalUser*>(localOnlineUser->databaseUser), odhtdb::DataView(serializer.getBuffer().data(), serializer.getBuffer().size()));
database->commit();
}
else
- addLocalMessage(msg, localUser, 0);
+ addLocalMessage(msg, localUser, 0, odhtdb::Hash());
+ }
+
+ void Channel::deleteLocalMessage(const odhtdb::Hash &id)
+ {
+ messageBoard.deleteMessage(id);
+ }
+
+ void Channel::deleteMessage(const odhtdb::Hash &id)
+ {
+ if(database && localUser->type == User::Type::ONLINE)
+ {
+ auto localOnlineUser = static_cast<OnlineUser*>(localUser);
+ assert(localOnlineUser->databaseUser->getType() == odhtdb::User::Type::LOCAL);
+
+ sibs::SafeSerializer serializer;
+ serializer.add(ChannelDataType::DELETE_MESSAGE);
+ serializer.add((const u8*)id.getData(), odhtdb::HASH_BYTE_SIZE);
+
+ database->addData(databaseNodeInfo, static_cast<const odhtdb::LocalUser*>(localOnlineUser->databaseUser), odhtdb::DataView(serializer.getBuffer().data(), serializer.getBuffer().size()));
+ database->commit();
+ }
+ else
+ deleteLocalMessage(id);
}
void Channel::addUserLocally(User *user)
diff --git a/src/ColorScheme.cpp b/src/ColorScheme.cpp
index 09dde51..4790e80 100644
--- a/src/ColorScheme.cpp
+++ b/src/ColorScheme.cpp
@@ -14,7 +14,10 @@ namespace dchat
colorSchemeType = type;
}
- sf::Color ColorScheme::getBackgroundColor(){ return sf::Color(54,57,62); }
- sf::Color ColorScheme::getPanelColor() { return sf::Color(47,49,54); }
+ sf::Color ColorScheme::getBackgroundColor(){ return sf::Color(54, 57, 62); }
+ sf::Color ColorScheme::getPanelColor() { return sf::Color(47, 49, 54); }
sf::Color ColorScheme::getTextRegularColor() { return sf::Color(255, 255, 255); }
+ sf::Color ColorScheme::getContextMenuBackgroundColor() { return sf::Color(47, 49, 54); }
+ sf::Color ColorScheme::getContextMenuTextColor() { return sf::Color(255, 255, 255); }
+ sf::Color ColorScheme::getContextMenuSelectedItemBackgroundColor() { return sf::Color(37, 39, 44); }
}
diff --git a/src/ContextMenu.cpp b/src/ContextMenu.cpp
new file mode 100644
index 0000000..317d34a
--- /dev/null
+++ b/src/ContextMenu.cpp
@@ -0,0 +1,128 @@
+#include "../include/ContextMenu.hpp"
+#include "../include/ColorScheme.hpp"
+#include "../include/ResourceCache.hpp"
+#include "../include/Settings.hpp"
+#include <SFML/Graphics/Text.hpp>
+#include <SFML/Graphics/RectangleShape.hpp>
+#include <cmath>
+#include <cassert>
+
+namespace dchat
+{
+ const float PADDING_SIDE = 10.0f;
+ const float MENU_ITEM_FONT_SIZE = 18.0f;
+ const std::string MENU_FONT_PATH = "fonts/Roboto-Regular.ttf";
+
+ ContextMenuItem::ContextMenuItem(const std::string & _text, MenuItemClickCallbackFunc _clickCallbackFunc) :
+ text(sf::String::fromUtf8(_text.begin(), _text.end()), *ResourceCache::getFont(MENU_FONT_PATH), MENU_ITEM_FONT_SIZE * Settings::getScaling()),
+ clickCallbackFunc(_clickCallbackFunc)
+ {
+ text.setFillColor(ColorScheme::getContextMenuTextColor());
+ }
+
+ ContextMenu::ContextMenu() :
+ focusedItem(-1),
+ pressedItem(-1),
+ visible(true)
+ {
+
+ }
+
+ void ContextMenu::addItem(const ContextMenuItem &item)
+ {
+ menuItems.push_back(item);
+ }
+
+ void ContextMenu::setPosition(const sf::Vector2f &position)
+ {
+ this->position = position;
+ }
+
+ void ContextMenu::setVisible(bool visible)
+ {
+ this->visible = visible;
+ }
+
+ ContextMenuItem& ContextMenu::getItemByIndex(usize index)
+ {
+ assert(index < menuItems.size());
+ return menuItems[index];
+ }
+
+ void ContextMenu::processEvent(const sf::Event &event)
+ {
+ if(!visible) return;
+
+ if(event.type == sf::Event::MouseButtonPressed)
+ {
+ if(event.mouseButton.button == sf::Mouse::Button::Left)
+ {
+ pressedItem = focusedItem;
+ if(pressedItem == -1)
+ setVisible(false);
+ }
+ else
+ {
+ focusedItem = -1;
+ pressedItem = -1;
+ setVisible(false);
+ }
+ }
+ else if(event.type == sf::Event::MouseButtonReleased)
+ {
+ if(pressedItem != -1 && pressedItem == focusedItem)
+ {
+ assert(pressedItem < menuItems.size());
+ if(menuItems[pressedItem].clickCallbackFunc)
+ menuItems[pressedItem].clickCallbackFunc(&menuItems[pressedItem]);
+ setVisible(false);
+ }
+ pressedItem = -1;
+ }
+ }
+
+ void ContextMenu::draw(sf::RenderWindow &window)
+ {
+ if(!visible) return;
+
+ const sf::Font *menuItemFont = ResourceCache::getFont(MENU_FONT_PATH);
+ float boxHeight = menuItemFont->getLineSpacing(MENU_ITEM_FONT_SIZE) * 1.5f;
+
+ sf::Vector2f menuSize;
+ for(ContextMenuItem &menuItem : menuItems)
+ {
+ menuItem.text.setCharacterSize(18 * Settings::getScaling());
+ menuSize.x = std::max(menuSize.x, menuItem.text.getLocalBounds().width);
+ menuSize.y += boxHeight;
+ }
+ menuSize.x += PADDING_SIDE * 2.0f;
+ menuSize.x = floor(menuSize.x);
+ menuSize.y = floor(menuSize.y);
+
+ sf::Vector2f pos(floor(position.x), floor(position.y));
+ sf::RectangleShape background(menuSize);
+ background.setPosition(pos);
+ background.setFillColor(ColorScheme::getContextMenuBackgroundColor());
+ window.draw(background);
+
+ auto mousePos = sf::Mouse::getPosition(window);
+
+ focusedItem = -1;
+ for(int i = 0; i < menuItems.size(); ++i)
+ {
+ ContextMenuItem &menuItem = menuItems[i];
+ if(mousePos.x >= pos.x && mousePos.x <= pos.x + menuSize.x && mousePos.y >= pos.y && mousePos.y <= pos.y + boxHeight && (pressedItem == -1 || i == pressedItem))
+ {
+ sf::RectangleShape selectedItemRect(sf::Vector2f(menuSize.x, floor(boxHeight)));
+ selectedItemRect.setFillColor(ColorScheme::getContextMenuSelectedItemBackgroundColor());
+ selectedItemRect.setPosition(floor(pos.x), floor(pos.y));
+ window.draw(selectedItemRect);
+ focusedItem = i;
+ }
+
+ menuItem.text.setPosition(floor(pos.x + PADDING_SIDE), floor(pos.y + boxHeight * 0.5f - menuItemFont->getLineSpacing(MENU_ITEM_FONT_SIZE) * 0.5f));
+ window.draw(menuItem.text);
+ pos.y += boxHeight;
+ }
+ }
+}
diff --git a/src/GlobalContextMenu.cpp b/src/GlobalContextMenu.cpp
new file mode 100644
index 0000000..9eddb7f
--- /dev/null
+++ b/src/GlobalContextMenu.cpp
@@ -0,0 +1,42 @@
+#include "../include/GlobalContextMenu.hpp"
+
+namespace dchat
+{
+ static ContextMenu *editMessageContextMenu = nullptr;
+
+ ContextMenu* GlobalContextMenu::getEditMessageContextMenu()
+ {
+ if(!editMessageContextMenu)
+ {
+ editMessageContextMenu = new ContextMenu();
+ editMessageContextMenu->setVisible(false);
+
+ ContextMenuItem editMessageItem("Edit message", nullptr);
+ ContextMenuItem deleteMessageItem("Delete message", nullptr);
+ deleteMessageItem.text.setFillColor(sf::Color::Red);
+ editMessageContextMenu->addItem(editMessageItem);
+ editMessageContextMenu->addItem(deleteMessageItem);
+ }
+ return editMessageContextMenu;
+ }
+
+ void GlobalContextMenu::setClickEditMessageCallbackFunc(MenuItemClickCallbackFunc callbackFunc)
+ {
+ getEditMessageContextMenu()->getItemByIndex(0).clickCallbackFunc = callbackFunc;
+ }
+
+ void GlobalContextMenu::setClickDeleteMessageCallbackFunc(MenuItemClickCallbackFunc callbackFunc)
+ {
+ getEditMessageContextMenu()->getItemByIndex(1).clickCallbackFunc = callbackFunc;
+ }
+
+ void GlobalContextMenu::processEvent(const sf::Event &event)
+ {
+ getEditMessageContextMenu()->processEvent(event);
+ }
+
+ void GlobalContextMenu::draw(sf::RenderWindow &window)
+ {
+ getEditMessageContextMenu()->draw(window);
+ }
+}
diff --git a/src/Message.cpp b/src/Message.cpp
index 77e3cfa..a408aee 100644
--- a/src/Message.cpp
+++ b/src/Message.cpp
@@ -10,7 +10,8 @@ namespace dchat
Message::Message(User *_user, const std::string &_text, u64 _timestampSeconds) :
user(_user),
text(sf::String::fromUtf8(_text.begin(), _text.end()), ResourceCache::getFont("fonts/Roboto-Regular.ttf"), 18 * Settings::getScaling(), 0.0f, false),
- timestampSeconds(_timestampSeconds)
+ timestampSeconds(_timestampSeconds),
+ type(Type::REGULAR)
{
text.setFillColor(ColorScheme::getTextRegularColor());
}
diff --git a/src/MessageBoard.cpp b/src/MessageBoard.cpp
index 49d84e8..bdaccf3 100644
--- a/src/MessageBoard.cpp
+++ b/src/MessageBoard.cpp
@@ -8,6 +8,8 @@
#include "../include/Chatbar.hpp"
#include "../include/ColorScheme.hpp"
#include "../include/Theme.hpp"
+#include "../include/GlobalContextMenu.hpp"
+#include "../include/Channel.hpp"
#include <SFML/Graphics/CircleShape.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/Sprite.hpp>
@@ -39,15 +41,14 @@ namespace dchat
// Merge messages from same user that are sent within one minute
const int MERGE_TEXT_TIMESTAMP_DIFF_SEC = 60;
- MessageBoard::MessageBoard(const sf::Vector2u &size) :
- selectingText(false),
- leftMouseButtonPressed(false),
+ MessageBoard::MessageBoard(Channel *_channel) :
+ channel(_channel),
scroll(0.0),
scrollSpeed(0.0),
totalHeight(0.0),
scrollToBottom(false)
{
- updateStaticContentTexture(size);
+
}
MessageBoard::~MessageBoard()
@@ -65,13 +66,35 @@ namespace dchat
dirty = true;
}
- void MessageBoard::addMessage(Message *message)
+ void MessageBoard::addMessage(Message *message, const odhtdb::Hash &id)
{
+ lock_guard<mutex> lock(messageProcessMutex);
messages.push_back(message);
+ if(!id.isEmpty())
+ messageIdMap[id] = message;
dirty = true;
scrollToBottom = true;
}
+ void MessageBoard::deleteMessage(const odhtdb::Hash &id)
+ {
+ lock_guard<mutex> lock(messageProcessMutex);
+ auto it = messageIdMap.find(id);
+ if(it == messageIdMap.end()) return;
+
+ for(usize i = 0; i < messages.size(); ++i)
+ {
+ Message *message = messages[i];
+ if(message == it->second)
+ {
+ delete message;
+ messages.erase(messages.begin() + i);
+ messageIdMap.erase(it);
+ break;
+ }
+ }
+ }
+
void MessageBoard::drawDefault(sf::RenderWindow &window, Cache &cache)
{
const float LINE_SPACING = 5.0f * Settings::getScaling();
@@ -253,32 +276,32 @@ namespace dchat
void MessageBoard::processEvent(const sf::Event &event)
{
- if(event.type == sf::Event::MouseButtonPressed)
+ lock_guard<mutex> lock(messageProcessMutex);
+ for(Message *message : messages)
{
- if(event.mouseButton.button == sf::Mouse::Button::Left)
- {
- leftMouseButtonPressed = true;
- mousePos.x = event.mouseButton.x;
- mousePos.y = event.mouseButton.y;
- }
+ message->text.processEvent(event);
}
- else if(event.type == sf::Event::MouseButtonReleased)
+
+ if(event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Button::Right)
{
- if(event.mouseButton.button == sf::Mouse::Button::Left)
+ for(auto it : messageIdMap)
{
- leftMouseButtonPressed = false;
- mousePos.x = event.mouseButton.x;
- mousePos.y = event.mouseButton.y;
+ it.second->text.processEvent(event);
+ auto textPos = it.second->text.getPosition();
+ if(event.mouseButton.x >= textPos.x && event.mouseButton.x <= textPos.x + it.second->text.getMaxWidth() && event.mouseButton.y >= textPos.y && event.mouseButton.y <= textPos.y + it.second->text.getHeight())
+ {
+ auto contextMenu = GlobalContextMenu::getEditMessageContextMenu();
+ contextMenu->setPosition(sf::Vector2f(event.mouseButton.x, event.mouseButton.y));
+ contextMenu->setVisible(true);
+ GlobalContextMenu::setClickDeleteMessageCallbackFunc([this, it](ContextMenuItem *menuItem)
+ {
+ channel->deleteMessage(it.first);
+ GlobalContextMenu::setClickDeleteMessageCallbackFunc(nullptr);
+ });
+ return;
+ }
}
- }
- else if(event.type == sf::Event::LostFocus)
- {
- leftMouseButtonPressed = false;
- }
- else if(event.type == sf::Event::MouseMoved)
- {
- mousePos.x = event.mouseMove.x;
- mousePos.y = event.mouseMove.y;
+ GlobalContextMenu::setClickDeleteMessageCallbackFunc(nullptr);
}
else if(event.type == sf::Event::MouseWheelScrolled && event.mouseWheelScroll.wheel == sf::Mouse::Wheel::VerticalWheel)
{
@@ -288,22 +311,6 @@ namespace dchat
else if(scrollSpeed < -SCROLL_MAX_SPEED)
scrollSpeed = -SCROLL_MAX_SPEED;
}
-
- if(selectingText && !leftMouseButtonPressed)
- {
- selectingText = false;
- }
- else if(!selectingText && leftMouseButtonPressed)
- {
- selectingText = true;
- selectingTextStart.x = mousePos.x;
- selectingTextStart.y = mousePos.y;
- }
-
- for(Message *message : messages)
- {
- message->text.processEvent(event);
- }
}
void MessageBoard::draw(sf::RenderWindow &window, Cache &cache)
@@ -331,6 +338,7 @@ namespace dchat
if(dirty)
{
+ lock_guard<mutex> lock(messageProcessMutex);
switch(Theme::getType())
{
case Theme::Type::DEFAULT:
@@ -385,11 +393,5 @@ namespace dchat
//sf::Sprite textureSprite(staticContentTexture.getTexture());
//textureSprite.setPosition(backgroundPos);
//window.draw(textureSprite);
-
- if(!selectingText) return;
-
- sf::Vector2f selectionRectStart(min((float)mousePos.x, selectingTextStart.x), min((float)mousePos.y, selectingTextStart.y));
- sf::Vector2f selectionRectEnd(max((float)mousePos.x, selectingTextStart.x), max((float)mousePos.y, selectingTextStart.y));
- sf::FloatRect selectionRect(selectionRectStart, selectionRectEnd - selectionRectStart);
}
}
diff --git a/src/Text.cpp b/src/Text.cpp
index 252d27f..5191ca5 100644
--- a/src/Text.cpp
+++ b/src/Text.cpp
@@ -84,6 +84,11 @@ namespace dchat
this->position = position;
}
+ sf::Vector2f Text::getPosition() const
+ {
+ return position;
+ }
+
void Text::setMaxWidth(float maxWidth)
{
if(maxWidth != this->maxWidth)
@@ -93,6 +98,11 @@ namespace dchat
}
}
+ float Text::getMaxWidth() const
+ {
+ return maxWidth;
+ }
+
void Text::setCharacterSize(unsigned int characterSize)
{
if(characterSize != this->characterSize)
diff --git a/src/main.cpp b/src/main.cpp
index b1f63e9..83ef11a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -8,6 +8,7 @@
#include "../include/Command.hpp"
#include "../include/Settings.hpp"
#include "../include/ColorScheme.hpp"
+#include "../include/GlobalContextMenu.hpp"
#include <string>
#include <SFML/Graphics.hpp>
#include <cstring>
@@ -75,7 +76,7 @@ void channelChangeUserNickname(Channel *channel, const StringView data, const od
// We dont care if there is more data to read (malicious packet), we already got all the data we need
}
-void channelAddStoredMessage(Channel *channel, const odhtdb::Signature::PublicKey &creatorPublicKey, const StringView decryptedObject, u64 timestamp)
+void channelAddStoredMessage(Channel *channel, const odhtdb::Hash &requestHash, const odhtdb::Signature::PublicKey &creatorPublicKey, const StringView decryptedObject, u64 timestamp)
{
User *user = channel->getUserByPublicKey(creatorPublicKey);
if(!user)
@@ -90,10 +91,18 @@ void channelAddStoredMessage(Channel *channel, const odhtdb::Signature::PublicKe
StringView decryptedData((const char*)decryptedObject.data + 1, decryptedObject.size - 1);
switch(channelDataType)
{
- case ChannelDataType::MESSAGE:
+ case ChannelDataType::ADD_MESSAGE:
{
string msg(decryptedData.data, decryptedData.size);
- channel->addLocalMessage(msg, user, ntp::NtpTimestamp::fromCombined(timestamp).seconds);
+ channel->addLocalMessage(msg, user, ntp::NtpTimestamp::fromCombined(timestamp).seconds, requestHash);
+ break;
+ }
+ case ChannelDataType::DELETE_MESSAGE:
+ {
+ sibs::SafeDeserializer deserializer((const u8*)decryptedData.data, decryptedData.size);
+ odhtdb::Hash messageId;
+ deserializer.extract((u8*)messageId.getData(), odhtdb::HASH_BYTE_SIZE);
+ channel->deleteLocalMessage(messageId);
break;
}
case ChannelDataType::NICKNAME_CHANGE:
@@ -127,7 +136,7 @@ void channelAddStoredMessages(Channel *channel, const odhtdb::DatabaseStorageObj
if(nodeStorageAddedObject->decryptedObject.operation == odhtdb::DatabaseOperation::ADD_DATA)
{
StringView decryptedObject((const char*)nodeStorageAddedObject->decryptedObject.data.data, nodeStorageAddedObject->decryptedObject.data.size);
- channelAddStoredMessage(channel, nodeStorageAddedObject->creatorPublicKey, decryptedObject, nodeStorageAddedObject->createdTimestamp);
+ channelAddStoredMessage(channel, nodeStorageAddedObject->requestHash, nodeStorageAddedObject->creatorPublicKey, decryptedObject, nodeStorageAddedObject->createdTimestamp);
}
}
}
@@ -200,7 +209,7 @@ int main(int argc, char **argv)
{
if(*request.nodeHash == *channel->getNodeInfo().getRequestHash())
{
- channelAddStoredMessage(channel, request.creatorUser->getPublicKey(), StringView((const char*)request.decryptedData.data, request.decryptedData.size), request.timestamp);
+ channelAddStoredMessage(channel, *request.requestHash, request.creatorUser->getPublicKey(), StringView((const char*)request.decryptedData.data, request.decryptedData.size), request.timestamp);
return;
}
}
@@ -642,6 +651,7 @@ int main(int argc, char **argv)
window.setFramerateLimit(FRAMERATE_FOCUSED);
//else if(event.type == sf::Event::LostFocus)
// window.setFramerateLimit(FRAMERATE_NOT_FOCUSED);
+ GlobalContextMenu::processEvent(event);
currentChannel->processEvent(event);
}
@@ -650,6 +660,7 @@ int main(int argc, char **argv)
currentChannel->draw(window, cache);
UsersSidePanel::draw(window);
ChannelTopPanel::draw(window);
+ GlobalContextMenu::draw(window);
if(waitingToJoin)
{