diff --git a/Allocators/private/HeapAllocatorGlobal.cpp b/Allocators/private/HeapAllocatorGlobal.cpp index 291ccd6..469070d 100644 --- a/Allocators/private/HeapAllocatorGlobal.cpp +++ b/Allocators/private/HeapAllocatorGlobal.cpp @@ -164,7 +164,7 @@ bool HeapAllocGlobal::checkLeaks() { } // 1) Check for not deallocated memory - if (mNumAllocations && ignoredCount != mNumAllocations) { + if (mNumAllocations && ignoredCount < mNumAllocations) { #ifdef MEM_STACK_TRACE for (auto iter = mEntry; iter; iter = iter->mPrev) { @@ -172,7 +172,7 @@ bool HeapAllocGlobal::checkLeaks() { } #endif - printf(" Count : %llu", mNumAllocations); + printf(" Count : %llu", mNumAllocations - ignoredCount); ASSERT(!"Destruction of not freed Allocator") return true; diff --git a/Containers/public/List.hpp b/Containers/public/List.hpp index 2da3168..85a49bf 100644 --- a/Containers/public/List.hpp +++ b/Containers/public/List.hpp @@ -177,8 +177,9 @@ namespace tp { void popBack() { DEBUG_ASSERT(mLast) + auto const tmp = mLast; detach(mLast); - deleteNode(mLast); + deleteNode(tmp); } void popFront() { diff --git a/Externals/imgui b/Externals/imgui index 1109de3..4144d7d 160000 --- a/Externals/imgui +++ b/Externals/imgui @@ -1 +1 @@ -Subproject commit 1109de38277fd2d14d4dca4c1cb8d4a2c4ff0f95 +Subproject commit 4144d7d772a800f08693b8b13f7c81f1f22a73c4 diff --git a/Graphics/examples/Example.cpp b/Graphics/examples/Example.cpp index 4505870..a074ff3 100644 --- a/Graphics/examples/Example.cpp +++ b/Graphics/examples/Example.cpp @@ -1,6 +1,8 @@ #include "Window.hpp" +#include "imgui.h" + int main() { tp::ModuleManifest* deps[] = { &tp::gModuleGraphics, nullptr }; tp::ModuleManifest testModule("Example", nullptr, nullptr, deps); @@ -10,12 +12,16 @@ int main() { } { - tp::HeapAllocGlobal::startIgnore(); auto window = tp::Window::createWindow(800, 600, "Window 1"); - tp::HeapAllocGlobal::stopIgnore(); if (window) { - window->renderLoop(); + while (!window->shouldClose()) { + window->processEvents(); + + ImGui::Text("Hello!"); + + window->draw(); + } } tp::Window::destroyWindow(window); diff --git a/Graphics/private/bindings/DebugGUI.cpp b/Graphics/private/bindings/DebugGUI.cpp index fdf1e79..5254806 100644 --- a/Graphics/private/bindings/DebugGUI.cpp +++ b/Graphics/private/bindings/DebugGUI.cpp @@ -42,10 +42,14 @@ void Graphics::GUI::deinit() { } void Graphics::GUI::proc() { + tp::HeapAllocGlobal::startIgnore(); + ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); + tp::HeapAllocGlobal::stopIgnore(); + // ImGui code goes here ImGui::Begin("Window"); ImGui::End(); diff --git a/Graphics/private/bindings/Window.cpp b/Graphics/private/bindings/Window.cpp index 3cf251f..88958d2 100644 --- a/Graphics/private/bindings/Window.cpp +++ b/Graphics/private/bindings/Window.cpp @@ -71,11 +71,13 @@ void Graphics::deinit() { mGl.deinit(); } -void Graphics::draw() { +void Graphics::proc() { mGl.proc(); mCanvas.proc(); mGui.proc(); +} +void Graphics::draw() { mGl.draw(); mCanvas.draw(); mGui.draw(); @@ -110,6 +112,8 @@ Window::~Window() { Window* Window::createWindow(int width, int height, const char* title) { + tp::HeapAllocGlobal::startIgnore(); + static int count = 1; if (!count) { printf("Window class is a singleton\n"); @@ -128,7 +132,10 @@ Window* Window::createWindow(int width, int height, const char* title) { printf("GLFW Error: %i %s\n", error, description); }); - return new Window(width, height, title); + auto out = new Window(width, height, title); + + tp::HeapAllocGlobal::stopIgnore(); + return out; } void Window::destroyWindow(Window* window) { @@ -136,15 +143,18 @@ void Window::destroyWindow(Window* window) { glfwTerminate(); } -void Window::renderLoop() { - while (!glfwWindowShouldClose(mContext->window)) { +bool Window::shouldClose() const { + return glfwWindowShouldClose(mContext->window); +} - mGraphics.draw(); +void Window::processEvents() { + glfwPollEvents(); + mGraphics.proc(); +} - // Swap buffers and poll events - glfwSwapBuffers(mContext->window); - glfwPollEvents(); - } +void Window::draw() { + mGraphics.draw(); + glfwSwapBuffers(mContext->window); } auto Window::getContext() -> Context* { return mContext; } \ No newline at end of file diff --git a/Graphics/public/Graphics.hpp b/Graphics/public/Graphics.hpp index b2e95d2..ef198b4 100644 --- a/Graphics/public/Graphics.hpp +++ b/Graphics/public/Graphics.hpp @@ -67,6 +67,7 @@ namespace tp { void init(Window* window); void deinit(); void draw(); + void proc(); private: GUI mGui; diff --git a/Graphics/public/Window.hpp b/Graphics/public/Window.hpp index 1f6a762..87d75bf 100644 --- a/Graphics/public/Window.hpp +++ b/Graphics/public/Window.hpp @@ -27,7 +27,10 @@ namespace tp { static void destroyWindow(Window* window); public: - void renderLoop(); + void draw(); + void processEvents(); + [[nodiscard]] bool shouldClose() const; + auto getContext() -> Context*; private: diff --git a/Math/public/Rect.hpp b/Math/public/Rect.hpp index 33fa70b..f6aba2a 100644 --- a/Math/public/Rect.hpp +++ b/Math/public/Rect.hpp @@ -94,7 +94,7 @@ namespace tp { // argument isInside bool isInside(const Vec2& p) const { - return (p.each_compre(pos) && (pos + size).each_compre(p)); + return isInside(p.x, p.y); } bool isInside(Type x, Type y) const { diff --git a/Objects/CMakeLists.txt b/Objects/CMakeLists.txt index 91166d2..893056a 100644 --- a/Objects/CMakeLists.txt +++ b/Objects/CMakeLists.txt @@ -7,7 +7,7 @@ project(Objects) ### ---------------------- Static Library --------------------- ### file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp") -file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp") +file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp" "./applications/*.hpp") add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) @@ -17,9 +17,11 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Strings Math Tokenizer CommandLine ### -------------------------- Applications -------------------------- ### #add_executable(osc ./applications/Compiler.cpp) #add_executable(osi ./applications/Interpreter.cpp) +add_executable(osg ./applications/GUI.cpp ./applications/GUIEntry.cpp) #target_link_libraries(osc ${PROJECT_NAME}) #target_link_libraries(osi ${PROJECT_NAME}) +target_link_libraries(osg ${PROJECT_NAME} Graphics Imgui) ### -------------------------- Tests -------------------------- ### enable_testing() diff --git a/Objects/applications/GUI.cpp b/Objects/applications/GUI.cpp new file mode 100644 index 0000000..3b6cdc0 --- /dev/null +++ b/Objects/applications/GUI.cpp @@ -0,0 +1,1109 @@ + +#include "GUI.h" + +#include "Rect.hpp" + +#include "interpreter/interpreter.h" + +#include "imgui.h" +#include "imgui_internal.h" + +namespace ImGui { + + bool SubMenuBegin(const char* desc, int level); + void SubMenuEnd(int level); + + void ToolTip(const char* desc); + + struct PopupData { + bool opened = false; + bool ishovered = false; + tp::Vec2F p1; + tp::Vec2F p2; + operator bool() { + return opened; + } + }; + + PopupData HoverPopupBegin(const char* id, tp::Vec2F size, tp::Vec2F pos = tp::Vec2F(-1), int flags = 0); + void HoverPopupEnd(PopupData& in); + + void ApplyStyle(tp::halnf dpmm, float font_size_mm = 5, float ui_scale = 1); +}; + +ImGui::PopupData ImGui::HoverPopupBegin(const char* str_id, tp::Vec2F size, tp::Vec2F pos_p, ImGuiPopupFlags popup_flags) { + ImGui::PopupData out; + out.ishovered = ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); + + if (out.ishovered) { + ImVec2 pos; + + if (pos_p == tp::Vec2F(-1)) { + pos = GImGui->CurrentWindow->DC.CursorPos; + } + else { + pos.x = pos_p.x; + pos.y = pos_p.y; + } + + ImGui::SetNextWindowPos(pos); + out.p1 = { pos.x, pos.y }; + + ImGui::OpenPopup(str_id); + + out.p2 = out.p1; + out.p2.x += ImGui::GetWindowWidth(); + } + + if (BeginPopup(str_id, ImGuiWindowFlags_NoMove)) { + out.opened = true; + + auto pos = GetWindowPos(); + out.p1 = { pos.x, pos.y }; + out.p2 = out.p1; + out.p2.x += ImGui::GetWindowWidth(); + + } + return out; +} + +void ImGui::HoverPopupEnd(ImGui::PopupData& in) { + + if (!in.opened) { + return; + } + + in.ishovered |= IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_ChildWindows); + + tp::Vec2F mousepos = { ImGui::GetMousePos().x, ImGui::GetMousePos().y }; + tp::halnf tollerance = 10; + tp::RectF tollerace_rect(tp::Vec2F(in.p1.x, in.p1.y - tollerance), tp::Vec2F(in.p2.x - in.p1.x, tollerance * 2.f)); + bool is_tollerance = tollerace_rect.isInside(mousepos); + + if (!(in.ishovered || is_tollerance)) { + CloseCurrentPopup(); + } + + EndPopup(); +} + + +obj::ObjectsGUI::~ObjectsGUI() { + if (mClipboard) { + obj::NDO->destroy(mClipboard); + } + for (auto iter : mViewStack) { + obj::NDO->destroy(iter->obj); + } +} + +void obj::ObjectsGUI::setClipboard(obj::Object* obj) { + if (mClipboard) { + obj::NDO->destroy(mClipboard); + } + + mClipboard = obj; + + if (mClipboard) { + obj::NDO->refinc(obj); + } +} + +obj::Object* obj::ObjectsGUI::getClipboard() { + return mClipboard; +} + +obj::Object* imgui_object_create_menu(obj::TypeGroups* type_group = NULL) { + + obj::Object* newo = NULL; + + if (!type_group) { + type_group = &obj::NDO->type_groups; + } + + for (auto childo : *type_group->getChilds()) { + + if (childo->val->isGroup()) { + if (ImGui::BeginMenu((childo->key).read())) { + newo = imgui_object_create_menu(childo->val); + ImGui::EndMenu(); + } + continue; + } + + if (ImGui::Button((childo->key).read(), { 100, 0 })) { + if (childo->key == "null") { + newo = NDO_NULL; + } + else { + newo = obj::NDO->create(childo->key); + } + } + } + + return newo; +} + +obj::ObjectsGUI::ObjectsGUI() { + assert(obj::NDO && "Objects library is not initialized"); +} + +void obj::ObjectsGUI::cd(obj::Object* child, tp::String name) { + mActive = child; + mViewStack.pushBack({ mActive, name }); + obj::NDO->refinc(child); +} + +void obj::ObjectsGUI::cdup() { + if (mViewStack.length() > 1) { + obj::NDO->destroy(mViewStack.last()->data.obj); + + mViewStack.popBack(); + mActive = mViewStack.last()->data.obj; + } +} + +void obj::ObjectsGUI::preview(obj::Object* obj) { + if (NDO_CAST(obj::LinkObject, obj)) { + NDO_CASTV(obj::LinkObject, obj, linko); + + bool no_link_preview = !linko->getLink(); + tp::alni max_depth = 5; + tp::alni depth_count = 0; + tp::Map link_lookup; + obj::LinkObject* link_iter = linko; + while (link_iter && link_iter->getLink() && !no_link_preview) { + link_iter = NDO_CAST(obj::LinkObject, link_iter->getLink()); + depth_count++; + + if (link_lookup.presents(tp::alni(link_iter))) { + no_link_preview = true; + } + else { + link_lookup.put(tp::alni(link_iter), 0); + } + no_link_preview |= max_depth < depth_count; + } + + if (linko->getLink()) { + if (!no_link_preview) { + ImGui::Text("=> "); + ImGui::SameLine(); + preview(linko->getLink()); + } + else { + ImGui::Text("Max preview depth exceeded"); + } + } + else { + ImGui::Text("Link Is Null"); + } + } + else if (NDO_CAST(obj::IntObject, obj)) { + tp::alni& val = NDO_CAST(obj::IntObject, obj)->val; + int gui_val = int(val); + ImGui::InputInt(" ", &gui_val); + val = tp::alni(gui_val); + } + else if (NDO_CAST(obj::StringObject, obj)) { + NDO_CASTV(obj::StringObject, obj, stringo); + static char val[2048] = { " " }; + if (stringo->val != val) { + assert(tp::String::Logic::calcLength(stringo->val.read()) < 2048); + tp::memCopy(val, stringo->val.read(), stringo->val.size() + 1); + } + ImGui::InputText("", val, 2048); + if (stringo->val != val) { + stringo->val = val; + } + } + else if (NDO_CAST(obj::BoolObject, obj)) { + boolView((obj::BoolObject*)obj); + } + else if (NDO_CAST(obj::FloatObject, obj)) { + tp::alnf& val = NDO_CAST(obj::FloatObject, obj)->val; + auto gui_val = float(val); + ImGui::InputFloat(" ", &gui_val); + val = tp::alnf(gui_val); + + } + else if (NDO_CAST(obj::EnumObject, obj)) { + enumView((obj::EnumObject*)obj); + } + else if (NDO_CAST(obj::ColorObject, obj)) { + colorView((obj::ColorObject*)obj); + } + else { + ImGui::Text(obj->type->name); ImGui::SameLine(); + ImGui::Text(" (No Preview) "); + } +} + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::interpreterView(obj::InterpreterObject* self) { + using namespace ImGui; + + auto& interp = self->mInterpreter; + + // not running state + if (interp.finished()) { + Text("State: Not Runnig"); + + if (Selectable("Debug")) { + self->debug(); + } + + auto res = ObjectsGUI::classView(self); + if (res) { + return res; + } + + return {}; + } + + // running state + BeginChild("dockable"); { + auto id = ImGui::GetCurrentWindow()->ID; + DockSpace(id); + } EndChild(); + + Begin("ByteCodeView"); { + + if (Button("Step")) { + interp.stepBytecode(); + if (interp.finished()) { + End(); + return {}; + } + } + + SameLine(); + if (Button("Step In")) { + interp.stepBytecodeIn(); + if (interp.finished()) { + End(); + return {}; + } + } + + SameLine(); + if (Button("Step out")) { + interp.stepBytecodeOut(); + if (interp.finished()) { + End(); + return {}; + } + } + + BeginChild("frame", { 0, 0 }, 0, ImGuiWindowFlags_NoBackground); + + const auto bytecode = interp.mCallStack.getBytecode(); + tp::halni idx = 0; + + for (auto ip = 0; ip < bytecode->mInstructions.size(); ) { + auto opcode = bytecode->mInstructions[ip]; + auto info = obj::gOpcodeInfos.fetch(opcode); + PushID(info.name); + + TextColored(ImVec4(1.f, 1.f, 1.f, 0.5f), "%i", idx); SameLine(); + if (bytecode->mInstructionIdx == ip) { + TextColored(ImVec4(1.f, 0.5f, 0.5f, 1.f), info.name); + } + else { + Text(info.name); + } + + // INFO + auto hd = HoverPopupBegin(tp::String((tp::alni)ip).read(), { 400, 250 }); + if (hd) { + Text(info.desc); + if (info.operands.len) { + Text("Operands :"); + for (auto i = 0; i < info.operands.len; i++) { + auto op = info.operands.buff[i]; + Text(" %i : %s : %s", i, op.obj_type, op.desc); + } + } + if (info.params.len) { + Text("Params : "); + for (auto i = 0; i < info.params.len; i++) { + auto param = info.params.buff[i]; + Text(" %i : %i bytes : %s ", i, param.bytes, param.desc); + } + } + } + HoverPopupEnd(hd); + + PopID(); + ip += info.opsize(); + idx++; + } + + EndChild(); + } End(); + + Begin("SourceCodeView"); { + stringView(interp.mCallStack.mStack.last().mMethod->mScript->mReadable); + } End(); + + Begin("OperandStack"); { + if (!interp.mOperandsStack.mIdx) { + Text("No Operands"); + } + for (auto i = 0; i < interp.mOperandsStack.mIdx; i++) { + auto operand = interp.mOperandsStack.mBuff[i]; + tp::alni operand_val = (tp::alni)operand; + + if (operand_val == NULL) { + Text("NULL"); + } + else if (tp::uint2(operand_val) == NULL) { + Text("2 BYTE VAL : %i", tp::uint2(operand_val)); + } + else { + if (Selectable(operand->type->name, false, 0, ImVec2(100, 0))) { + End(); + return { operand, "operand" }; + } + SameLine(); + + PushID((tp::alni)operand); + preview(operand); + PopID(); + } + } + } End(); + + Begin("ScopeStack"); { + for (auto i = 0; i < interp.mScopeStack.mIdx; i++) { + if (TreeNode(tp::String((tp::alni)i).read())) { + + auto& scope = interp.mScopeStack.mBuff[i]; + + if (TreeNode("Locals")) { + for (auto local : scope.mLocals) { + if (Selectable(local->key.read(), false, 0, ImVec2(100, 0))) { + TreePop(); + TreePop(); + End(); + return { local->val, local->key }; + } + + PushID(local->key.read()); + SameLine(); + preview(local->val); + PopID(); + } + TreePop(); + } + + if (TreeNode("Temps")) { + tp::alni idx = 0; + for (auto tmp : scope.mTemps) { + if (Selectable(tp::String(idx).read(), false, 0, ImVec2(100, 0))) { + TreePop(); + TreePop(); + End(); + return { tmp.data(), "temp" }; + } + idx++; + } + TreePop(); + } + TreePop(); + } + } + } End(); + + Begin("CallStack"); { + for (auto i = 0; i < interp.mCallStack.mStack.size(); i++) { + auto method = interp.mCallStack.mStack[i].mMethod; + PushID(i); + if (Selectable("method")) { + PopID(); + End(); + return { method, "call stack method" }; + } + PopID(); + } + } End(); + + Begin("ConstPool"); { + auto bc = interp.mCallStack.getBytecode(); + tp::alni idx = 0; + for (auto const_obj : bc->mConstants) { + PushID(idx); + if (Button(const_obj.data()->type->name)) { + End(); + PopID(); + return {const_obj.data(), tp::String(idx)}; + } + SameLine(); + preview(const_obj.data()); + PopID(); + idx++; + } + } End(); + + return {}; +} + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::colorView(obj::ColorObject* in) { + ImGui::ColorEdit4(" ", &in->mCol.r); + return {}; +} + + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::enumView(obj::EnumObject* obj) { + + if (!obj->entries) { + ImGui::Text("enum is uninitialized"); + return {}; + } + + if (ImGui::BeginCombo(" ", obj->getActiveName())) { + + for (tp::uhalni idx = 0; idx < obj->nentries; idx++) { + if (ImGui::Selectable(obj->getItemName(idx))) { + obj::NDO->set(obj, tp::alni(idx)); + } + } + + ImGui::EndCombo(); + } + + return {}; +} + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::boolView(obj::BoolObject* obj) { + tp::alni& val = obj->val; + bool gui_val = bool(val); + ImGui::Checkbox(gui_val ? "True" : "False", &gui_val); + val = tp::alni(gui_val); + return {}; +} + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::floatView(obj::FloatObject* obj) { + tp::alnf& val = obj->val; + float gui_val = float(val); + ImGui::InputFloat("Value", &gui_val); + val = tp::alnf(gui_val); + return {}; +} + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::nullView(obj::NullObject* in) { + ImGui::Text("Null Object."); + return {}; +} + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::linkoView(obj::LinkObject* obj) { + + if (obj->getLink()) { + + ImGui::Text("%s at %x", obj->getLink()->type->name, obj->getLink()); + + if (ImGui::Selectable("View")) { + return { obj->getLink(), "adress" }; + } + } + else { + ImGui::Text("Link Is Null"); + } + + if (ImGui::Selectable("Set from clipboard")) { + obj->setLink(mClipboard); + } + + if (ImGui::Selectable("Copy value")) { + setClipboard(obj->getLink()); + } + if (ImGui::Selectable("Set Null")) { + obj->setLink(NULL); + } + + return {}; +} + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::intoView(obj::IntObject* obj) { + ImGui::Text("Int Value: "); ImGui::SameLine(); + int val = (int)obj->val; + ImGui::InputInt(" ", &val); + obj->val = (tp::alni)val; + return {}; +} + +void obj::ObjectsGUI::dictViewDrawCreate(obj::DictObject* dict) { + if (ImGui::BeginPopupContextItem("child_2", ImGuiPopupFlags_MouseButtonRight)) { + + if (mClipboard) { + if (ImGui::Selectable("Paste")) { + tp::alni idx = 1; + tp::String name_base = tp::String("clipboard ") + tp::String(mClipboard->type->name) + tp::String(" "); + tp::String name_out = name_base; + + while (dict->presents(name_out)) { + name_out = name_base + tp::String(idx); + idx++; + } + + dict->put(name_out, mClipboard); + } + } + + if (ImGui::BeginMenu("Create")) { + + obj::Object* newo = imgui_object_create_menu(); + + if (newo) { + tp::alni idx = 1; + tp::String name_base = tp::String("new ") + tp::String(newo->type->name) + tp::String(" "); + tp::String name_out = name_base; + + while (dict->presents(name_out)) { + name_out = name_base + tp::String(idx); + idx++; + } + + dict->put(name_out, newo); + } + + ImGui::EndMenu(); + } + + ImGui::EndPopup(); + } +} + +void obj::ObjectsGUI::dictViewEdit(obj::DictObject* dict, tp::String key, obj::Object* obj, bool& popup) { + if (ImGui::BeginPopupContextItem(key.read(), ImGuiPopupFlags_MouseButtonRight)) { + popup = true; + + ImGui::Text("%s at %x", obj->type->name, obj); + + if (key.size() > 100) { + ImGui::Text("name is too large"); + } + else { + + if (mLastNameEditObject != obj) { + tp::memCopy(mNameEdit, key.read(), key.size() + 1); + mLastNameEditObject = obj; + } + + if (ImGui::InputTextEx(" ", "new name", mNameEdit, 100, { 140 , 30 }, ImGuiInputTextFlags_EnterReturnsTrue)) { + auto idx = dict->presents(mNameEdit); + if (bool(idx)) { + //Notify("Object with such name Already Exists"); + } + else { + obj::NDO->refinc(obj); + dict->remove(key); + auto id = tp::String(mNameEdit); + dict->put(id, obj); + obj::NDO->destroy(obj); + } + } + } + + if (ImGui::Selectable("Remove")) { + dict->remove(key); + } + + if (ImGui::Selectable("Copy Link")) { + setClipboard(obj); + } + + ImGui::EndPopup(); + } +} + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::dictView(obj::DictObject* obj) { + bool popup = false; + auto table_flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable; + + ImGui::BeginChild("frame", { 0, 0 }, 0, ImGuiWindowFlags_NoBackground); { + if (!obj->getItems().size()) { + ImGui::Text("Dictinary Is Empty. "); + } + + if (ImGui::BeginTable("Members", 2, table_flags)) { + ImGui::TableSetupColumn("name"); + ImGui::TableSetupColumn("info"); + for (auto childo : obj->getItems()) { + + ImGui::TableNextRow(0, 30); + ImGui::TableSetColumnIndex(0); + + if (ImGui::Selectable(childo->key.read())) { + ImGui::EndTable(); + ImGui::EndChild(); + return { childo->val, { tp::String(childo->val->type->name) + tp::String(" ") + childo->key } }; + } + + dictViewEdit(obj, childo->key, childo->val, popup); + + ImGui::TableSetColumnIndex(1); + ImGui::PushID((int)childo->key.read()[0]); + preview(childo->val); + ImGui::PopID(); + + } + ImGui::EndTable(); + } + } ImGui::EndChild(); + + if (!popup) { + dictViewDrawCreate(obj); + } + + return {}; +} + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::listView(obj::ListObject* obj) { + bool popup = false; + ViewStackNode out; + + if (!obj->getItems().length()) { + ImGui::Text("List Is Empty. "); + } + + ImGui::BeginChild("frame", { 0, 0 }, 0, ImGuiWindowFlags_NoBackground); + + if (ImGui::BeginTable("Items", 2)) { + ImGui::TableSetupColumn("type", ImGuiTableColumnFlags_WidthFixed, 120.0f); + ImGui::TableSetupColumn("info"); + + tp::alni idx = 0; + for (auto childo : obj->getItems()) { + ImGui::TableNextRow(0, 36); + + ImGui::TableSetColumnIndex(0); + if (ImGui::Selectable(tp::String(idx).read())) { + out = ViewStackNode(childo.data(), { tp::String(childo->type->name) + tp::String("at") + tp::String(idx) } ); + break; + } + + { + if (ImGui::BeginPopupContextItem(tp::String(idx).read(), ImGuiPopupFlags_MouseButtonRight)) { + popup = true; + + ImGui::Text("%s at %x", childo->type->name, childo.data()); + + if (ImGui::Selectable("Remove")) { + obj->delNode(childo.node()); + ImGui::EndPopup(); + break; + } + + if (ImGui::Selectable("Copy Link")) { + setClipboard(childo.data()); + ImGui::EndPopup(); + break; + } + + if (childo.node()->prev && ImGui::Selectable("Move Up")) { + tp::swap(childo.node()->prev->data, childo.data()); + ImGui::EndPopup(); + break; + } + + if (childo.node()->next && ImGui::Selectable("Move Down")) { + tp::swap(childo.node()->next->data, childo.data()); + ImGui::EndPopup(); + break; + } + + ImGui::EndPopup(); + } + } + + ImGui::TableSetColumnIndex(1); + + ImGui::PushID((int)idx); + preview(childo.data()); + ImGui::PopID(); + + idx++; + } + ImGui::EndTable(); + } + + ImGui::EndChild(); + + if (!popup && ImGui::BeginPopupContextItem("child_2", ImGuiPopupFlags_MouseButtonRight)) { + + if (ImGui::Selectable("Paste")) { + obj->pushBack(mClipboard); + } + + if (ImGui::BeginMenu("Create")) { + + obj::Object* newo = imgui_object_create_menu(); + if (newo) { + obj->pushBack(newo); + } + ImGui::EndMenu(); + } + ImGui::EndPopup(); + } + + return out; +} + +void drawStrView(tp::String& in) { + static char val[2048] = { " " }; + + if (in != val) { + assert(tp::String::Logic::calcLength(in.read()) < 2048); + tp::memCopy(val, in.read(), in.size() + 1); + } + + ImGui::BeginChild("str_edit"); + ImGui::InputTextMultiline(" ", val, 2048, { ImGui::GetWindowWidth() , ImGui::GetWindowHeight() }); + ImGui::EndChild(); + + if (in != val) { + in = val; + } +} + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::stringView(obj::StringObject* in) { + drawStrView(in->val); + return {}; +} + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::classView(obj::ClassObject* self) { + + bool popup = false; + auto dict = self->members; + + ImGui::BeginChild("frame", { 0, 0 }, 0, ImGuiWindowFlags_NoBackground); + + if (!dict->getItems().size()) { + ImGui::Text("No Members"); + } + + auto table_flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable; + auto tree_flags = ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed; + ImGuiWindow* window = ImGui::GetCurrentWindow(); + + auto n_methods = 0; + for (auto childo : dict->getItems()) { + if (childo->val->type == &obj::MethodObject::TypeData) { + n_methods++; + } + } + + if (n_methods != dict->getItems().size() && ImGui::TreeNodeBehavior(window->GetID("Members"), tree_flags, "Members", 0)) { + if (ImGui::BeginTable("Members", 2, table_flags)) { + ImGui::TableSetupColumn("name"); + ImGui::TableSetupColumn("info"); + + tp::alni idx = 0; + for (auto childo : dict->getItems()) { + if (childo->val->type == &obj::MethodObject::TypeData) { + continue; + } + + ImGui::TableNextRow(0, 30); + ImGui::TableSetColumnIndex(0); + + if (ImGui::Selectable(childo->key.read())) { + ImGui::EndTable(); + ImGui::TreePop(); + ImGui::EndChild(); + return { childo->val, { tp::String(childo->val->type->name) + childo->key } }; + } + + dictViewEdit(dict, childo->key, childo->val, popup); + + ImGui::TableSetColumnIndex(1); + ImGui::PushID((int)idx); + preview(childo->val); + ImGui::PopID(); + + } + ImGui::EndTable(); + + idx++; + } + ImGui::TreePop(); + } + + if (n_methods && ImGui::TreeNodeBehavior(window->GetID("Methods"), tree_flags, "Methods", 0) ) { + for (auto childo : dict->getItems()) { + if (childo->val->type == &obj::MethodObject::TypeData) { + if (ImGui::Selectable(childo->key.read())) { + ImGui::TreePop(); + ImGui::EndChild(); + return { childo->val, { tp::String(childo->val->type->name) + childo->key } }; + } + dictViewEdit(dict, childo->key, childo->val, popup); + } + } + ImGui::TreePop(); + } + + ImGui::EndChild(); + + if (!popup) { + dictViewDrawCreate(dict); + } + + return {}; +} + +obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::methodView(obj::MethodObject* in) { + + if (in->mScript->mBytecode.mInstructions.size()) { + if (ImGui::Button("Recompile")) { + in->compile(); + } + + ImGui::SameLine(); + if (ImGui::Button("Execute")) { + obj::Interpreter interp; + interp.execAll(in); + } + + } + else { + if (ImGui::Button("Compile")) { + in->compile(); + } + } + + ImGui::SameLine(); + auto ret = stringView(in->mScript->mReadable); + + if (ret.obj) { + return ret; + } + + return {}; +} + +void obj::ObjectsGUI::explorer() { + + if (ImGui::Button("<")) { + cdup(); + } + + ImGui::SameLine(); + ImGui::BeginChild("child_path", { 0, 45 }, false, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_HorizontalScrollbar); + tp::List rev_path; + for (auto childo = mViewStack.last(); childo; childo = childo->prev) { + rev_path.pushBack(&childo->data); + } + + tp::alni idx = 0; + for (auto childo = rev_path.last(); childo; childo = childo->prev) { + ImGui::PushID((int)idx); + bool go_back = false; + if (childo == rev_path.last()) { + go_back = ImGui::Button(childo->data->id.read()); ImGui::SameLine(); + } + else { + go_back = ImGui::Button((childo->data->id).read()); ImGui::SameLine(); + } + ImGui::PopID(); + + if (ImGui::BeginPopupContextItem(NULL, ImGuiPopupFlags_MouseButtonRight)) { + + obj::Object* curretn_object = childo->data->obj; + ImGui::Text("%s at %x", curretn_object->type->name, curretn_object); + ImGui::Separator(); + + if (ImGui::Selectable("Copy Link")) { + setClipboard(curretn_object); + } + + if (ImGui::Selectable("Instantiate ")) { + setClipboard(obj::NDO->instatiate(curretn_object)); + //Notify("Object copied to clipboard"); + } + + ImGui::Separator(); + + static char path_str[100] = { "data.o\0" }; + static bool compressed = true; + ImGui::InputTextEx(" ", "save path", path_str, 100, { 100, 30 }, 0); + + bool save_object = ImGui::Button("Save Object"); + ImGui::SameLine(); ImGui::Checkbox("Compressed", &compressed); + bool load_object = ImGui::Button("Load Object"); + + if (save_object) { + obj::NDO->save(curretn_object, path_str, compressed); + //Notify("Object saved"); + } + + if (load_object) { + obj::Object* loadedo = obj::NDO->load(path_str); + if (loadedo) { + setClipboard(loadedo); + //Notify("Object copied to clipboard"); + } + else { + //Notify("Can't load Object"); + } + } + + ImGui::EndPopup(); + } + + if (go_back) { + while (&mViewStack.last()->data != childo->data) { + cdup(); + } + mActive = childo->data->obj; + ImGui::EndChild(); + return; + } + idx++; + } + ImGui::Text(" "); + ImGui::EndChild(); + + ImGui::Separator(); + + ViewStackNode new_active; + if (NDO_CAST(obj::NullObject, mActive)) { + new_active = nullView((obj::NullObject*)mActive); + } + else if (NDO_CAST(obj::LinkObject, mActive)) { + new_active = linkoView((obj::LinkObject*)mActive); + } + else if (NDO_CAST(obj::IntObject, mActive)) { + new_active = intoView((obj::IntObject*)mActive); + } + else if (NDO_CAST(obj::StringObject, mActive)) { + new_active = stringView((obj::StringObject*)mActive); + } + else if (NDO_CAST(obj::ListObject, mActive)) { + new_active = listView((obj::ListObject*)mActive); + } + else if (NDO_CAST(obj::DictObject, mActive)) { + new_active = dictView((obj::DictObject*)mActive); + } + else if (NDO_CAST(obj::InterpreterObject, mActive)) { + new_active = interpreterView((obj::InterpreterObject*)mActive); + } + else if (NDO_CAST(obj::ClassObject, mActive)) { + new_active = classView((obj::ClassObject*)mActive); + } + else if (NDO_CAST(obj::BoolObject, mActive)) { + new_active = boolView((obj::BoolObject*)mActive); + } + else if (NDO_CAST(obj::FloatObject, mActive)) { + new_active = floatView((obj::FloatObject*)mActive); + } + else if (NDO_CAST(obj::EnumObject, mActive)) { + new_active = enumView((obj::EnumObject*)mActive); + } + else if (NDO_CAST(obj::MethodObject, mActive)) { + new_active = methodView((obj::MethodObject*)mActive); + } + else if (NDO_CAST(obj::ColorObject, mActive)) { + new_active = colorView((obj::ColorObject*)mActive); + } + else { + ImGui::Text("Preview is Unavaliable"); + } + + if (new_active != NULL) { + cd(new_active.obj, new_active.id); + } +} + +void obj::ObjectsGUI::properties(const obj::ObjectType* type, bool top_of_tree_vew) { + + assert(type); + assert(mActive); + assert(mActive->type == type); + + ImGui::Text(" RefCount : %i", obj::NDO->getrefc(mActive)); + + ImGui::Text(" Type : %s", type->name); + + if (ImGui::TreeNode("Description ")) { + if (type->description) { + ImGui::Text(type->description); + } + else { + ImGui::Text("Description is not given"); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Size")) { + if (0 && ImGui::TreeNode("Top Level Type")) { + + ImGui::Text("RAM : "); + ImGui::Indent(); + ImGui::Text("Only Structure : %i bytes", type->size - (type->base ? type->base->size : 0)); + ImGui::Text("With Non-Object Links : Not Supported"); + ImGui::Unindent(); + + ImGui::Text("Disk :"); + ImGui::Indent(); + ImGui::Text("Only Structure : Currently Not Supported"); + ImGui::Text("With Object Links : Not Supported"); + ImGui::Unindent(); + + ImGui::TreePop(); + } + //if (ImGui::TreeNode("Full Type Hierarchy")) { + + ImGui::Text("RAM : "); + ImGui::Indent(); + ImGui::Text("Only Structure : %i bytes", type->size); + ImGui::Text("With Non-Object Links : %i bytes", obj::NDO->objsize_ram(mActive)); + ImGui::Text("Full Size Recursive : %i bytes", obj::NDO->objsize_ram_recursive(mActive)); + ImGui::Unindent(); + + ImGui::Text("Disk :"); + ImGui::Indent(); + ImGui::Text("Only Structure : %i bytes", obj::NDO->objsize_file(mActive)); + ImGui::Text("With Object Links : %i bytes", obj::NDO->objsize_file_recursive(mActive)); + ImGui::Unindent(); + + //ImGui::TreePop(); + //} + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Base Type")) { + if (type->base) { + properties(type->base, false); + } + else { + ImGui::Text("No base type"); + } + ImGui::TreePop(); + } +} + +void obj::ObjectsGUI::draw() { + if (!mShowDebugInfo) { + return; + } + + if (mViewStack.length()) { + if (ImGui::Begin("Explorer")) { + explorer(); + } + ImGui::End(); + + if (ImGui::Begin("Objet Info")) { + properties(mActive->type); + } + ImGui::End(); + + } + else { + ImGui::Text("ViewStack is Empty"); + } + + auto& io = ImGui::GetIO(); + mCaptureInput = (io.WantCaptureMouse || io.WantCaptureKeyboard); +} diff --git a/Objects/applications/GUI.h b/Objects/applications/GUI.h new file mode 100644 index 0000000..6297db6 --- /dev/null +++ b/Objects/applications/GUI.h @@ -0,0 +1,73 @@ + +#pragma once + +#include "primitives/primitives.h" +#include "primitives//interpreterobject.h" + +#include "compiler/function.h" + +#include "strings.h" + +namespace obj { + + class ObjectsGUI { + + enum { MAX_NAME_LENGHT = 102 }; + char mNameEdit [MAX_NAME_LENGHT]; + obj::Object* mLastNameEditObject = NULL; + + struct ViewStackNode { + obj::Object* obj; + tp::String id; + ViewStackNode() { obj = NULL; } + ViewStackNode(obj::Object* obj, tp::String id) : obj(obj), id(id) {} + operator bool() { return obj; } + }; + + tp::List mViewStack; + obj::Object* mRoot = NULL; + obj::Object* mActive = NULL; + obj::Object* mClipboard = NULL; + + void setClipboard(obj::Object*); + obj::Object* getClipboard(); + + void* mImGuiCtx = NULL; + + public: + + bool mShowDebugInfo = true; + bool mCaptureInput = false; + + ObjectsGUI(); + ~ObjectsGUI(); + + void cd(obj::Object* child, tp::String name); + void cdup(); + + void clearEvents(); + + void draw(); + void explorer(); + void properties(const obj::ObjectType*, bool top_of_tree_vew = true); + void drawFps(); + private: + + void preview(obj::Object* obj); + ViewStackNode enumView(obj::EnumObject* obj); + ViewStackNode boolView(obj::BoolObject* obj); + ViewStackNode floatView(obj::FloatObject* obj); + ViewStackNode nullView(obj::NullObject* obj); + ViewStackNode linkoView(obj::LinkObject* obj); + ViewStackNode intoView(obj::IntObject* obj); + ViewStackNode dictView(obj::DictObject* obj); + ViewStackNode listView(obj::ListObject* obj); + ViewStackNode stringView(obj::StringObject* in); + ViewStackNode classView(obj::ClassObject* in); + ViewStackNode methodView(obj::MethodObject* in); + ViewStackNode colorView(obj::ColorObject* in); + ViewStackNode interpreterView(obj::InterpreterObject* in); + void dictViewEdit(obj::DictObject* dict, tp::String item_id, obj::Object* obj, bool& popup); + void dictViewDrawCreate(obj::DictObject* dict); + }; +}; diff --git a/Objects/applications/GUIEntry.cpp b/Objects/applications/GUIEntry.cpp new file mode 100644 index 0000000..3323b16 --- /dev/null +++ b/Objects/applications/GUIEntry.cpp @@ -0,0 +1,50 @@ + +#include "NewPlacement.hpp" +#include "Window.hpp" + +#include "GUI.h" + +using namespace tp; +using namespace obj; + +class GUIWindow { + Window* window; + ObjectsGUI gui; + +public: + GUIWindow() { + tp::HeapAllocGlobal::startIgnore(); + window = Window::createWindow(1500, 900, "Objects GUI"); + tp::HeapAllocGlobal::stopIgnore(); + + gui.cd(NDO->create("dict"), "root"); + } + + void run() { + while (!window->shouldClose()) { + window->processEvents(); + gui.draw(); + window->draw(); + } + } + + ~GUIWindow() { + Window::destroyWindow(window); + } +}; + +int main() { + + tp::ModuleManifest* deps[] = { &gModuleObjects, &gModuleGraphics, nullptr }; + tp::ModuleManifest module("ObjectsTests", nullptr, nullptr, deps); + + if (module.initialize()) { + { + GUIWindow window; + window.run(); + } + module.deinitialize(); + } + + return 0; +} \ No newline at end of file diff --git a/Strings/public/StringLogic.hpp b/Strings/public/StringLogic.hpp index f66be01..b86baa5 100644 --- a/Strings/public/StringLogic.hpp +++ b/Strings/public/StringLogic.hpp @@ -26,42 +26,42 @@ namespace tp { return iter - in; } - static tChar* insertLogic(const tChar* cur, const tChar* tar, Index at, Index len) { + static void insertLogic(tChar* result, Index resultLen, const tChar* cur, const tChar* tar, Index at, Index len) { auto curLen = calcLength(cur); auto allLen = curLen + len; - auto* out = new tChar[allLen + 1]; + ASSERT(allLen <= resultLen); DEBUG_ASSERT(curLen >= 0) DEBUG_ASSERT(len >= 0) DEBUG_ASSERT(at < curLen + 1 && at >= 0) for (Index idx = 0; idx < at; idx++) { - out[idx] = cur[idx]; + result[idx] = cur[idx]; } for (Index idx = 0; idx < len; idx++) { - out[idx + at] = tar[idx]; + result[idx + at] = tar[idx]; } for (Index idx = at + len; idx < allLen; idx++) { - out[idx] = cur[idx - len]; + result[idx] = cur[idx - len]; } - out[allLen] = '\0'; - return out; + result[allLen] = '\0'; } // including end not including start - static tChar* removeLogic(const tChar* cur, Index start, Index end) { + static void removeLogic(tChar* result, Index resultLen, const tChar* cur, Index start, Index end) { auto curLen = calcLength(cur); auto rangeLen = end - start; auto newLen = curLen - rangeLen; - auto* out = new tChar[newLen + 1]; - out[newLen] = '\0'; + + ASSERT(newLen <= resultLen); + + result[newLen] = '\0'; for (Index idx = 0; idx < start; idx++) { - out[idx] = cur[idx]; + result[idx] = cur[idx]; } for (Index idx = end; idx < curLen; idx++) { - out[idx - rangeLen] = cur[idx]; + result[idx - rangeLen] = cur[idx]; } - return out; } static bool isEqualLogic(const tChar* left, const tChar* right) { diff --git a/Strings/public/Strings.hpp b/Strings/public/Strings.hpp index 9f61cfa..5bdf9f8 100644 --- a/Strings/public/Strings.hpp +++ b/Strings/public/Strings.hpp @@ -15,6 +15,7 @@ namespace tp { class StringData { friend StringTemplate; typedef StringLogic Logic; + typedef typename StringLogic::Index Index; private: uint2 mIsConst; // source is non-modifiable @@ -38,7 +39,7 @@ namespace tp { mEditedIdx = 0; } - explicit StringData(const tChar* aBuff) { + explicit StringData(tChar* aBuff) { MODULE_SANITY_CHECK(gModuleStrings) DEBUG_ASSERT(aBuff) auto const len = Logic::calcLength(aBuff); @@ -58,7 +59,7 @@ namespace tp { if (!mIsConst) delete[] mBuff; } - void resize(ualni size) { + void resize(Index size) { DEBUG_ASSERT(mReferenceCount == 1 && !mIsConst) delete[] mBuff; mBuff = new tChar[size + 1]; @@ -143,7 +144,7 @@ namespace tp { } // output will be null if in TextEditing mode - tChar* resize(uint1 size) { + tChar* resize(Index size) { makeModifiable(); mData->resize(size); return write(); @@ -231,6 +232,12 @@ namespace tp { Logic::calcLineOffsets(read(), size(), aOut); } + StringTemplate& operator=(tChar* in) { + this->~StringTemplate(); + new (this) StringTemplate(in); + return *this; + } + StringTemplate& operator=(const tChar* in) { this->~StringTemplate(); new (this) StringTemplate(in); @@ -250,6 +257,14 @@ namespace tp { return Logic::isEqualLogic(in.read(), read()); } + StringTemplate operator+(const StringTemplate& in) const { + StringTemplate out; + auto const newSize = in.size() + size(); + out.resize(newSize); + Logic::insertLogic(out.write(), newSize, read(), in.read(), size(), in.size()); + return out; + } + public: // Debugging [[nodiscard]] ualni getReferenceCount() const { return mData->mReferenceCount; } [[nodiscard]] bool getIsConstFlag() const { return mData->mIsConst; } diff --git a/Strings/tests/TestsStrings.cpp b/Strings/tests/TestsStrings.cpp index 70f29cb..5bdee31 100644 --- a/Strings/tests/TestsStrings.cpp +++ b/Strings/tests/TestsStrings.cpp @@ -9,6 +9,18 @@ struct TestStruct { String str = "test data"; }; +TEST_DEF_STATIC(Addition) { + String str1 = "abc"; + String str2 = "def"; + { + str1 + str2; + } + { + TEST(str1 + str2 == "abcdef"); + TEST(str1 + "aaaccc" == "abcaaaccc"); + } +} + TEST_DEF_STATIC(Simple) { String str; TEST(str.getIsConstFlag()); @@ -35,4 +47,5 @@ TEST_DEF_STATIC(Simple) { TEST_DEF(Strings) { testSimple(); + testAddition(); } \ No newline at end of file diff --git a/Strings/tests/TestsStringsLogic.cpp b/Strings/tests/TestsStringsLogic.cpp index 747f2ab..7de8051 100644 --- a/Strings/tests/TestsStringsLogic.cpp +++ b/Strings/tests/TestsStringsLogic.cpp @@ -33,78 +33,78 @@ TEST_DEF(calcLength) { TEST_DEF(insertLogic_emptyTarget) { // Test insertLogic function with an empty target string + char inserted[40] = { "" }; const char* cur = "Hello"; const char* tar = ""; const char* result = "Hello"; - char* inserted = Logic::insertLogic(cur, tar, 5, 0); + Logic::insertLogic(inserted, 40, cur, tar, 5, 0); TEST(Logic::isEqualLogic(inserted, result)); - delete[] inserted; } TEST_DEF(insertLogic_emptyCurrent) { // Test insertLogic function with an empty current string + char inserted[40] = { "" }; const char* cur = ""; const char* tar = "World"; const char* result = "World"; - char* inserted = Logic::insertLogic(cur, tar, 0, 5); + Logic::insertLogic(inserted, 40, cur, tar, 0, 5); TEST(Logic::isEqualLogic(inserted, result)); - delete[] inserted; } TEST_DEF(insertLogic_curLengthLessThanPos) { // Test insertLogic function with current length less than the insert position + char inserted[40] = { "" }; const char* cur = "Hello"; const char* tar = "World"; const char* result = "HelloWorld"; - char* inserted = Logic::insertLogic(cur, tar, 10, 5); + Logic::insertLogic(inserted, 40, cur, tar, 10, 5); TEST(Logic::isEqualLogic(inserted, result)); - delete[] inserted; } TEST_DEF(removeLogic_emptyCurrent) { // Test removeLogic function with an empty current string + char removed[40] = { "" }; const char* cur = ""; const char* result = ""; - char* removed = Logic::removeLogic(cur, 0, 0); + Logic::removeLogic(removed, 40, cur, 0, 0); TEST(Logic::isEqualLogic(removed, result)); - delete[] removed; } TEST_DEF(removeLogic_removeUntilEnd) { // Test removeLogic function by removing until the end of the current string + char removed[40] = { "" }; const char* cur = "HelloWorld"; const char* result = "World"; - char* removed = Logic::removeLogic(cur, 0, 5); + Logic::removeLogic(removed, 40, cur, 0, 5); TEST(Logic::isEqualLogic(removed, result)); - delete[] removed; } TEST_DEF(removeLogic_removeMiddleCharacters) { // Test removeLogic function by removing characters in the middle of the current string + char removed[40] = { "" }; const char* cur = "HelloWorld"; const char* result = "Helrld"; - char* removed = Logic::removeLogic(cur, 3, 7); + Logic::removeLogic(removed, 40, cur, 3, 7); TEST(Logic::isEqualLogic(removed, result)); - delete[] removed; } TEST_DEF(insertLogicGood) { // Test insertLogic function + char inserted[40] = { "" }; const char* cur = "Hello"; const char* tar = "World"; const char* result = "HelloWorld"; - char* inserted = Logic::insertLogic(cur, tar, 5, 5); + Logic::insertLogic(inserted, 40, cur, tar, 5, 5); TEST(Logic::isEqualLogic(inserted, result)); - delete[] inserted; } TEST_DEF(removeLogicGood) { // Test removeLogic function + char removed[40] = { "" }; const char* cur = "HelloWorld"; const char* result = "Helo"; - char* removed = Logic::removeLogic(cur, 3, 8); + Logic::removeLogic(removed, 40, cur, 3, 8); TEST(Logic::isEqualLogic(removed, result)); - delete[] removed; } diff --git a/TODO b/TODO index a57da84..bff087b 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,13 @@ Testing !! +Graphics: + Window event system + Graphics API + FPS count & Performance control + Objects: + Debug GUI + use anonymous namespaces for object static methods write tests before refactor !! Alloc Size queries remove obj_ref_count macro @@ -10,11 +17,6 @@ Objects: remove tp:: rename classes -Graphics: - Window event system - Graphics API - FPS count & Performance control - Containers: Test generatePermutations Add variant size buffer