From: Jann Horn Date: Sun, 9 Aug 2026 21:45:12 +0000 (+0200) Subject: initial commit X-Git-Url: http://git.thejh.net/?a=commitdiff_plain;h=3c36b9bebbeaaa0b2d9a75e78bc52b7d384c322a;p=logscroll.git initial commit --- 3c36b9bebbeaaa0b2d9a75e78bc52b7d384c322a diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1bd38b4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +logscroll +imgui.ini +*.mp4 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..028a4fb --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "imgui"] + path = imgui + url = https://github.com/ocornut/imgui diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ed261f2 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +IMGUI_DIR = imgui/ +SOURCES = logscroll.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp +SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp +OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) + +CXXFLAGS = -std=c++20 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends +CXXFLAGS += -g -Wall -Wformat +LIBS = -lGL `pkg-config --static --libs glfw3` +CXXFLAGS += `pkg-config --cflags glfw3` + +logscroll: $(OBJS) + $(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS) + +%.o:%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/backends/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +clean: + rm -f $(EXE) $(OBJS) diff --git a/imgui b/imgui new file mode 160000 index 0000000..46d39d5 --- /dev/null +++ b/imgui @@ -0,0 +1 @@ +Subproject commit 46d39d56febc2a00bdd2270dc88c8a13f2a0441a diff --git a/logscroll.cpp b/logscroll.cpp new file mode 100644 index 0000000..a6fb170 --- /dev/null +++ b/logscroll.cpp @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include +#include "imgui.h" +#include "imgui_impl_glfw.h" +#include "imgui_impl_opengl3.h" +#include + +static void glfw_error_callback(int error, const char* description) { + errx(1, "GLFW Error %d: %s", error, description); +} + +static unsigned int physical_line_length = 30; +static std::vector physical_lines; +static std::vector logical_lines; +static std::string next_line_buf; +static size_t next_line_buf_used; +static void add_line_(std::string& line) { + size_t num_phys_lines = (line.size() + (physical_line_length-1)) / physical_line_length; + if (num_phys_lines == 0) + physical_lines.push_back(""); + for (size_t i=0; i= next_line_buf_used) + break; + add_line(next_line_buf.substr(0, newline_pos)); + want_scroll_to_bottom = true; + next_line_buf = next_line_buf.substr(newline_pos+1); + next_line_buf_used -= newline_pos+1; + } + } + + float line_height = ImGui::GetTextLineHeightWithSpacing(); + + // Start the Dear ImGui frame + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + //ImGui::ShowDemoWindow(nullptr); + + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + unsigned int num_lines_in_window = viewport->Size.y / line_height; + ImGui::SetNextWindowPos(viewport->Pos); + ImGui::SetNextWindowSize(viewport->Size); + + ImGui::SetNextWindowContentSize(ImVec2(0, line_height * (physical_lines.size()+1))); + if (1 && want_scroll_to_bottom) { + ssize_t scroll_y = (ssize_t)physical_lines.size() - (ssize_t)num_lines_in_window + 1; + if (scroll_y < 0) + scroll_y = 0; + ImGui::SetNextWindowScroll(ImVec2(0, line_height*scroll_y)); + } + ImGui::Begin("logscroll", nullptr, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | + ImGuiWindowFlags_AlwaysVerticalScrollbar); + unsigned int new_physical_line_length = ImGui::GetContentRegionAvail().x / ImGui::CalcTextSize("A").x; + if (physical_line_length != new_physical_line_length) { + physical_line_length = new_physical_line_length; + physical_lines.clear(); + for (std::string& line : logical_lines) + add_line_(line); + } + size_t phys_line_startidx = ImGui::GetScrollY() / line_height; + size_t top_line_idx = phys_line_startidx - (phys_line_startidx % num_lines_in_window); + ImGui::SetCursorScreenPos(ImVec2(ImGui::GetCursorScreenPos().x, ImGui::GetCursorScreenPos().y + ImGui::GetScrollY())); + for (size_t i=top_line_idx; iAddRectFilled(p0, p1, ImGui::GetColorU32(ImVec4(1, 0, 0, 1))); + ImGui::Text(" "); + continue; + } + if (i == top_line_idx + num_lines_in_window) + break; + size_t cur_i = (i < phys_line_startidx) ? (i + num_lines_in_window) : i; + if (cur_i < physical_lines.size()) + ImGui::Text("%s", physical_lines[cur_i].c_str()); + else + ImGui::Text(" "); + } + ImGui::End(); + + // Rendering + ImGui::Render(); + int display_w, display_h; + glfwGetFramebufferSize(window, &display_w, &display_h); + glViewport(0, 0, display_w, display_h); + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + + glfwSwapBuffers(window); + } + + // Cleanup + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + + glfwDestroyWindow(window); + glfwTerminate(); + + return 0; +}