refactor big contact

This commit is contained in:
2024-04-21 14:17:50 +02:00
parent 858b9dfcfa
commit b88fffd959
13 changed files with 399 additions and 171 deletions

View File

@ -0,0 +1,145 @@
#include "./contact_list.hpp"
#include <solanaceae/contact/components.hpp>
#include <imgui/imgui.h>
//#include <imgui/imgui_internal.h>
bool renderContactBig(
const Theme& th,
ContactTextureCache& contact_tc,
const Contact3Handle c,
const bool unread,
const bool selectable,
const bool selected
) {
// we dont need ### bc there is no named prefix
auto label = "##" + std::to_string(entt::to_integral(c.entity()));
const bool request_incoming = c.all_of<Contact::Components::RequestIncoming>();
const bool request_outgoing = c.all_of<Contact::Components::TagRequestOutgoing>();
ImVec2 orig_curser_pos = ImGui::GetCursorPos();
// HACK: fake selected to make it draw a box for us
const bool show_selected = request_incoming || request_outgoing || selected;
if (request_incoming) {
ImGui::PushStyleColor(
ImGuiCol_Header,
th.getColor<ThemeCol_Contact::request_incoming>()
);
} else if (request_outgoing) {
ImGui::PushStyleColor(
ImGuiCol_Header,
th.getColor<ThemeCol_Contact::request_outgoing>()
);
}
const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
bool got_selected = false;
if (selectable) {
got_selected = ImGui::Selectable(label.c_str(), show_selected, ImGuiSelectableFlags_None, {0, 3*TEXT_BASE_HEIGHT});
} else {
got_selected = ImGui::InvisibleButton(label.c_str(), {-FLT_MIN, 3*TEXT_BASE_HEIGHT});
}
if (request_incoming || request_outgoing) {
ImGui::PopStyleColor();
}
if (ImGui::BeginItemTooltip()) {
if (c.all_of<Contact::Components::ConnectionState>()) {
const auto cstate = c.get<Contact::Components::ConnectionState>().state;
ImGui::Text("Connection state: %s",
(cstate == Contact::Components::ConnectionState::disconnected)
? "offline"
: (cstate == Contact::Components::ConnectionState::direct)
? "online (direct)"
: "online (cloud)"
);
} else {
ImGui::TextUnformatted("Connection state: unknown");
}
ImGui::EndTooltip();
}
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);
// TODO: refactor out avatar (with online state overlay)
ImVec4 color_current = th.getColor<ThemeCol_Contact::avatar_offline>();
if (c.all_of<Contact::Components::ConnectionState>()) {
const auto c_state = c.get<Contact::Components::ConnectionState>().state;
if (c_state == Contact::Components::ConnectionState::State::direct) {
color_current = th.getColor<ThemeCol_Contact::avatar_online_direct>();
} else if (c_state == Contact::Components::ConnectionState::State::cloud) {
color_current = th.getColor<ThemeCol_Contact::avatar_online_cloud>();
}
}
// avatar
const auto [id, width, height] = contact_tc.get(c);
ImGui::Image(
id,
ImVec2{img_y, img_y},
{0, 0},
{1, 1},
{1, 1, 1, 1},
color_current
);
ImGui::SameLine();
ImGui::BeginGroup();
{
// TODO: is there a better way?
// maybe cache mm?
//bool has_unread = false;
#if 0
if (const auto* mm = _rmm.get(c); mm != nullptr) {
if (const auto* unread_storage = mm->storage<Message::Components::TagUnread>(); unread_storage != nullptr && !unread_storage->empty()) {
#if 0
assert(unread_storage.size() == 0);
assert(unread_storage.cbegin() == unread_storage.cend());
std::cout << "UNREAD ";
for (const auto e : mm->view<Message::Components::TagUnread>()) {
std::cout << entt::to_integral(e) << " ";
}
std::cout << "\n";
#endif
has_unread = true;
}
}
#endif
ImGui::Text("%s%s", unread?"* ":"", (c.all_of<Contact::Components::Name>() ? c.get<Contact::Components::Name>().name.c_str() : "<unk>"));
if (request_incoming) {
ImGui::TextUnformatted("Incoming request/invite");
} else if (request_outgoing) {
ImGui::TextUnformatted("Outgoing request/invite");
} else {
//ImGui::Text("status message...");
}
//constexpr std::string_view test_text{"text"};
//ImGui::RenderTextEllipsis(ImGui::GetWindowDrawList(), ImVec2{}, ImVec2{}, 1.f, 1.f, test_text.data(), test_text.data()+test_text.size(), nullptr);
}
ImGui::EndGroup();
ImGui::SetCursorPos(post_curser_pos);
return got_selected;
}

View File

@ -0,0 +1,33 @@
#pragma once
#include "./texture_cache_defs.hpp"
#include "./theme.hpp"
#include <solanaceae/contact/contact_model3.hpp>
enum class ThemeCol_Contact {
request_incoming,
request_outgoing,
avatar_online_direct,
avatar_online_cloud,
avatar_offline,
};
// returns true if clicked, if selectable, will highlight on hover and respect selected
// TODO: refine
// +------+
// | | *Name (Alias?)
// |Avatar| Satus Message <-- richpresence interface?
// | | user status (online/away/busy)-direct/relayed / offline <-- last text?
// +------+
bool renderContactBig(
const Theme& th,
ContactTextureCache& contact_tc,
const Contact3Handle c,
const bool unread = false,
const bool selectable = false,
const bool selected = false
);

View File

@ -0,0 +1,12 @@
#pragma once
#include <solanaceae/message3/registry_message_model.hpp>
#include "../texture_cache.hpp"
#include "../tox_avatar_loader.hpp"
#include "../message_image_loader.hpp"
using ContactTextureCache = TextureCache<void*, Contact3, ToxAvatarLoader>;
using MessageTextureCache = TextureCache<void*, Message3Handle, MessageImageLoader>;

60
src/chat_gui/theme.cpp Normal file
View File

@ -0,0 +1,60 @@
#include "./theme.hpp"
// HACK: includes everything and sets theme defaults
#include "./contact_list.hpp"
//#include <iostream>
//enum class TestThemeSet {
//Value1,
//};
//// specialization
////template<>
////std::string typeValueName(TestThemeSet v) {
////switch (v) {
////case TestThemeSet::Value1: return "Value1";
////default: return "unk";
////}
////}
Theme::Theme(void) {
load();
}
void Theme::update(void) {
}
bool Theme::load(void) {
name = "Default";
//setColor<TestThemeSet::Value1>(ImVec4{});
//std::cout << "test value name: " << getColorName<TestThemeSet::Value1>() << "\n";
return true;
}
bool Theme::store(void) {
return true;
}
Theme getDefaultThemeDark(void) {
Theme t;
t.setColor<ThemeCol_Contact::request_incoming>({0.98f, 0.41f, 0.26f, 0.52f});
t.setColor<ThemeCol_Contact::request_outgoing>({0.98f, 0.26f, 0.41f, 0.52f});
t.setColor<ThemeCol_Contact::avatar_online_direct>({0.3, 1, 0, 1});
t.setColor<ThemeCol_Contact::avatar_online_cloud>({0, 1, 0.8, 1});
t.setColor<ThemeCol_Contact::avatar_offline>({0.4, 0.4, 0.4, 1});
return t;
}
Theme getDefaultThemeLight(void) {
// HACK: inherit dark and only diff
Theme t = getDefaultThemeDark();
return t;
}

76
src/chat_gui/theme.hpp Normal file
View File

@ -0,0 +1,76 @@
#pragma once
#include <imgui/imgui.h>
#include <entt/container/dense_map.hpp>
#include <entt/core/type_info.hpp>
#include <string>
#include <type_traits>
// default is resolving to its value
template<typename T>
std::string typeValueName(T V) {
return std::to_string(static_cast<std::underlying_type_t<T>>(V));
}
// stores theming values and colors not expressed by imgui directly
struct Theme {
using key_type = entt::id_type;
entt::dense_map<key_type, ImVec4> colors;
entt::dense_map<key_type, std::string> colors_name;
// TODO: spec out dependencies
// TODO: what for
entt::dense_map<key_type, float> single_values;
std::string name; // theme name
Theme(void);
// call when any color changed, so dependencies can be resolved
void update(void);
template<auto V>
void setColor(ImVec4 color) {
constexpr auto key = entt::type_hash<entt::tag<V>>::value();
colors[key] = color;
if (!colors_name.contains(key)) {
std::string key_name = static_cast<std::string>(
entt::type_name<decltype(V)>::value()
) + ":" + typeValueName(V);
colors_name[key] = key_name;
}
}
template<auto V>
ImVec4 getColor(void) const {
constexpr auto key = entt::type_hash<entt::tag<V>>::value();
const auto it = colors.find(key);
if (it != colors.end()) {
return it->second;
} else {
return {}; // TODO: pink as default?
}
}
template<auto V>
std::string_view getColorName(void) const {
constexpr auto key = entt::type_hash<entt::tag<V>>::value();
if (colors_name.contains(key)) {
return colors_name.at(key);
} else {
return "unk";
}
}
// TODO: actually serialize from config?
bool load(void);
bool store(void);
};
Theme getDefaultThemeDark(void);
Theme getDefaultThemeLight(void);