|
- /* moontalk-imgui.cpp - Dear ImGui frontend
- * written by an Anon. https://boards.4chan.org/g/thread/98813374#p98826333
- */
-
- #include <imgui.h>
- #include <imgui_stdlib.h>
- #include <imgui_impl_sdl2.h>
- #include <imgui_impl_sdlrenderer2.h>
- #include <SDL.h>
-
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <err.h>
- #include <stdio.h>
- #include <unistd.h>
-
- #include <vector>
- #include <string>
- #include <thread>
- #include <mutex>
- #include <queue>
-
- #define SERV "7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion"
- #define PORT "50000"
-
- static int moontalk_fd = -1;
- static std::mutex inqueue_lock;
- static std::queue<std::string> inqueue;
- static std::vector<std::string> moontalk_lines;
-
- int tcp_connect(const char* addr, const char *port)
- {
- struct addrinfo hints;
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
-
- struct addrinfo* res;
- int status = getaddrinfo(addr, port, &hints, &res);
- if (status != 0)
- errx(1, "getaddrinfo: %s", gai_strerror(status));
-
- int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
- if (fd < 0)
- err(1, "socket");
-
- if (connect(fd, res->ai_addr, res->ai_addrlen))
- err(1, "socket");
-
- freeaddrinfo(res);
- return fd;
- }
-
- void moontalk_send(const std::string& line)
- {
- char timebuf[256];
-
- time_t t = time(NULL);;
- struct tm * tm;
- tm = gmtime(&t);
- strftime(timebuf, sizeof(timebuf), "<%Y/%m/%d %H:%M:%S ", tm);
-
-
- std::string out;
- out += timebuf;
- out += line;
- if (line.at(line.size()-1) != '\n') out.push_back('\n');
-
- send(moontalk_fd, out.data(), out.size(), 0);
- printf("send %s", out.c_str());
- }
-
- void read_loop()
- {
- char buffer[4096];
- size_t pos = 0;
-
- for (;;) {
- ssize_t r = read(moontalk_fd, buffer + pos, sizeof(buffer) - pos);
- if (r < 0) {
- if (r == EINTR)
- continue;
- err(1, "read");
- }
- pos += r;
-
- // scan lines and push them to inqueue
- size_t start = 0;
- size_t end = 0;
- while (end < pos) {
- if (buffer[end] == '\n') {
- std::string line = {buffer + start, buffer + end+1};
-
- inqueue_lock.lock();
- inqueue.push(std::move(line));
- inqueue_lock.unlock();
-
- start = end+1;
- end = end+1;
- } else {
- end++;
- }
- }
- if (start != 0) {
- memmove(buffer, buffer+start, pos-start);
- pos -= start;
- }
- }
- }
-
- void ui()
- {
- static std::string input;
-
- if (ImGui::Begin("Chat")) {
- for (auto& line : moontalk_lines) {
- ImGui::TextUnformatted(line.c_str());
- }
- ImGui::End();
- }
-
- if (ImGui::Begin("Input")) {
- ImGui::InputText("Input", &input);
- if (ImGui::Button("Send")) {
- moontalk_send(input);
- input.clear();
- }
-
- // TODO or make it separate window and handle the layout on docking layer
- ImGui::End();
- }
- }
-
- int main(int argc, char *argv[])
- {
- if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
- err(1, "SDL_Init: %s", SDL_GetError());
-
- // From 2.0.18: Enable native IME.
- #ifdef SDL_HINT_IME_SHOW_UI
- SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
- #endif
-
- SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
- SDL_Window* window = SDL_CreateWindow("moontalk", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
- if (!window)
- err(1, "SDL_CreateWindow: %s", SDL_GetError());
-
- SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
- if (renderer == nullptr)
- err(1, "SDL_CreateRenderer: %s", SDL_GetError());
-
- // Setup Dear ImGui context
- IMGUI_CHECKVERSION();
- ImGui::CreateContext();
- ImGuiIO& io = ImGui::GetIO(); (void)io;
- io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
- io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
- io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
- // io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
- //io.ConfigViewportsNoAutoMerge = true;
- //io.ConfigViewportsNoTaskBarIcon = true;
-
- // Setup Dear ImGui style
- ImGui::StyleColorsDark();
- //ImGui::StyleColorsLight();
-
- // Setup Platform/Renderer backends
- ImGui_ImplSDL2_InitForSDLRenderer(window, renderer);
- ImGui_ImplSDLRenderer2_Init(renderer);
-
- // Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
- // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
- // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
- // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering.
- // - Read 'docs/FONTS.md' for more instructions and details.
- // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
- //io.Fonts->AddFontDefault();
- //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
- //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
- //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
- //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
- //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese());
- //IM_ASSERT(font != nullptr);
-
- // setup
- fprintf(stderr, "Connecting...\n");
- moontalk_fd = tcp_connect(SERV, PORT);
- fprintf(stderr, "Connected\n");
-
- std::thread t(read_loop);
-
- bool done = false;
- while (!done) {
- // Poll and handle events (inputs, window resize, etc.)
- // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
- // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
- // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
- // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
- SDL_Event event;
- while (SDL_PollEvent(&event)) {
- ImGui_ImplSDL2_ProcessEvent(&event);
- if (event.type == SDL_QUIT)
- done = true;
- if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
- done = true;
- }
-
- inqueue_lock.lock();
- if (!inqueue.empty()) {
- std::string line = std::move(inqueue.front());
- inqueue.pop();
- moontalk_lines.push_back(std::move(line));
- }
- inqueue_lock.unlock();
-
- // Start the Dear ImGui frame
- ImGui_ImplSDLRenderer2_NewFrame();
- ImGui_ImplSDL2_NewFrame();
- ImGui::NewFrame();
-
- ImGui::DockSpaceOverViewport(ImGui::GetMainViewport());
-
- ui();
-
- // Rendering
- ImGui::Render();
- SDL_RenderSetScale(renderer, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
- SDL_SetRenderDrawColor(renderer, 0, 0, 0, 1);
- SDL_RenderClear(renderer);
- ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData());
- SDL_RenderPresent(renderer);
- }
-
- // Cleanup
- ImGui_ImplSDLRenderer2_Shutdown();
- ImGui_ImplSDL2_Shutdown();
- ImGui::DestroyContext();
-
- SDL_DestroyRenderer(renderer);
- SDL_DestroyWindow(window);
- SDL_Quit();
-
- close(moontalk_fd);
-
- return 0;
- }
|