Compare commits
3 Commits
a848a01527
...
4cd295065b
Author | SHA1 | Date | |
---|---|---|---|
4cd295065b | |||
5a9aacc603 | |||
082c4febdf |
@ -12,6 +12,16 @@ add_executable(tomato
|
|||||||
|
|
||||||
tox_client.hpp
|
tox_client.hpp
|
||||||
tox_client.cpp
|
tox_client.cpp
|
||||||
|
|
||||||
|
theme.hpp
|
||||||
|
texture_uploader.hpp
|
||||||
|
./sdlrenderer_texture_uploader.hpp
|
||||||
|
./sdlrenderer_texture_uploader.cpp
|
||||||
|
./file_selector.hpp
|
||||||
|
./file_selector.cpp
|
||||||
|
|
||||||
|
./chat_gui4.hpp
|
||||||
|
./chat_gui4.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_features(tomato PUBLIC cxx_std_17)
|
target_compile_features(tomato PUBLIC cxx_std_17)
|
||||||
|
504
src/chat_gui4.cpp
Normal file
504
src/chat_gui4.cpp
Normal file
@ -0,0 +1,504 @@
|
|||||||
|
#include "./chat_gui4.hpp"
|
||||||
|
|
||||||
|
#include "./file_selector.hpp"
|
||||||
|
|
||||||
|
#include <solanaceae/message3/components.hpp>
|
||||||
|
#include <solanaceae/tox_messages/components.hpp>
|
||||||
|
#include <solanaceae/contact/components.hpp>
|
||||||
|
|
||||||
|
//#include "./media_meta_info_loader.hpp"
|
||||||
|
|
||||||
|
#include <imgui/imgui.h>
|
||||||
|
#include <imgui/misc/cpp/imgui_stdlib.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
#include <chrono>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
ChatGui4::ChatGui4(
|
||||||
|
RegistryMessageModel& rmm,
|
||||||
|
Contact3Registry& cr,
|
||||||
|
TextureUploaderI& tu
|
||||||
|
) : _rmm(rmm), _cr(cr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatGui4::render(void) {
|
||||||
|
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||||
|
ImGui::SetNextWindowPos(viewport->WorkPos);
|
||||||
|
ImGui::SetNextWindowSize(viewport->WorkSize);
|
||||||
|
|
||||||
|
TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
|
||||||
|
TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
|
||||||
|
|
||||||
|
constexpr auto bg_window_flags =
|
||||||
|
ImGuiWindowFlags_NoDecoration |
|
||||||
|
ImGuiWindowFlags_NoMove |
|
||||||
|
ImGuiWindowFlags_NoResize |
|
||||||
|
ImGuiWindowFlags_NoSavedSettings |
|
||||||
|
ImGuiWindowFlags_MenuBar |
|
||||||
|
ImGuiWindowFlags_NoBringToFrontOnFocus;
|
||||||
|
|
||||||
|
if (ImGui::Begin("tomato", nullptr, bg_window_flags)) {
|
||||||
|
if (ImGui::BeginMenuBar()) {
|
||||||
|
//ImGui::Separator();
|
||||||
|
ImGui::Text("%.1fFPS", ImGui::GetIO().Framerate);
|
||||||
|
ImGui::EndMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderContactList();
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (_selected_contact) {
|
||||||
|
const std::string chat_label = "chat " + std::to_string(entt::to_integral(*_selected_contact));
|
||||||
|
if (ImGui::BeginChild(chat_label.c_str(), {0, 0}, true)) {
|
||||||
|
static std::string text_buffer;
|
||||||
|
|
||||||
|
if (_cr.all_of<Contact::Components::ParentOf>(*_selected_contact)) {
|
||||||
|
const auto sub_contacts = _cr.get<Contact::Components::ParentOf>(*_selected_contact).subs;
|
||||||
|
if (!sub_contacts.empty()) {
|
||||||
|
if (ImGui::BeginChild("subcontacts", {150, -100}, true)) {
|
||||||
|
ImGui::Text("subs: %zu", sub_contacts.size());
|
||||||
|
ImGui::Separator();
|
||||||
|
for (const auto& c : sub_contacts) {
|
||||||
|
if (renderSubContactListContact(c)) {
|
||||||
|
text_buffer.insert(0, (_cr.all_of<Contact::Components::Name>(c) ? _cr.get<Contact::Components::Name>(c).name : "<unk>") + ": ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginChild("message_log", {0, -100}, false, ImGuiWindowFlags_MenuBar)) {
|
||||||
|
if (ImGui::BeginMenuBar()) {
|
||||||
|
ImGui::Checkbox("show extra info", &_show_chat_extra_info);
|
||||||
|
ImGui::EndMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* msg_reg_ptr = _rmm.get(*_selected_contact);
|
||||||
|
|
||||||
|
constexpr ImGuiTableFlags table_flags =
|
||||||
|
ImGuiTableFlags_BordersInnerV |
|
||||||
|
ImGuiTableFlags_RowBg |
|
||||||
|
ImGuiTableFlags_SizingFixedFit
|
||||||
|
;
|
||||||
|
if (msg_reg_ptr != nullptr && ImGui::BeginTable("chat_table", 4, table_flags)) {
|
||||||
|
ImGui::TableSetupColumn("name", 0, TEXT_BASE_WIDTH * 15.f);
|
||||||
|
ImGui::TableSetupColumn("message", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
ImGui::TableSetupColumn("timestamp");
|
||||||
|
ImGui::TableSetupColumn("extra_info", _show_chat_extra_info ? ImGuiTableColumnFlags_None : ImGuiTableColumnFlags_Disabled);
|
||||||
|
|
||||||
|
// very hacky, and we have variable hight entries
|
||||||
|
//ImGuiListClipper clipper;
|
||||||
|
|
||||||
|
// fake empty placeholders
|
||||||
|
// TODO: save/calc height for each row
|
||||||
|
// - use number of lines for text
|
||||||
|
// - save img dims (capped)
|
||||||
|
// - other static sizes
|
||||||
|
//ImGui::TableNextRow(0, TEXT_BASE_HEIGHT);
|
||||||
|
//ImGui::TableNextRow(0, TEXT_BASE_HEIGHT);
|
||||||
|
|
||||||
|
Message3Registry& msg_reg = *msg_reg_ptr;
|
||||||
|
msg_reg.view<Message::Components::ContactFrom, Message::Components::ContactTo, Message::Components::Timestamp>()
|
||||||
|
.use<Message::Components::Timestamp>()
|
||||||
|
.each([&](const Message3 e, Message::Components::ContactFrom& c_from, Message::Components::ContactTo& c_to, Message::Components::Timestamp ts
|
||||||
|
) {
|
||||||
|
// TODO: why?
|
||||||
|
ImGui::TableNextRow(0, TEXT_BASE_HEIGHT);
|
||||||
|
|
||||||
|
ImGui::PushID(entt::to_integral(e));
|
||||||
|
|
||||||
|
// name
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
if (_cr.all_of<Contact::Components::Name>(c_from.c)) {
|
||||||
|
ImGui::TextUnformatted(_cr.get<Contact::Components::Name>(c_from.c).name.c_str());
|
||||||
|
} else {
|
||||||
|
ImGui::TextUnformatted("<unk>");
|
||||||
|
}
|
||||||
|
|
||||||
|
// highlight self
|
||||||
|
if (_cr.any_of<Contact::Components::TagSelfWeak, Contact::Components::TagSelfStrong>(c_from.c)) {
|
||||||
|
ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.7f, 0.3f, 0.20f));
|
||||||
|
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color);
|
||||||
|
} else {
|
||||||
|
//based on power level?
|
||||||
|
//ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.7f, 0.3f, 0.65f));
|
||||||
|
//ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// private group message
|
||||||
|
if (_cr.any_of<Contact::Components::TagSelfWeak, Contact::Components::TagSelfStrong>(c_to.c)) {
|
||||||
|
ImU32 row_bg_color = ImGui::GetColorU32(ImVec4(0.5f, 0.2f, 0.5f, 0.35f));
|
||||||
|
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, row_bg_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// content (msgtext/file)
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (msg_reg.all_of<Message::Components::MessageText>(e)) {
|
||||||
|
renderMessageBodyText(msg_reg, e);
|
||||||
|
} else if (msg_reg.any_of<Message::Components::Transfer::FileInfo>(e)) { // add more comps?
|
||||||
|
renderMessageBodyFile(msg_reg, e);
|
||||||
|
} else {
|
||||||
|
ImGui::TextUnformatted("---");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ts
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
auto time = std::chrono::system_clock::to_time_t(
|
||||||
|
std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>{std::chrono::milliseconds{ts.ts}}
|
||||||
|
);
|
||||||
|
auto localtime = std::localtime(&time);
|
||||||
|
|
||||||
|
ImGui::Text("%.2d:%.2d", localtime->tm_hour, localtime->tm_min);
|
||||||
|
}
|
||||||
|
|
||||||
|
// extra
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
renderMessageExtra(msg_reg, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopID(); // ent
|
||||||
|
});
|
||||||
|
|
||||||
|
// fake empty placeholders
|
||||||
|
//ImGui::TableNextRow(0, TEXT_BASE_HEIGHT);
|
||||||
|
//ImGui::TableNextRow(0, TEXT_BASE_HEIGHT);
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) {
|
||||||
|
ImGui::SetScrollHereY(1.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
if (ImGui::BeginChild("text_input", {-150, 0})) {
|
||||||
|
static bool evil_enter_looses_focus_hack = false;
|
||||||
|
if (evil_enter_looses_focus_hack) {
|
||||||
|
ImGui::SetKeyboardFocusHere();
|
||||||
|
evil_enter_looses_focus_hack = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ImGuiInputTextFlags input_flags =
|
||||||
|
ImGuiInputTextFlags_EnterReturnsTrue |
|
||||||
|
//ImGuiInputTextFlags_AllowTabInput |
|
||||||
|
ImGuiInputTextFlags_NoHorizontalScroll |
|
||||||
|
ImGuiInputTextFlags_CtrlEnterForNewLine;
|
||||||
|
|
||||||
|
if (ImGui::InputTextMultiline("##text_input", &text_buffer, {-0.001f, -0.001f}, input_flags)) {
|
||||||
|
//_mm.sendMessage(*_selected_contact, MessageType::TEXT, text_buffer);
|
||||||
|
_rmm.sendText(*_selected_contact, text_buffer);
|
||||||
|
text_buffer.clear();
|
||||||
|
evil_enter_looses_focus_hack = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (ImGui::BeginChild("buttons")) {
|
||||||
|
if (ImGui::Button("send\nfile", {-FLT_MIN, 0})) {
|
||||||
|
_fss.requestFile(
|
||||||
|
[](const auto& path) -> bool { return std::filesystem::is_regular_file(path); },
|
||||||
|
[this](const auto& path){
|
||||||
|
_rmm.sendFilePath(*_selected_contact, path.filename().c_str(), path.c_str());
|
||||||
|
},
|
||||||
|
[](){}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
_fss.render();
|
||||||
|
|
||||||
|
//_tc.update();
|
||||||
|
//_tc.workLoadQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// has MessageText
|
||||||
|
void ChatGui4::renderMessageBodyText(Message3Registry& reg, const Message3 e) {
|
||||||
|
const auto& msgtext = reg.get<Message::Components::MessageText>(e).text;
|
||||||
|
|
||||||
|
ImVec2 text_size = ImGui::CalcTextSize(msgtext.c_str(), msgtext.c_str()+msgtext.size());
|
||||||
|
text_size.x = -FLT_MIN; // fill width (suppresses label)
|
||||||
|
text_size.y += ImGui::GetStyle().FramePadding.y; // single pad
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0}); // make align with text height
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, {0.f, 0.f, 0.f, 0.f}); // remove text input box
|
||||||
|
|
||||||
|
ImGui::InputTextMultiline(
|
||||||
|
"",
|
||||||
|
const_cast<char*>(msgtext.c_str()), // ugly const cast
|
||||||
|
msgtext.size() + 1, // needs to include '\0'
|
||||||
|
text_size,
|
||||||
|
ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoHorizontalScroll
|
||||||
|
);
|
||||||
|
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatGui4::renderMessageBodyFile(Message3Registry& reg, const Message3 e) {
|
||||||
|
#if 0
|
||||||
|
if (msg_reg.all_of<Components::TransferState>(e)) {
|
||||||
|
switch (msg_reg.get<Components::TransferState>(e).state) {
|
||||||
|
case Components::TransferState::State::running: ImGui::TextUnformatted("running"); break;
|
||||||
|
case Components::TransferState::State::paused: ImGui::TextUnformatted("paused"); break;
|
||||||
|
case Components::TransferState::State::failed: ImGui::TextUnformatted("failed"); break;
|
||||||
|
case Components::TransferState::State::finished: ImGui::TextUnformatted("finished"); break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// TODO: better way to display state
|
||||||
|
if (reg.all_of<Message::Components::Transfer::TagPaused>(e)) {
|
||||||
|
ImGui::TextUnformatted("paused");
|
||||||
|
} else {
|
||||||
|
// TODO: missing other staes
|
||||||
|
ImGui::TextUnformatted("running");
|
||||||
|
}
|
||||||
|
|
||||||
|
// if in offered state
|
||||||
|
// paused, never started
|
||||||
|
if (
|
||||||
|
reg.all_of<Message::Components::Transfer::TagReceiving>(e) &&
|
||||||
|
reg.all_of<Message::Components::Transfer::TagPaused>(e) &&
|
||||||
|
// TODO: how does restarting a broken/incomplete transfer look like?
|
||||||
|
!reg.all_of<Message::Components::Transfer::FileInfoLocal>(e) &&
|
||||||
|
!reg.all_of<Message::Components::Transfer::ActionAccept>(e)
|
||||||
|
) {
|
||||||
|
if (ImGui::Button("save to")) {
|
||||||
|
_fss.requestFile(
|
||||||
|
[](const auto& path) -> bool { return std::filesystem::is_directory(path); },
|
||||||
|
[this, ®, e](const auto& path) {
|
||||||
|
if (reg.valid(e)) { // still valid
|
||||||
|
reg.emplace<Message::Components::Transfer::ActionAccept>(e, path.string());
|
||||||
|
_rmm.throwEventUpdate(reg, e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[](){}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// down progress
|
||||||
|
if (reg.all_of<Message::Components::Transfer::TagReceiving>(e)) {
|
||||||
|
ImGui::TextUnformatted("down");
|
||||||
|
if (reg.all_of<Message::Components::Transfer::BytesReceived>(e)) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::ProgressBar(
|
||||||
|
float(reg.get<Message::Components::Transfer::BytesReceived>(e).total) / reg.get<Message::Components::Transfer::FileInfo>(e).total_size,
|
||||||
|
{-FLT_MIN, TEXT_BASE_HEIGHT}
|
||||||
|
);
|
||||||
|
// TODO: numbers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (can be both)
|
||||||
|
// up progess
|
||||||
|
if (reg.all_of<Message::Components::Transfer::TagSending>(e)) {
|
||||||
|
ImGui::TextUnformatted(" up");
|
||||||
|
if (reg.all_of<Message::Components::Transfer::BytesSent>(e)) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::ProgressBar(
|
||||||
|
float(reg.get<Message::Components::Transfer::BytesSent>(e).total) / reg.get<Message::Components::Transfer::FileInfo>(e).total_size,
|
||||||
|
{-FLT_MIN, TEXT_BASE_HEIGHT}
|
||||||
|
);
|
||||||
|
// TODO: numbers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto file_list = reg.get<Message::Components::Transfer::FileInfo>(e).file_list;
|
||||||
|
|
||||||
|
// if has local, display save base path?
|
||||||
|
|
||||||
|
for (size_t i = 0; i < file_list.size(); i++) {
|
||||||
|
// TODO: selectable text widget
|
||||||
|
ImGui::Bullet(); ImGui::Text("%s (%lu)", file_list[i].file_name.c_str(), file_list[i].file_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
// TODO: use frame dims
|
||||||
|
if (file_list.size() == 1 && reg.all_of<Message::Components::Transfer::FileInfoLocal, Message::Components::FrameDims>(e)) {
|
||||||
|
auto [id, width, height] = _tc.get(reg.get<Message::Components::Transfer::FileInfoLocal>(e).file_list.front());
|
||||||
|
|
||||||
|
// if cache gives 0s, fall back to frame dims (eg if pic not loaded yet)
|
||||||
|
if (width > 0 || height > 0) {
|
||||||
|
const auto& frame_dims = reg.get<Message::Components::FrameDims>(e);
|
||||||
|
width = frame_dims.width;
|
||||||
|
height = frame_dims.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: config
|
||||||
|
const auto max_inline_height = 10*TEXT_BASE_HEIGHT;
|
||||||
|
if (height > max_inline_height) {
|
||||||
|
const float scale = max_inline_height / height;
|
||||||
|
height = max_inline_height;
|
||||||
|
width *= scale;
|
||||||
|
}
|
||||||
|
ImGui::Image(id, ImVec2{static_cast<float>(width), static_cast<float>(height)});
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatGui4::renderMessageExtra(Message3Registry& reg, const Message3 e) {
|
||||||
|
if (reg.all_of<Message::Components::Transfer::FileKind>(e)) {
|
||||||
|
ImGui::TextDisabled("fk:%lu", reg.get<Message::Components::Transfer::FileKind>(e).kind);
|
||||||
|
}
|
||||||
|
if (reg.all_of<Message::Components::Transfer::ToxTransferFriend>(e)) {
|
||||||
|
ImGui::TextDisabled("ttf:%u", reg.get<Message::Components::Transfer::ToxTransferFriend>(e).transfer_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg.all_of<Message::Components::ToxGroupMessageID>(e)) {
|
||||||
|
ImGui::TextDisabled("msgid:%u", reg.get<Message::Components::ToxGroupMessageID>(e).id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg.all_of<Message::Components::SyncedBy>(e)) {
|
||||||
|
std::string synced_by_text {"syncedBy:"};
|
||||||
|
const auto& synced_by = reg.get<Message::Components::SyncedBy>(e).list;
|
||||||
|
for (const auto& c : synced_by) {
|
||||||
|
if (_cr.all_of<Contact::Components::TagSelfStrong>(c)) {
|
||||||
|
synced_by_text += "\n sself";
|
||||||
|
} else if (_cr.all_of<Contact::Components::TagSelfWeak>(c)) {
|
||||||
|
synced_by_text += "\n wself";
|
||||||
|
} else {
|
||||||
|
synced_by_text += "\n >" + (_cr.all_of<Contact::Components::Name>(c) ? _cr.get<Contact::Components::Name>(c).name : "<unk>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::TextDisabled("%s", synced_by_text.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatGui4::renderContactList(void) {
|
||||||
|
if (ImGui::BeginChild("contacts", {TEXT_BASE_WIDTH*35, 0})) {
|
||||||
|
//for (const auto& c : _cm.getBigContacts()) {
|
||||||
|
for (const auto& c : _cr.view<Contact::Components::TagBig>()) {
|
||||||
|
if (renderContactListContactBig(c)) {
|
||||||
|
_selected_contact = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChatGui4::renderContactListContactBig(const Contact3 c) {
|
||||||
|
// TODO:
|
||||||
|
// - unread message
|
||||||
|
// - avatar img
|
||||||
|
// - connection status
|
||||||
|
// - user status
|
||||||
|
// - status message
|
||||||
|
// - context menu n shit?
|
||||||
|
|
||||||
|
// +------+
|
||||||
|
// | | *Name (Alias?)
|
||||||
|
// |Avatar| Satus Message
|
||||||
|
// | | user status (online/away/busy)-direct/relayed / offline
|
||||||
|
// +------+
|
||||||
|
|
||||||
|
auto label = "###" + std::to_string(entt::to_integral(c));
|
||||||
|
|
||||||
|
ImVec2 orig_curser_pos = ImGui::GetCursorPos();
|
||||||
|
bool selected = ImGui::Selectable(label.c_str(), _selected_contact.has_value() && *_selected_contact == c, 0, {0,3*TEXT_BASE_HEIGHT});
|
||||||
|
ImVec2 post_curser_pos = ImGui::GetCursorPos();
|
||||||
|
|
||||||
|
ImVec2 img_curser {
|
||||||
|
orig_curser_pos.x + ImGui::GetStyle().FramePadding.x,
|
||||||
|
orig_curser_pos.y + ImGui::GetStyle().FramePadding.y
|
||||||
|
};
|
||||||
|
|
||||||
|
float img_y {
|
||||||
|
//(post_curser_pos.y - orig_curser_pos.y) - ImGui::GetStyle().FramePadding.y*2
|
||||||
|
TEXT_BASE_HEIGHT*3 - ImGui::GetStyle().FramePadding.y*2
|
||||||
|
};
|
||||||
|
|
||||||
|
ImGui::SetCursorPos(img_curser);
|
||||||
|
const ImVec4 color_online_direct{0.3, 1, 0, 1};
|
||||||
|
const ImVec4 color_online_cloud{0, 1, 0.8, 1};
|
||||||
|
const ImVec4 color_offline{0.4, 0.4, 0.4, 1};
|
||||||
|
|
||||||
|
ImVec4 color_current = color_offline;
|
||||||
|
if (_cr.all_of<Contact::Components::ConnectionState>(c)) {
|
||||||
|
const auto c_state = _cr.get<Contact::Components::ConnectionState>(c).state;
|
||||||
|
if (c_state == Contact::Components::ConnectionState::State::direct) {
|
||||||
|
color_current = color_online_direct;
|
||||||
|
} else if (c_state == Contact::Components::ConnectionState::State::cloud) {
|
||||||
|
color_current = color_online_cloud;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// avatar
|
||||||
|
#if 0
|
||||||
|
const auto [id, width, height] = _tc.get("test");
|
||||||
|
ImGui::Image(
|
||||||
|
id,
|
||||||
|
ImVec2{img_y, img_y},
|
||||||
|
{0, 0},
|
||||||
|
{1, 1},
|
||||||
|
{1, 1, 1, 1},
|
||||||
|
color_current
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
ImGui::Dummy({img_y, img_y});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
{
|
||||||
|
ImGui::Text("%s", (_cr.all_of<Contact::Components::Name>(c) ? _cr.get<Contact::Components::Name>(c).name.c_str() : "<unk>"));
|
||||||
|
//ImGui::Text("status message...");
|
||||||
|
//ImGui::TextDisabled("hi");
|
||||||
|
//ImGui::RenderTextEllipsis
|
||||||
|
}
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
ImGui::SetCursorPos(post_curser_pos);
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChatGui4::renderContactListContactSmall(const Contact3 c) {
|
||||||
|
std::string label;
|
||||||
|
|
||||||
|
label += (_cr.all_of<Contact::Components::Name>(c) ? _cr.get<Contact::Components::Name>(c).name.c_str() : "<unk>");
|
||||||
|
label += "###";
|
||||||
|
label += std::to_string(entt::to_integral(c));
|
||||||
|
|
||||||
|
return ImGui::Selectable(label.c_str(), _selected_contact.has_value() && *_selected_contact == c);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChatGui4::renderSubContactListContact(const Contact3 c) {
|
||||||
|
std::string label;
|
||||||
|
|
||||||
|
if (_cr.all_of<Contact::Components::ConnectionState>(c)) {
|
||||||
|
const auto c_state = _cr.get<Contact::Components::ConnectionState>(c).state;
|
||||||
|
if (c_state == Contact::Components::ConnectionState::State::direct) {
|
||||||
|
label += "[D] ";
|
||||||
|
} else if (c_state == Contact::Components::ConnectionState::State::cloud) {
|
||||||
|
label += "[C] ";
|
||||||
|
} else {
|
||||||
|
label += "[-] ";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
label += "[?] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
label += (_cr.all_of<Contact::Components::Name>(c) ? _cr.get<Contact::Components::Name>(c).name.c_str() : "<unk>");
|
||||||
|
label += "###";
|
||||||
|
label += std::to_string(entt::to_integral(c));
|
||||||
|
|
||||||
|
return ImGui::Selectable(label.c_str(), _selected_contact.has_value() && *_selected_contact == c);
|
||||||
|
}
|
||||||
|
|
45
src/chat_gui4.hpp
Normal file
45
src/chat_gui4.hpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <solanaceae/message3/registry_message_model.hpp>
|
||||||
|
|
||||||
|
#include "./texture_uploader.hpp"
|
||||||
|
#include "./file_selector.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
class ChatGui4 {
|
||||||
|
RegistryMessageModel& _rmm;
|
||||||
|
Contact3Registry& _cr;
|
||||||
|
|
||||||
|
FileSelector _fss;
|
||||||
|
|
||||||
|
std::optional<Contact3> _selected_contact;
|
||||||
|
|
||||||
|
bool _show_chat_extra_info {true};
|
||||||
|
|
||||||
|
float TEXT_BASE_WIDTH {1};
|
||||||
|
float TEXT_BASE_HEIGHT {1};
|
||||||
|
|
||||||
|
public:
|
||||||
|
ChatGui4(
|
||||||
|
RegistryMessageModel& rmm,
|
||||||
|
Contact3Registry& cr,
|
||||||
|
TextureUploaderI& tu
|
||||||
|
);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void render(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void renderMessageBodyText(Message3Registry& reg, const Message3 e);
|
||||||
|
void renderMessageBodyFile(Message3Registry& reg, const Message3 e);
|
||||||
|
void renderMessageExtra(Message3Registry& reg, const Message3 e);
|
||||||
|
|
||||||
|
void renderContactList(void);
|
||||||
|
bool renderContactListContactBig(const Contact3 c);
|
||||||
|
bool renderContactListContactSmall(const Contact3 c);
|
||||||
|
bool renderSubContactListContact(const Contact3 c);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
235
src/file_selector.cpp
Normal file
235
src/file_selector.cpp
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
#include "./file_selector.hpp"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <imgui/imgui.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void FileSelector::reset(void) {
|
||||||
|
_is_valid = [](auto){ return true; };
|
||||||
|
_on_choose = [](auto){};
|
||||||
|
_on_cancel = [](){};
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSelector::FileSelector(void) {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSelector::requestFile(
|
||||||
|
std::function<bool(const std::filesystem::path& path)>&& is_valid,
|
||||||
|
std::function<void(const std::filesystem::path& path)>&& on_choose,
|
||||||
|
std::function<void(void)>&& on_cancel
|
||||||
|
) {
|
||||||
|
_open_popup = true;
|
||||||
|
|
||||||
|
_is_valid = std::move(is_valid);
|
||||||
|
_on_choose = std::move(on_choose);
|
||||||
|
_on_cancel = std::move(on_cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSelector::render(void) {
|
||||||
|
if (_open_popup) {
|
||||||
|
_open_popup = false;
|
||||||
|
ImGui::OpenPopup("file picker##FileSelector");
|
||||||
|
|
||||||
|
const auto TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
|
||||||
|
const auto TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
|
||||||
|
|
||||||
|
ImGui::SetNextWindowSize({TEXT_BASE_WIDTH*100, TEXT_BASE_HEIGHT*30});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginPopupModal("file picker##FileSelector", nullptr/*, ImGuiWindowFlags_NoDecoration*/)) {
|
||||||
|
const auto TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
|
||||||
|
const auto TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
|
||||||
|
|
||||||
|
std::filesystem::path current_path = _current_file_path;
|
||||||
|
current_path.remove_filename();
|
||||||
|
|
||||||
|
ImGui::Text("path: %s", _current_file_path.c_str());
|
||||||
|
|
||||||
|
// begin table with selectables
|
||||||
|
constexpr ImGuiTableFlags table_flags =
|
||||||
|
ImGuiTableFlags_BordersInnerV |
|
||||||
|
ImGuiTableFlags_RowBg |
|
||||||
|
ImGuiTableFlags_SizingFixedFit |
|
||||||
|
ImGuiTableFlags_ScrollY |
|
||||||
|
ImGuiTableFlags_Sortable
|
||||||
|
;
|
||||||
|
if (ImGui::BeginTable("dir listing", 4, table_flags, {0, -TEXT_BASE_HEIGHT * 2.5f})) {
|
||||||
|
enum class SortID : ImGuiID {
|
||||||
|
name = 1,
|
||||||
|
size,
|
||||||
|
date
|
||||||
|
};
|
||||||
|
ImGui::TableSetupColumn("type", 0, TEXT_BASE_WIDTH);
|
||||||
|
ImGui::TableSetupColumn("name", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultSort, 0.f, static_cast<ImGuiID>(SortID::name));
|
||||||
|
ImGui::TableSetupColumn("size", 0, 0.f, static_cast<ImGuiID>(SortID::size));
|
||||||
|
ImGui::TableSetupColumn("dd.mm.yyyy - hh:mm", 0, 0.f, static_cast<ImGuiID>(SortID::date));
|
||||||
|
|
||||||
|
ImGui::TableSetupScrollFreeze(0, 2);
|
||||||
|
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
|
//ImGui::TableNextRow(0, TEXT_BASE_HEIGHT);
|
||||||
|
|
||||||
|
if (current_path.has_parent_path()) {
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
if (ImGui::Selectable("D##..", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||||
|
_current_file_path = _current_file_path.parent_path();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
ImGui::TextUnformatted("..");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
ImGui::TextDisabled("---");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
ImGui::TextDisabled("---");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size_t tmp_id = 0;
|
||||||
|
// dirs
|
||||||
|
static const ImU32 dir_bg0_color = ImGui::GetColorU32(ImVec4(0.6, 0.6, 0.1, 0.15));
|
||||||
|
static const ImU32 dir_bg1_color = ImGui::GetColorU32(ImVec4(0.7, 0.7, 0.2, 0.15));
|
||||||
|
|
||||||
|
std::vector<std::filesystem::directory_entry> dirs;
|
||||||
|
std::vector<std::filesystem::directory_entry> files;
|
||||||
|
for (auto const& dir_entry : std::filesystem::directory_iterator(current_path)) {
|
||||||
|
if (dir_entry.is_directory()) {
|
||||||
|
dirs.push_back(dir_entry);
|
||||||
|
} else if (dir_entry.is_regular_file()) {
|
||||||
|
files.push_back(dir_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do sorting here
|
||||||
|
// TODO: cache the result (lol)
|
||||||
|
if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs(); sorts_specs != nullptr && sorts_specs->SpecsCount >= 1) {
|
||||||
|
switch (static_cast<SortID>(sorts_specs->Specs->ColumnUserID)) {
|
||||||
|
break; case SortID::name:
|
||||||
|
if (sorts_specs->Specs->SortDirection == ImGuiSortDirection_Descending) {
|
||||||
|
std::sort(dirs.begin(), dirs.end(), [](const auto& a, const auto& b) -> bool {
|
||||||
|
return a.path() < b.path();
|
||||||
|
});
|
||||||
|
std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) -> bool {
|
||||||
|
return a.path().filename() < b.path().filename();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
std::sort(dirs.begin(), dirs.end(), [](const auto& a, const auto& b) -> bool {
|
||||||
|
return a.path() > b.path();
|
||||||
|
});
|
||||||
|
std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) -> bool {
|
||||||
|
return a.path().filename() > b.path().filename();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break; case SortID::size:
|
||||||
|
if (sorts_specs->Specs->SortDirection == ImGuiSortDirection_Descending) {
|
||||||
|
// TODO: sort dirs?
|
||||||
|
std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) -> bool {
|
||||||
|
return a.file_size() < b.file_size();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// TODO: sort dirs?
|
||||||
|
std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) -> bool {
|
||||||
|
return a.file_size() > b.file_size();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break; case SortID::date:
|
||||||
|
if (sorts_specs->Specs->SortDirection == ImGuiSortDirection_Descending) {
|
||||||
|
std::sort(dirs.begin(), dirs.end(), [](const auto& a, const auto& b) -> bool {
|
||||||
|
return a.last_write_time() < b.last_write_time();
|
||||||
|
});
|
||||||
|
std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) -> bool {
|
||||||
|
return a.last_write_time() < b.last_write_time();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
std::sort(dirs.begin(), dirs.end(), [](const auto& a, const auto& b) -> bool {
|
||||||
|
return a.last_write_time() > b.last_write_time();
|
||||||
|
});
|
||||||
|
std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) -> bool {
|
||||||
|
return a.last_write_time() > b.last_write_time();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break; default: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& dir_entry : dirs) {
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
if (tmp_id & 0x01) {
|
||||||
|
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, dir_bg0_color);
|
||||||
|
} else {
|
||||||
|
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg1, dir_bg1_color);
|
||||||
|
}
|
||||||
|
ImGui::PushID(tmp_id++);
|
||||||
|
if (ImGui::Selectable("D", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||||
|
_current_file_path = dir_entry.path() / "";
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
ImGui::TextUnformatted((dir_entry.path().filename().string() + "/").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
ImGui::TextDisabled("---");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
const auto ctime = std::chrono::system_clock::to_time_t(dir_entry.last_write_time() - decltype(dir_entry.last_write_time())::clock::now() + std::chrono::system_clock::now());
|
||||||
|
const auto ltime = std::localtime(&ctime);
|
||||||
|
ImGui::TextDisabled("%2d.%2d.%2d - %2d:%2d", ltime->tm_mday, ltime->tm_mon, ltime->tm_year + 1900, ltime->tm_hour, ltime->tm_min);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// files
|
||||||
|
for (auto const& dir_entry : files) {
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
ImGui::PushID(tmp_id++);
|
||||||
|
if (ImGui::Selectable("F", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||||
|
_current_file_path = dir_entry.path();
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
ImGui::TextUnformatted(dir_entry.path().filename().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
ImGui::TextDisabled("%s", std::to_string(dir_entry.file_size()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
const auto ctime = std::chrono::system_clock::to_time_t(dir_entry.last_write_time() - decltype(dir_entry.last_write_time())::clock::now() + std::chrono::system_clock::now());
|
||||||
|
const auto ltime = std::localtime(&ctime);
|
||||||
|
ImGui::TextDisabled("%2d.%2d.%2d - %2d:%2d", ltime->tm_mday, ltime->tm_mon, ltime->tm_year + 1900, ltime->tm_hour, ltime->tm_min);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Button("X cancel", {ImGui::GetWindowContentRegionWidth()/2.f, TEXT_BASE_HEIGHT*2})) {
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
_on_cancel();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("choose ->", {-FLT_MIN, TEXT_BASE_HEIGHT*2})) {
|
||||||
|
if (_is_valid(_current_file_path)) {
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
_on_choose(_current_file_path);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
30
src/file_selector.hpp
Normal file
30
src/file_selector.hpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
struct FileSelector {
|
||||||
|
std::filesystem::path _current_file_path = std::filesystem::canonical(".") / ""; // add /
|
||||||
|
|
||||||
|
bool _open_popup {false};
|
||||||
|
|
||||||
|
std::function<bool(const std::filesystem::path& path)> _is_valid = [](auto){ return true; };
|
||||||
|
std::function<void(const std::filesystem::path& path)> _on_choose = [](auto){};
|
||||||
|
std::function<void(void)> _on_cancel = [](){};
|
||||||
|
|
||||||
|
void reset(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
FileSelector(void);
|
||||||
|
|
||||||
|
// TODO: supply hints
|
||||||
|
void requestFile(
|
||||||
|
std::function<bool(const std::filesystem::path& path)>&& is_valid,
|
||||||
|
std::function<void(const std::filesystem::path& path)>&& on_choose,
|
||||||
|
std::function<void(void)>&& on_cancel
|
||||||
|
);
|
||||||
|
|
||||||
|
// call this each frame
|
||||||
|
void render(void);
|
||||||
|
};
|
||||||
|
|
@ -6,6 +6,7 @@
|
|||||||
#include <imgui/backends/imgui_impl_sdlrenderer3.h>
|
#include <imgui/backends/imgui_impl_sdlrenderer3.h>
|
||||||
|
|
||||||
#include "./theme.hpp"
|
#include "./theme.hpp"
|
||||||
|
#include "./sdlrenderer_texture_uploader.hpp"
|
||||||
|
|
||||||
#include "./start_screen.hpp"
|
#include "./start_screen.hpp"
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SDL_Renderer, decltype(&SDL_DestroyRenderer)> renderer {
|
std::unique_ptr<SDL_Renderer, decltype(&SDL_DestroyRenderer)> renderer {
|
||||||
SDL_CreateRenderer(window.get(), nullptr, 0),
|
SDL_CreateRenderer(window.get(), nullptr, SDL_RENDERER_PRESENTVSYNC),
|
||||||
&SDL_DestroyRenderer
|
&SDL_DestroyRenderer
|
||||||
};
|
};
|
||||||
if (!renderer) {
|
if (!renderer) {
|
||||||
@ -52,7 +53,7 @@ int main(int argc, char** argv) {
|
|||||||
ImGui_ImplSDLRenderer3_Init(renderer.get());
|
ImGui_ImplSDLRenderer3_Init(renderer.get());
|
||||||
auto imgui_sdlrenderer_scope = std::async(std::launch::deferred, &ImGui_ImplSDLRenderer3_Shutdown);
|
auto imgui_sdlrenderer_scope = std::async(std::launch::deferred, &ImGui_ImplSDLRenderer3_Shutdown);
|
||||||
|
|
||||||
std::unique_ptr<Screen> screen = std::make_unique<StartScreen>();
|
std::unique_ptr<Screen> screen = std::make_unique<StartScreen>(renderer.get());
|
||||||
|
|
||||||
bool quit = false;
|
bool quit = false;
|
||||||
while (!quit) {
|
while (!quit) {
|
||||||
|
@ -2,9 +2,20 @@
|
|||||||
|
|
||||||
#include <imgui/imgui.h>
|
#include <imgui/imgui.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
MainScreen::MainScreen(std::string save_path) : rmm(cr), tc(save_path) {
|
MainScreen::MainScreen(SDL_Renderer* renderer_, std::string save_path) :
|
||||||
|
renderer(renderer_),
|
||||||
|
rmm(cr),
|
||||||
|
tc(save_path),
|
||||||
|
tcm(cr, tc, tc),
|
||||||
|
tmm(rmm, cr, tcm, tc, tc),
|
||||||
|
ttm(rmm, cr, tcm, tc, tc),
|
||||||
|
sdlrtu(renderer_),
|
||||||
|
cg(rmm, cr, sdlrtu)
|
||||||
|
{
|
||||||
tel.subscribeAll(tc);
|
tel.subscribeAll(tc);
|
||||||
|
|
||||||
conf.set("tox", "save_file_path", save_path);
|
conf.set("tox", "save_file_path", save_path);
|
||||||
@ -33,12 +44,15 @@ MainScreen::MainScreen(std::string save_path) : rmm(cr), tc(save_path) {
|
|||||||
|
|
||||||
// graphics
|
// graphics
|
||||||
g_provideInstance("ImGuiContext", "host", ImGui::GetCurrentContext());
|
g_provideInstance("ImGuiContext", "host", ImGui::GetCurrentContext());
|
||||||
//g_provideInstance<TextureUploaderI>("TextureUploaderI", "host", &ogltu);
|
g_provideInstance<TextureUploaderI>("TextureUploaderI", "host", &sdlrtu);
|
||||||
}
|
}
|
||||||
|
|
||||||
conf.dump();
|
conf.dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MainScreen::~MainScreen(void) {
|
||||||
|
}
|
||||||
|
|
||||||
Screen* MainScreen::poll(bool& quit) {
|
Screen* MainScreen::poll(bool& quit) {
|
||||||
auto new_time = std::chrono::high_resolution_clock::now();
|
auto new_time = std::chrono::high_resolution_clock::now();
|
||||||
const float time_delta {std::chrono::duration<float, std::chrono::seconds::period>(new_time - last_time).count()};
|
const float time_delta {std::chrono::duration<float, std::chrono::seconds::period>(new_time - last_time).count()};
|
||||||
@ -48,12 +62,41 @@ Screen* MainScreen::poll(bool& quit) {
|
|||||||
|
|
||||||
pm.tick(time_delta);
|
pm.tick(time_delta);
|
||||||
|
|
||||||
|
cg.render();
|
||||||
|
|
||||||
{
|
{
|
||||||
bool open = !quit;
|
bool open = !quit;
|
||||||
ImGui::ShowDemoWindow(&open);
|
ImGui::ShowDemoWindow(&open);
|
||||||
quit = !open;
|
quit = !open;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ // texture tests
|
||||||
|
const size_t width = 8;
|
||||||
|
const size_t height = 8;
|
||||||
|
#define W 0xff, 0xff, 0xff, 0xff
|
||||||
|
#define B 0x00, 0x00, 0x00, 0xff
|
||||||
|
#define P 0xff, 0x00, 0xff, 0xff
|
||||||
|
static uint8_t raw_pixel[width*height*4] {
|
||||||
|
P, W, W, W, W, W, W, P,
|
||||||
|
W, W, W, W, W, W, W, W,
|
||||||
|
W, W, W, W, W, W, W, W,
|
||||||
|
W, W, W, B, B, W, W, W,
|
||||||
|
W, W, W, B, B, W, W, W,
|
||||||
|
W, W, W, W, W, W, W, W,
|
||||||
|
W, W, W, W, W, W, W, W,
|
||||||
|
P, W, W, W, W, W, W, P,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint64_t texture = sdlrtu.uploadRGBA(raw_pixel, width, height);
|
||||||
|
|
||||||
|
if (ImGui::Begin("test texture")) {
|
||||||
|
ImGui::Text("test texture windoajsdf");
|
||||||
|
|
||||||
|
ImGui::Image(reinterpret_cast<void*>(texture), {width*10, height*10});
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,13 +8,27 @@
|
|||||||
#include <solanaceae/plugin/plugin_manager.hpp>
|
#include <solanaceae/plugin/plugin_manager.hpp>
|
||||||
#include <solanaceae/toxcore/tox_event_logger.hpp>
|
#include <solanaceae/toxcore/tox_event_logger.hpp>
|
||||||
|
|
||||||
|
#include <solanaceae/tox_contacts/tox_contact_model2.hpp>
|
||||||
|
#include <solanaceae/tox_messages/tox_message_manager.hpp>
|
||||||
|
#include <solanaceae/tox_messages/tox_transfer_manager.hpp>
|
||||||
|
|
||||||
#include "./tox_client.hpp"
|
#include "./tox_client.hpp"
|
||||||
|
|
||||||
|
#include "./sdlrenderer_texture_uploader.hpp"
|
||||||
|
#include "./chat_gui4.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
// fwd
|
||||||
|
extern "C" {
|
||||||
|
struct SDL_Renderer;
|
||||||
|
} // C
|
||||||
|
|
||||||
struct MainScreen final : public Screen {
|
struct MainScreen final : public Screen {
|
||||||
|
SDL_Renderer* renderer;
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point last_time = std::chrono::high_resolution_clock::now();
|
std::chrono::high_resolution_clock::time_point last_time = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
SimpleConfigModel conf;
|
SimpleConfigModel conf;
|
||||||
@ -25,12 +39,17 @@ struct MainScreen final : public Screen {
|
|||||||
|
|
||||||
ToxEventLogger tel{std::cout};
|
ToxEventLogger tel{std::cout};
|
||||||
ToxClient tc;
|
ToxClient tc;
|
||||||
|
ToxContactModel2 tcm;
|
||||||
|
ToxMessageManager tmm;
|
||||||
|
ToxTransferManager ttm;
|
||||||
|
|
||||||
|
SDLRendererTextureUploader sdlrtu;
|
||||||
//OpenGLTextureUploader ogltu;
|
//OpenGLTextureUploader ogltu;
|
||||||
|
|
||||||
|
ChatGui4 cg;
|
||||||
|
|
||||||
MainScreen(std::string save_path);
|
MainScreen(SDL_Renderer* renderer_, std::string save_path);
|
||||||
~MainScreen(void) = default;
|
~MainScreen(void);
|
||||||
|
|
||||||
// return nullptr if not next
|
// return nullptr if not next
|
||||||
// sets bool quit to true if exit
|
// sets bool quit to true if exit
|
||||||
|
32
src/sdlrenderer_texture_uploader.cpp
Normal file
32
src/sdlrenderer_texture_uploader.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "./sdlrenderer_texture_uploader.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
SDLRendererTextureUploader::SDLRendererTextureUploader(SDL_Renderer* renderer_) :
|
||||||
|
renderer(renderer_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SDLRendererTextureUploader::uploadRGBA(const uint8_t* data, uint32_t width, uint32_t height) {
|
||||||
|
// TODO: test if pitch is 4 or 4*width
|
||||||
|
SDL_Surface* surf = SDL_CreateSurfaceFrom(
|
||||||
|
(void*)data,
|
||||||
|
width, height,
|
||||||
|
4*width,
|
||||||
|
//SDL_PIXELFORMAT_RGBA8888
|
||||||
|
SDL_PIXELFORMAT_ABGR8888 // little endian
|
||||||
|
);
|
||||||
|
assert(surf); // TODO: add error reporting
|
||||||
|
|
||||||
|
SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer, surf);
|
||||||
|
assert(tex); // TODO: add error reporting
|
||||||
|
|
||||||
|
SDL_DestroySurface(surf);
|
||||||
|
|
||||||
|
return reinterpret_cast<uint64_t>(tex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLRendererTextureUploader::destroy(uint64_t tex_id) {
|
||||||
|
SDL_DestroyTexture(static_cast<SDL_Texture*>(reinterpret_cast<void*>(tex_id)));
|
||||||
|
}
|
||||||
|
|
16
src/sdlrenderer_texture_uploader.hpp
Normal file
16
src/sdlrenderer_texture_uploader.hpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "./texture_uploader.hpp"
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
struct SDLRendererTextureUploader : public TextureUploaderI {
|
||||||
|
SDL_Renderer* renderer;
|
||||||
|
SDLRendererTextureUploader(void) = delete;
|
||||||
|
SDLRendererTextureUploader(SDL_Renderer* renderer_);
|
||||||
|
~SDLRendererTextureUploader(void) = default;
|
||||||
|
|
||||||
|
uint64_t uploadRGBA(const uint8_t* data, uint32_t width, uint32_t height) override;
|
||||||
|
void destroy(uint64_t tex_id) override;
|
||||||
|
};
|
||||||
|
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
StartScreen::StartScreen(void) {
|
StartScreen::StartScreen(SDL_Renderer* renderer) : _renderer(renderer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Screen* StartScreen::poll(bool&) {
|
Screen* StartScreen::poll(bool&) {
|
||||||
@ -18,7 +18,7 @@ Screen* StartScreen::poll(bool&) {
|
|||||||
// | +------+ +--------
|
// | +------+ +--------
|
||||||
// +----------------------------
|
// +----------------------------
|
||||||
|
|
||||||
auto new_screen = std::make_unique<MainScreen>("tomato.tox");
|
auto new_screen = std::make_unique<MainScreen>(_renderer, "tomato.tox");
|
||||||
return new_screen.release();
|
return new_screen.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,16 @@
|
|||||||
|
|
||||||
#include "./screen.hpp"
|
#include "./screen.hpp"
|
||||||
|
|
||||||
|
// fwd
|
||||||
|
extern "C" {
|
||||||
|
struct SDL_Renderer;
|
||||||
|
} // C
|
||||||
|
|
||||||
struct StartScreen final : public Screen {
|
struct StartScreen final : public Screen {
|
||||||
StartScreen(void);
|
SDL_Renderer* _renderer;
|
||||||
|
|
||||||
|
StartScreen(void) = delete;
|
||||||
|
StartScreen(SDL_Renderer* renderer);
|
||||||
~StartScreen(void) = default;
|
~StartScreen(void) = default;
|
||||||
|
|
||||||
// return nullptr if not next
|
// return nullptr if not next
|
||||||
|
13
src/texture_uploader.hpp
Normal file
13
src/texture_uploader.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
struct TextureUploaderI {
|
||||||
|
virtual ~TextureUploaderI(void) {}
|
||||||
|
|
||||||
|
//virtual uint64_t uploadRGBA(const uint8_t* data, uint64_t data_size) = 0;
|
||||||
|
virtual uint64_t uploadRGBA(const uint8_t* data, uint32_t width, uint32_t height) = 0;
|
||||||
|
|
||||||
|
virtual void destroy(uint64_t tex_id) = 0;
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user