From fde531e7c44ea917f745a9f800178fbe83fa19b5 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Mon, 22 Nov 2021 19:44:48 -0500 Subject: [PATCH] more refactor; draw samples grid and cursor; gen load fixes --- Makefile | 2 +- source/circular.hpp | 32 ++++ source/device.cpp | 151 ++++++++------- source/device_formula.cpp | 12 +- source/file.cpp | 6 +- source/gui.cpp | 6 +- source/gui_device.cpp | 129 +++++++++---- source/imgui/TextEditor.cpp | 356 +----------------------------------- source/imgui/TextEditor.h | 6 - source/imgui/imgui.h | 6 +- source/logview.cpp | 82 +++++++++ source/logview.h | 80 +------- source/main.cpp | 143 ++++++++------- 13 files changed, 389 insertions(+), 622 deletions(-) create mode 100644 source/circular.hpp create mode 100644 source/logview.cpp diff --git a/Makefile b/Makefile index 26e0208..81e580d 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ $(OUTPUT): $(OFILES) clean: @echo " CLEAN" - @rm $(OFILES) $(OUTPUT) + @rm -f $(OFILES) $(OUTPUT) %.o: %.cpp @echo " CXX " $< diff --git a/source/circular.hpp b/source/circular.hpp new file mode 100644 index 0000000..33b8ee0 --- /dev/null +++ b/source/circular.hpp @@ -0,0 +1,32 @@ +#ifndef CIRCULAR_HPP +#define CIRCULAR_HPP + +#include + +template class Container, typename T> +class CircularBuffer +{ +public: + CircularBuffer(Container& container) : + m_begin(std::begin(container)), + m_end(std::end(container)), + m_current(std::begin(container)) {} + + void put(const T& value) noexcept { + *m_current = value; + if (++m_current == m_end) + m_current = m_begin; + } + + std::size_t size() const noexcept { + return std::distance(m_begin, m_end); + } + +private: + Container::iterator m_begin; + Container::iterator m_end; + Container::iterator m_current; +}; + +#endif // CIRCULAR_HPP + diff --git a/source/device.cpp b/source/device.cpp index df3f361..abcc88a 100644 --- a/source/device.cpp +++ b/source/device.cpp @@ -11,10 +11,12 @@ #include "stmdsp.hpp" +#include "circular.hpp" #include "imgui.h" #include "wav.hpp" #include +#include #include #include #include @@ -30,7 +32,7 @@ extern std::string tempFileName; extern void log(const std::string& str); -extern std::vector deviceGenLoadFormulaEval(const std::string_view); +extern std::vector deviceGenLoadFormulaEval(const std::string&); std::shared_ptr m_device; @@ -62,14 +64,16 @@ static std::vector tryReceiveChunk( std::shared_ptr device, auto readFunc) { - int tries = -1; - do { + for (int tries = 0; tries < 100; ++tries) { + if (!device->is_running()) + break; + const auto chunk = readFunc(device.get()); if (!chunk.empty()) return chunk; else std::this_thread::sleep_for(std::chrono::microseconds(20)); - } while (++tries < 100 && device->is_running()); + } return {}; } @@ -94,15 +98,13 @@ static void drawSamplesTask(std::shared_ptr device) const auto bufferTime = getBufferPeriod(device); - std::unique_lock lockDraw (mutexDrawSamples, std::defer_lock); - std::unique_lock lockDevice (mutexDeviceLoad, std::defer_lock); - - auto addToQueue = [&lockDraw](auto& queue, const auto& chunk) { - lockDraw.lock(); + const auto addToQueue = [](auto& queue, const auto& chunk) { + std::scoped_lock lock (mutexDrawSamples); std::copy(chunk.cbegin(), chunk.cend(), std::back_inserter(queue)); - lockDraw.unlock(); }; + std::unique_lock lockDevice (mutexDeviceLoad, std::defer_lock); + while (device && device->is_running()) { const auto next = std::chrono::high_resolution_clock::now() + bufferTime; @@ -112,7 +114,7 @@ static void drawSamplesTask(std::shared_ptr device) lockDevice.unlock(); addToQueue(drawSamplesQueue, chunk); - if (logSamplesFile.good()) { + if (logSamplesFile.is_open()) { for (const auto& s : chunk) logSamplesFile << s << '\n'; } @@ -145,29 +147,29 @@ static void feedSigGenTask(std::shared_ptr device) std::vector wavBuf (device->get_buffer_size() * 2, 2048); - std::unique_lock lockDevice (mutexDeviceLoad, std::defer_lock); + { + std::scoped_lock lock (mutexDeviceLoad); + device->siggen_upload(wavBuf.data(), wavBuf.size()); + device->siggen_start(); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } - lockDevice.lock(); - device->siggen_upload(wavBuf.data(), wavBuf.size()); wavBuf.resize(wavBuf.size() / 2); - device->siggen_start(); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - lockDevice.unlock(); - std::vector wavIntBuf (wavBuf.size()); while (device->is_siggening()) { const auto next = std::chrono::high_resolution_clock::now() + delay; wavOutput.next(wavIntBuf.data(), wavIntBuf.size()); - auto src = wavIntBuf.cbegin(); - std::generate(wavBuf.begin(), wavBuf.end(), - [&src] { return static_cast(*src++ / 16 + 2048); }); + std::transform(wavIntBuf.cbegin(), wavIntBuf.cend(), + wavBuf.begin(), + [](auto i) { return static_cast(i / 16 + 2048); }); - lockDevice.lock(); - while (!device->siggen_upload(wavBuf.data(), wavBuf.size())) - std::this_thread::sleep_for(uploadDelay); - lockDevice.unlock(); + { + std::scoped_lock lock (mutexDeviceLoad); + while (!device->siggen_upload(wavBuf.data(), wavBuf.size())) + std::this_thread::sleep_for(uploadDelay); + } std::this_thread::sleep_until(next); } @@ -179,10 +181,9 @@ static void statusTask(std::shared_ptr device) return; while (device->connected()) { - std::unique_lock lockDevice (mutexDeviceLoad, std::defer_lock); - lockDevice.lock(); + mutexDeviceLoad.lock(); const auto [status, error] = device->get_status(); - lockDevice.unlock(); + mutexDeviceLoad.unlock(); if (error != stmdsp::Error::None) { switch (error) { @@ -214,7 +215,7 @@ void deviceLoadAudioFile(const std::string& file) void deviceLoadLogFile(const std::string& file) { logSamplesFile = std::ofstream(file); - if (logSamplesFile.good()) + if (logSamplesFile.is_open()) log("Log file ready."); else log("Error: Could not open log file."); @@ -261,7 +262,7 @@ bool deviceConnect() if (!m_device) { stmdsp::scanner scanner; - if (auto devices = scanner.scan(); !devices.empty()) { + if (const auto devices = scanner.scan(); !devices.empty()) { try { m_device.reset(new stmdsp::device(devices.front())); } catch (...) { @@ -307,7 +308,7 @@ void deviceStart(bool measureCodeTime, bool logResults, bool drawSamples) std::this_thread::sleep_for(std::chrono::microseconds(150)); m_device->continuous_stop(); } - if (logSamplesFile.good()) { + if (logSamplesFile.is_open()) { logSamplesFile.close(); log("Log file saved and closed."); } @@ -329,12 +330,9 @@ void deviceAlgorithmUpload() { if (!m_device) { log("No device connected."); - return; } else if (m_device->is_running()) { - return; - } - - if (std::ifstream algo (tempFileName + ".o"); algo.good()) { + log("Cannot upload algorithm while running."); + } else if (std::ifstream algo (tempFileName + ".o"); algo.is_open()) { std::ostringstream sstr; sstr << algo.rdbuf(); auto str = sstr.str(); @@ -350,7 +348,9 @@ void deviceAlgorithmUnload() { if (!m_device) { log("No device connected."); - } else if (!m_device->is_running()) { + } else if (m_device->is_running()) { + log("Cannot unload algorithm while running."); + } else { m_device->unload_filter(); log("Algorithm unloaded."); } @@ -361,85 +361,82 @@ void deviceGenLoadList(const std::string_view list) std::vector samples; auto it = list.cbegin(); - while (it != list.cend() && samples.size() < stmdsp::SAMPLES_MAX * 2) { - const auto end = list.find_first_not_of("0123456789", - std::distance(list.cbegin(), it)); - const auto itend = end != std::string_view::npos ? list.cbegin() + end - : list.cend(); + while (it != list.cend()) { + const auto itend = std::find_if(it, list.cend(), + [](char c) { return !isdigit(c); }); + unsigned long n; - const auto [ptr, ec] = std::from_chars(it, itend, n); - if (ec != std::errc()) + const auto ec = std::from_chars(it, itend, n).ec; + if (ec != std::errc()) { + log("Error: Bad data in sample list."); + break; + } else if (n > 4095) { + log("Error: Sample data value larger than max of 4095."); break; + } else { + samples.push_back(n & 4095); + if (samples.size() >= stmdsp::SAMPLES_MAX * 2) { + log("Error: Too many samples for signal generator."); + break; + } + } - samples.push_back(n & 4095); it = itend; } - if (samples.size() <= stmdsp::SAMPLES_MAX * 2) { + if (it == list.cend()) { // DAC buffer must be of even size if (samples.size() % 2 != 0) samples.push_back(samples.back()); - if (m_device) - m_device->siggen_upload(samples.data(), samples.size()); + m_device->siggen_upload(samples.data(), samples.size()); log("Generator ready."); - } else { - log("Error: Too many samples for signal generator."); } } -void deviceGenLoadFormula(std::string_view formula) +void deviceGenLoadFormula(const std::string& formula) { auto samples = deviceGenLoadFormulaEval(formula); if (!samples.empty()) { - if (m_device) - m_device->siggen_upload(samples.data(), samples.size()); - + m_device->siggen_upload(samples.data(), samples.size()); log("Generator ready."); } else { log("Error: Bad formula."); } } -void pullFromQueue( +std::size_t pullFromQueue( std::deque& queue, - std::vector& buffer, - decltype(buffer.begin())& bufferCursor, + CircularBuffer& circ, double timeframe) { - if (buffer.size() != drawSamplesBufferSize) { - buffer.resize(drawSamplesBufferSize); - bufferCursor = buffer.begin(); - } + if (circ.size() != drawSamplesBufferSize) + return drawSamplesBufferSize; std::scoped_lock lock (mutexDrawSamples); - auto count = drawSamplesBufferSize / (60. * timeframe) * 1.025; - count = std::min(drawSamplesInputQueue.size(), - static_cast(count)); - for (auto i = count; i; --i) { - *bufferCursor = queue.front(); + const auto desiredCount = drawSamplesBufferSize / (60. * timeframe) * 1.025; + auto count = std::min(queue.size(), static_cast(desiredCount)); + while (count--) { + circ.put(queue.front()); queue.pop_front(); - - if (++bufferCursor == buffer.end()) - bufferCursor = buffer.begin(); } + + return 0; } -void pullFromDrawQueue( - std::vector& buffer, - decltype(buffer.begin())& bufferCursor, +std::size_t pullFromDrawQueue( + CircularBuffer& circ, double timeframe) { - pullFromQueue(drawSamplesQueue, buffer, bufferCursor, timeframe); + return pullFromQueue(drawSamplesQueue, circ, timeframe); } -void pullFromInputDrawQueue( - std::vector& buffer, - decltype(buffer.begin())& bufferCursor, +std::size_t pullFromInputDrawQueue( + CircularBuffer& circ, double timeframe) { - pullFromQueue(drawSamplesInputQueue, buffer, bufferCursor, timeframe); + return pullFromQueue(drawSamplesInputQueue, circ, timeframe); } diff --git a/source/device_formula.cpp b/source/device_formula.cpp index 5c1ca16..c94eab7 100644 --- a/source/device_formula.cpp +++ b/source/device_formula.cpp @@ -5,7 +5,7 @@ #include #include -std::vector deviceGenLoadFormulaEval(const std::string_view formulaString) +std::vector deviceGenLoadFormulaEval(const std::string& formulaString) { double x = 0; @@ -16,13 +16,17 @@ std::vector deviceGenLoadFormulaEval(const std::string_view symbol_table.add_variable("x", x); symbol_table.add_constants(); expression.register_symbol_table(symbol_table); - parser.compile(std::string(formulaString), expression); + parser.compile(formulaString, expression); std::vector samples (stmdsp::SAMPLES_MAX); - std::generate(samples.begin(), samples.end(), - [&] { ++x; return static_cast(expression.value()); }); + auto genFun = [&x, &expression] { + stmdsp::dacsample_t s = expression.value(); + ++x; + return s; + }; + std::generate(samples.begin(), samples.end(), genFun); return samples; } diff --git a/source/file.cpp b/source/file.cpp index dfd9148..a5ef1d8 100644 --- a/source/file.cpp +++ b/source/file.cpp @@ -26,6 +26,8 @@ #include #include +#include + extern TextEditor editor; extern void log(const std::string& str); @@ -133,8 +135,8 @@ void fileRenderMenu() ImGui::Separator(); if (ImGui::MenuItem("Quit")) { - extern bool done; - done = true; + SDL_Event quitEvent (SDL_QUIT); + SDL_PushEvent(&quitEvent); } ImGui::EndMenu(); diff --git a/source/gui.cpp b/source/gui.cpp index 9720442..515d471 100644 --- a/source/gui.cpp +++ b/source/gui.cpp @@ -108,8 +108,10 @@ void guiRender(void (*func)()) SDL_GL_SwapWindow(window); } -void guiHandleEvents(bool& done) +bool guiHandleEvents() { + bool done = false; + for (SDL_Event event; SDL_PollEvent(&event);) { ImGui_ImplSDL2_ProcessEvent(&event); if (event.type == SDL_QUIT) @@ -117,6 +119,8 @@ void guiHandleEvents(bool& done) if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) done = true; } + + return done; } void guiShutdown() diff --git a/source/gui_device.cpp b/source/gui_device.cpp index 5399c8b..a1d0555 100644 --- a/source/gui_device.cpp +++ b/source/gui_device.cpp @@ -1,3 +1,4 @@ +#include "circular.hpp" #include "imgui.h" #include "imgui_internal.h" #include "ImGuiFileDialog.h" @@ -5,6 +6,7 @@ #include "stmdsp.hpp" #include +#include #include #include #include @@ -15,7 +17,7 @@ extern std::shared_ptr m_device; void deviceAlgorithmUnload(); void deviceAlgorithmUpload(); bool deviceConnect(); -void deviceGenLoadFormula(std::string_view list); +void deviceGenLoadFormula(const std::string& list); void deviceGenLoadList(std::string_view list); bool deviceGenStartToggle(); void deviceLoadAudioFile(const std::string& file); @@ -24,13 +26,11 @@ void deviceSetSampleRate(unsigned int index); void deviceSetInputDrawing(bool enabled); void deviceStart(bool measureCodeTime, bool logResults, bool drawSamples); void deviceUpdateDrawBufferSize(double timeframe); -void pullFromDrawQueue( - std::vector& buffer, - decltype(buffer.begin())& bufferCursor, +std::size_t pullFromDrawQueue( + CircularBuffer& circ, double timeframe); -void pullFromInputDrawQueue( - std::vector& buffer, - decltype(buffer.begin())& bufferCursor, +std::size_t pullFromInputDrawQueue( + CircularBuffer& circ, double timeframe); static std::string sampleRatePreview = "?"; @@ -56,11 +56,8 @@ void deviceRenderMenu() }; if (ImGui::BeginMenu("Run")) { - const bool isConnected = m_device ? true : false; - const bool isRunning = isConnected && m_device->is_running(); - static std::string connectLabel ("Connect"); - addMenuItem(connectLabel, !isConnected || !isRunning, [&] { + addMenuItem(connectLabel, !m_device || !m_device->is_running(), [&] { if (deviceConnect()) { connectLabel = "Disconnect"; sampleRatePreview = @@ -68,9 +65,15 @@ void deviceRenderMenu() deviceUpdateDrawBufferSize(drawSamplesTimeframe); } else { connectLabel = "Connect"; + measureCodeTime = false; + logResults = false; + drawSamples = false; } }); + const bool isConnected = m_device ? true : false; + const bool isRunning = isConnected && m_device->is_running(); + ImGui::Separator(); static std::string startLabel ("Start"); @@ -153,12 +156,11 @@ void deviceRenderToolbar() void deviceRenderWidgets() { - static std::string siggenInput; + static std::string siggenInput (32768, '\0'); static int siggenOption = 0; if (popupRequestSiggen) { popupRequestSiggen = false; - siggenInput.clear(); ImGui::OpenPopup("siggen"); } else if (popupRequestBuffer) { popupRequestBuffer = false; @@ -166,15 +168,19 @@ void deviceRenderWidgets() } else if (popupRequestLog) { popupRequestLog = false; ImGuiFileDialog::Instance()->OpenModal( - "ChooseFileLogGen", "Choose File", ".csv", "."); + "ChooseFileLog", "Choose File", ".csv", "."); } if (ImGui::BeginPopup("siggen")) { - if (ImGui::RadioButton("List", &siggenOption, 0)) - siggenInput.clear(); + if (ImGui::RadioButton("List", &siggenOption, 0)) { + siggenInput.resize(32768); + siggenInput[0] = '\0'; + } ImGui::SameLine(); - if (ImGui::RadioButton("Formula", &siggenOption, 1)) - siggenInput.clear(); + if (ImGui::RadioButton("Formula", &siggenOption, 1)) { + siggenInput.resize(1024); + siggenInput[0] = '\0'; + } ImGui::SameLine(); if (ImGui::RadioButton("Audio File", &siggenOption, 2)) siggenInput.clear(); @@ -183,7 +189,7 @@ void deviceRenderWidgets() if (ImGui::Button("Choose File")) { // This dialog will override the siggen popup, closing it. ImGuiFileDialog::Instance()->OpenModal( - "ChooseFileLogGen", "Choose File", ".wav", "."); + "ChooseFileGen", "Choose File", ".wav", "."); } } else { ImGui::Text(siggenOption == 0 ? "Enter a list of numbers:" @@ -201,10 +207,10 @@ void deviceRenderWidgets() if (ImGui::Button("Save")) { switch (siggenOption) { case 0: - deviceGenLoadList(siggenInput); + deviceGenLoadList(siggenInput.substr(0, siggenInput.find('\0'))); break; case 1: - deviceGenLoadFormula(siggenInput); + deviceGenLoadFormula(siggenInput.substr(0, siggenInput.find('\0'))); break; case 2: break; @@ -238,18 +244,27 @@ void deviceRenderWidgets() ImGui::EndPopup(); } - if (ImGuiFileDialog::Instance()->Display("ChooseFileLogGen", + if (ImGuiFileDialog::Instance()->Display("ChooseFileLog", ImGuiWindowFlags_NoCollapse, ImVec2(460, 540))) { if (ImGuiFileDialog::Instance()->IsOk()) { - auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); - auto ext = filePathName.substr(filePathName.size() - 4); + const auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); + deviceLoadLogFile(filePathName); + } else { + logResults = false; + } + + ImGuiFileDialog::Instance()->Close(); + } - if (ext.compare(".wav") == 0) - deviceLoadAudioFile(filePathName); - else if (ext.compare(".csv") == 0) - deviceLoadLogFile(filePathName); + if (ImGuiFileDialog::Instance()->Display("ChooseFileGen", + ImGuiWindowFlags_NoCollapse, + ImVec2(460, 540))) + { + if (ImGuiFileDialog::Instance()->IsOk()) { + const auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); + deviceLoadAudioFile(filePathName); } ImGuiFileDialog::Instance()->Close(); @@ -260,9 +275,9 @@ void deviceRenderDraw() { if (drawSamples) { static std::vector buffer; - static decltype(buffer.begin()) bufferCursor; static std::vector bufferInput; - static decltype(bufferInput.begin()) bufferInputCursor; + static auto bufferCirc = CircularBuffer(buffer); + static auto bufferInputCirc = CircularBuffer(bufferInput); static bool drawSamplesInput = false; static unsigned int yMinMax = 4095; @@ -295,16 +310,50 @@ void deviceRenderDraw() yMinMax = std::min(4095u, (yMinMax << 1) | 1); } - pullFromDrawQueue(buffer, bufferCursor, drawSamplesTimeframe); - if (drawSamplesInput) - pullFromInputDrawQueue(bufferInput, bufferInputCursor, drawSamplesTimeframe); + auto newSize = pullFromDrawQueue(bufferCirc, drawSamplesTimeframe); + if (newSize > 0) { + buffer.resize(newSize); + bufferCirc = CircularBuffer(buffer); + pullFromDrawQueue(bufferCirc, drawSamplesTimeframe); + } + + if (drawSamplesInput) { + auto newSize = pullFromInputDrawQueue(bufferInputCirc, drawSamplesTimeframe); + if (newSize > 0) { + bufferInput.resize(newSize); + bufferInputCirc = CircularBuffer(bufferInput); + pullFromInputDrawQueue(bufferInputCirc, drawSamplesTimeframe); + } + } auto drawList = ImGui::GetWindowDrawList(); ImVec2 p0 = ImGui::GetWindowPos(); auto size = ImGui::GetWindowSize(); p0.y += 65; size.y -= 70; - drawList->AddRectFilled(p0, {p0.x + size.x, p0.y + size.y}, IM_COL32(0, 0, 0, 255)); + drawList->AddRectFilled(p0, {p0.x + size.x, p0.y + size.y}, IM_COL32_BLACK); + + const auto lcMinor = ImGui::GetColorU32(IM_COL32(40, 40, 40, 255)); + const auto lcMajor = ImGui::GetColorU32(IM_COL32(140, 140, 140, 255)); + + { + const float yinc = (3. / 3.3) * size.y / 12.f; + const float center = p0.y + size.y / 2; + drawList->AddLine({p0.x, center}, {p0.x + size.x, center}, ImGui::GetColorU32(IM_COL32_WHITE)); + for (int i = 1; i < 7; ++i) { + drawList->AddLine({p0.x, center + i * yinc}, {p0.x + size.x, center + i * yinc}, (i % 2) ? lcMinor : lcMajor); + drawList->AddLine({p0.x, center - i * yinc}, {p0.x + size.x, center - i * yinc}, (i % 2) ? lcMinor : lcMajor); + } + } + { + const float xinc = size.x / 16.f; + const float center = p0.x + size.x / 2; + drawList->AddLine({center, p0.y}, {center, p0.y + size.y}, ImGui::GetColorU32(IM_COL32_WHITE)); + for (int i = 1; i < 8; ++i) { + drawList->AddLine({center + i * xinc, p0.y}, {center + i * xinc, p0.y + size.y}, (i % 2) ? lcMinor : lcMajor); + drawList->AddLine({center - i * xinc, p0.y}, {center - i * xinc, p0.y + size.y}, (i % 2) ? lcMinor : lcMajor); + } + } const float di = static_cast(buffer.size()) / size.x; const float dx = std::ceil(size.x / static_cast(buffer.size())); @@ -334,6 +383,18 @@ void deviceRenderDraw() } } + const auto mouse = ImGui::GetMousePos(); + if (mouse.x > p0.x && mouse.x < p0.x + size.x && + mouse.y > p0.y && mouse.y < p0.y + size.y) + { + const std::size_t si = (mouse.x - p0.x) / size.x * buffer.size(); + const float s = buffer[si] / 4095.f * 6.6f - 3.3f; + char buf[12]; + snprintf(buf, 16, " %1.3fV", s); + drawList->AddLine({mouse.x, p0.y}, {mouse.x, p0.y + size.y}, IM_COL32(255, 255, 0, 255)); + drawList->AddText(ImGui::GetMousePos(), IM_COL32(210, 210, 0, 255), buf); + } + ImGui::End(); } } diff --git a/source/imgui/TextEditor.cpp b/source/imgui/TextEditor.cpp index 02966f0..b45a21e 100644 --- a/source/imgui/TextEditor.cpp +++ b/source/imgui/TextEditor.cpp @@ -50,7 +50,7 @@ TextEditor::TextEditor() , mStartTime(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) { SetPalette(GetDarkPalette()); - SetLanguageDefinition(LanguageDefinition::HLSL()); + SetLanguageDefinition(LanguageDefinition::CPlusPlus()); mLines.push_back(Line()); } @@ -2804,357 +2804,3 @@ const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::CPlusPlus( return langDef; } -const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::HLSL() -{ - static bool inited = false; - static LanguageDefinition langDef; - if (!inited) - { - static const char* const keywords[] = { - "AppendStructuredBuffer", "asm", "asm_fragment", "BlendState", "bool", "break", "Buffer", "ByteAddressBuffer", "case", "cbuffer", "centroid", "class", "column_major", "compile", "compile_fragment", - "CompileShader", "const", "continue", "ComputeShader", "ConsumeStructuredBuffer", "default", "DepthStencilState", "DepthStencilView", "discard", "do", "double", "DomainShader", "dword", "else", - "export", "extern", "false", "float", "for", "fxgroup", "GeometryShader", "groupshared", "half", "Hullshader", "if", "in", "inline", "inout", "InputPatch", "int", "interface", "line", "lineadj", - "linear", "LineStream", "matrix", "min16float", "min10float", "min16int", "min12int", "min16uint", "namespace", "nointerpolation", "noperspective", "NULL", "out", "OutputPatch", "packoffset", - "pass", "pixelfragment", "PixelShader", "point", "PointStream", "precise", "RasterizerState", "RenderTargetView", "return", "register", "row_major", "RWBuffer", "RWByteAddressBuffer", "RWStructuredBuffer", - "RWTexture1D", "RWTexture1DArray", "RWTexture2D", "RWTexture2DArray", "RWTexture3D", "sample", "sampler", "SamplerState", "SamplerComparisonState", "shared", "snorm", "stateblock", "stateblock_state", - "static", "string", "struct", "switch", "StructuredBuffer", "tbuffer", "technique", "technique10", "technique11", "texture", "Texture1D", "Texture1DArray", "Texture2D", "Texture2DArray", "Texture2DMS", - "Texture2DMSArray", "Texture3D", "TextureCube", "TextureCubeArray", "true", "typedef", "triangle", "triangleadj", "TriangleStream", "uint", "uniform", "unorm", "unsigned", "vector", "vertexfragment", - "VertexShader", "void", "volatile", "while", - "bool1","bool2","bool3","bool4","double1","double2","double3","double4", "float1", "float2", "float3", "float4", "int1", "int2", "int3", "int4", "in", "out", "inout", - "uint1", "uint2", "uint3", "uint4", "dword1", "dword2", "dword3", "dword4", "half1", "half2", "half3", "half4", - "float1x1","float2x1","float3x1","float4x1","float1x2","float2x2","float3x2","float4x2", - "float1x3","float2x3","float3x3","float4x3","float1x4","float2x4","float3x4","float4x4", - "half1x1","half2x1","half3x1","half4x1","half1x2","half2x2","half3x2","half4x2", - "half1x3","half2x3","half3x3","half4x3","half1x4","half2x4","half3x4","half4x4", - }; - for (auto& k : keywords) - langDef.mKeywords.insert(k); - - static const char* const identifiers[] = { - "abort", "abs", "acos", "all", "AllMemoryBarrier", "AllMemoryBarrierWithGroupSync", "any", "asdouble", "asfloat", "asin", "asint", "asint", "asuint", - "asuint", "atan", "atan2", "ceil", "CheckAccessFullyMapped", "clamp", "clip", "cos", "cosh", "countbits", "cross", "D3DCOLORtoUBYTE4", "ddx", - "ddx_coarse", "ddx_fine", "ddy", "ddy_coarse", "ddy_fine", "degrees", "determinant", "DeviceMemoryBarrier", "DeviceMemoryBarrierWithGroupSync", - "distance", "dot", "dst", "errorf", "EvaluateAttributeAtCentroid", "EvaluateAttributeAtSample", "EvaluateAttributeSnapped", "exp", "exp2", - "f16tof32", "f32tof16", "faceforward", "firstbithigh", "firstbitlow", "floor", "fma", "fmod", "frac", "frexp", "fwidth", "GetRenderTargetSampleCount", - "GetRenderTargetSamplePosition", "GroupMemoryBarrier", "GroupMemoryBarrierWithGroupSync", "InterlockedAdd", "InterlockedAnd", "InterlockedCompareExchange", - "InterlockedCompareStore", "InterlockedExchange", "InterlockedMax", "InterlockedMin", "InterlockedOr", "InterlockedXor", "isfinite", "isinf", "isnan", - "ldexp", "length", "lerp", "lit", "log", "log10", "log2", "mad", "max", "min", "modf", "msad4", "mul", "noise", "normalize", "pow", "printf", - "Process2DQuadTessFactorsAvg", "Process2DQuadTessFactorsMax", "Process2DQuadTessFactorsMin", "ProcessIsolineTessFactors", "ProcessQuadTessFactorsAvg", - "ProcessQuadTessFactorsMax", "ProcessQuadTessFactorsMin", "ProcessTriTessFactorsAvg", "ProcessTriTessFactorsMax", "ProcessTriTessFactorsMin", - "radians", "rcp", "reflect", "refract", "reversebits", "round", "rsqrt", "saturate", "sign", "sin", "sincos", "sinh", "smoothstep", "sqrt", "step", - "tan", "tanh", "tex1D", "tex1D", "tex1Dbias", "tex1Dgrad", "tex1Dlod", "tex1Dproj", "tex2D", "tex2D", "tex2Dbias", "tex2Dgrad", "tex2Dlod", "tex2Dproj", - "tex3D", "tex3D", "tex3Dbias", "tex3Dgrad", "tex3Dlod", "tex3Dproj", "texCUBE", "texCUBE", "texCUBEbias", "texCUBEgrad", "texCUBElod", "texCUBEproj", "transpose", "trunc" - }; - for (auto& k : identifiers) - { - Identifier id; - id.mDeclaration = "Built-in function"; - langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); - } - - langDef.mTokenRegexStrings.push_back(std::make_pair("[ \\t]*#[ \\t]*[a-zA-Z_]+", PaletteIndex::Preprocessor)); - langDef.mTokenRegexStrings.push_back(std::make_pair("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String)); - langDef.mTokenRegexStrings.push_back(std::make_pair("\\'\\\\?[^\\']\\'", PaletteIndex::CharLiteral)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation)); - - langDef.mCommentStart = "/*"; - langDef.mCommentEnd = "*/"; - langDef.mSingleLineComment = "//"; - - langDef.mCaseSensitive = true; - langDef.mAutoIndentation = true; - - langDef.mName = "HLSL"; - - inited = true; - } - return langDef; -} - -const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::GLSL() -{ - static bool inited = false; - static LanguageDefinition langDef; - if (!inited) - { - static const char* const keywords[] = { - "auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long", "register", "restrict", "return", "short", - "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary", - "_Noreturn", "_Static_assert", "_Thread_local" - }; - for (auto& k : keywords) - langDef.mKeywords.insert(k); - - static const char* const identifiers[] = { - "abort", "abs", "acos", "asin", "atan", "atexit", "atof", "atoi", "atol", "ceil", "clock", "cosh", "ctime", "div", "exit", "fabs", "floor", "fmod", "getchar", "getenv", "isalnum", "isalpha", "isdigit", "isgraph", - "ispunct", "isspace", "isupper", "kbhit", "log10", "log2", "log", "memcmp", "modf", "pow", "putchar", "putenv", "puts", "rand", "remove", "rename", "sinh", "sqrt", "srand", "strcat", "strcmp", "strerror", "time", "tolower", "toupper" - }; - for (auto& k : identifiers) - { - Identifier id; - id.mDeclaration = "Built-in function"; - langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); - } - - langDef.mTokenRegexStrings.push_back(std::make_pair("[ \\t]*#[ \\t]*[a-zA-Z_]+", PaletteIndex::Preprocessor)); - langDef.mTokenRegexStrings.push_back(std::make_pair("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String)); - langDef.mTokenRegexStrings.push_back(std::make_pair("\\'\\\\?[^\\']\\'", PaletteIndex::CharLiteral)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation)); - - langDef.mCommentStart = "/*"; - langDef.mCommentEnd = "*/"; - langDef.mSingleLineComment = "//"; - - langDef.mCaseSensitive = true; - langDef.mAutoIndentation = true; - - langDef.mName = "GLSL"; - - inited = true; - } - return langDef; -} - -const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::C() -{ - static bool inited = false; - static LanguageDefinition langDef; - if (!inited) - { - static const char* const keywords[] = { - "auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long", "register", "restrict", "return", "short", - "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary", - "_Noreturn", "_Static_assert", "_Thread_local" - }; - for (auto& k : keywords) - langDef.mKeywords.insert(k); - - static const char* const identifiers[] = { - "abort", "abs", "acos", "asin", "atan", "atexit", "atof", "atoi", "atol", "ceil", "clock", "cosh", "ctime", "div", "exit", "fabs", "floor", "fmod", "getchar", "getenv", "isalnum", "isalpha", "isdigit", "isgraph", - "ispunct", "isspace", "isupper", "kbhit", "log10", "log2", "log", "memcmp", "modf", "pow", "putchar", "putenv", "puts", "rand", "remove", "rename", "sinh", "sqrt", "srand", "strcat", "strcmp", "strerror", "time", "tolower", "toupper" - }; - for (auto& k : identifiers) - { - Identifier id; - id.mDeclaration = "Built-in function"; - langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); - } - - langDef.mTokenize = [](const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end, PaletteIndex & paletteIndex) -> bool - { - paletteIndex = PaletteIndex::Max; - - while (in_begin < in_end && isascii(*in_begin) && isblank(*in_begin)) - in_begin++; - - if (in_begin == in_end) - { - out_begin = in_end; - out_end = in_end; - paletteIndex = PaletteIndex::Default; - } - else if (TokenizeCStyleString(in_begin, in_end, out_begin, out_end)) - paletteIndex = PaletteIndex::String; - else if (TokenizeCStyleCharacterLiteral(in_begin, in_end, out_begin, out_end)) - paletteIndex = PaletteIndex::CharLiteral; - else if (TokenizeCStyleIdentifier(in_begin, in_end, out_begin, out_end)) - paletteIndex = PaletteIndex::Identifier; - else if (TokenizeCStyleNumber(in_begin, in_end, out_begin, out_end)) - paletteIndex = PaletteIndex::Number; - else if (TokenizeCStylePunctuation(in_begin, in_end, out_begin, out_end)) - paletteIndex = PaletteIndex::Punctuation; - - return paletteIndex != PaletteIndex::Max; - }; - - langDef.mCommentStart = "/*"; - langDef.mCommentEnd = "*/"; - langDef.mSingleLineComment = "//"; - - langDef.mCaseSensitive = true; - langDef.mAutoIndentation = true; - - langDef.mName = "C"; - - inited = true; - } - return langDef; -} - -const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::SQL() -{ - static bool inited = false; - static LanguageDefinition langDef; - if (!inited) - { - static const char* const keywords[] = { - "ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", - "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", - "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", - "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", - "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", - "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", - "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", - "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", - "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING","DROP", "OPENROWSET", "VIEW", - "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT" - }; - - for (auto& k : keywords) - langDef.mKeywords.insert(k); - - static const char* const identifiers[] = { - "ABS", "ACOS", "ADD_MONTHS", "ASCII", "ASCIISTR", "ASIN", "ATAN", "ATAN2", "AVG", "BFILENAME", "BIN_TO_NUM", "BITAND", "CARDINALITY", "CASE", "CAST", "CEIL", - "CHARTOROWID", "CHR", "COALESCE", "COMPOSE", "CONCAT", "CONVERT", "CORR", "COS", "COSH", "COUNT", "COVAR_POP", "COVAR_SAMP", "CUME_DIST", "CURRENT_DATE", - "CURRENT_TIMESTAMP", "DBTIMEZONE", "DECODE", "DECOMPOSE", "DENSE_RANK", "DUMP", "EMPTY_BLOB", "EMPTY_CLOB", "EXP", "EXTRACT", "FIRST_VALUE", "FLOOR", "FROM_TZ", "GREATEST", - "GROUP_ID", "HEXTORAW", "INITCAP", "INSTR", "INSTR2", "INSTR4", "INSTRB", "INSTRC", "LAG", "LAST_DAY", "LAST_VALUE", "LEAD", "LEAST", "LENGTH", "LENGTH2", "LENGTH4", - "LENGTHB", "LENGTHC", "LISTAGG", "LN", "LNNVL", "LOCALTIMESTAMP", "LOG", "LOWER", "LPAD", "LTRIM", "MAX", "MEDIAN", "MIN", "MOD", "MONTHS_BETWEEN", "NANVL", "NCHR", - "NEW_TIME", "NEXT_DAY", "NTH_VALUE", "NULLIF", "NUMTODSINTERVAL", "NUMTOYMINTERVAL", "NVL", "NVL2", "POWER", "RANK", "RAWTOHEX", "REGEXP_COUNT", "REGEXP_INSTR", - "REGEXP_REPLACE", "REGEXP_SUBSTR", "REMAINDER", "REPLACE", "ROUND", "ROWNUM", "RPAD", "RTRIM", "SESSIONTIMEZONE", "SIGN", "SIN", "SINH", - "SOUNDEX", "SQRT", "STDDEV", "SUBSTR", "SUM", "SYS_CONTEXT", "SYSDATE", "SYSTIMESTAMP", "TAN", "TANH", "TO_CHAR", "TO_CLOB", "TO_DATE", "TO_DSINTERVAL", "TO_LOB", - "TO_MULTI_BYTE", "TO_NCLOB", "TO_NUMBER", "TO_SINGLE_BYTE", "TO_TIMESTAMP", "TO_TIMESTAMP_TZ", "TO_YMINTERVAL", "TRANSLATE", "TRIM", "TRUNC", "TZ_OFFSET", "UID", "UPPER", - "USER", "USERENV", "VAR_POP", "VAR_SAMP", "VARIANCE", "VSIZE " - }; - for (auto& k : identifiers) - { - Identifier id; - id.mDeclaration = "Built-in function"; - langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); - } - - langDef.mTokenRegexStrings.push_back(std::make_pair("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String)); - langDef.mTokenRegexStrings.push_back(std::make_pair("\\\'[^\\\']*\\\'", PaletteIndex::String)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation)); - - langDef.mCommentStart = "/*"; - langDef.mCommentEnd = "*/"; - langDef.mSingleLineComment = "//"; - - langDef.mCaseSensitive = false; - langDef.mAutoIndentation = false; - - langDef.mName = "SQL"; - - inited = true; - } - return langDef; -} - -const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::AngelScript() -{ - static bool inited = false; - static LanguageDefinition langDef; - if (!inited) - { - static const char* const keywords[] = { - "and", "abstract", "auto", "bool", "break", "case", "cast", "class", "const", "continue", "default", "do", "double", "else", "enum", "false", "final", "float", "for", - "from", "funcdef", "function", "get", "if", "import", "in", "inout", "int", "interface", "int8", "int16", "int32", "int64", "is", "mixin", "namespace", "not", - "null", "or", "out", "override", "private", "protected", "return", "set", "shared", "super", "switch", "this ", "true", "typedef", "uint", "uint8", "uint16", "uint32", - "uint64", "void", "while", "xor" - }; - - for (auto& k : keywords) - langDef.mKeywords.insert(k); - - static const char* const identifiers[] = { - "cos", "sin", "tab", "acos", "asin", "atan", "atan2", "cosh", "sinh", "tanh", "log", "log10", "pow", "sqrt", "abs", "ceil", "floor", "fraction", "closeTo", "fpFromIEEE", "fpToIEEE", - "complex", "opEquals", "opAddAssign", "opSubAssign", "opMulAssign", "opDivAssign", "opAdd", "opSub", "opMul", "opDiv" - }; - for (auto& k : identifiers) - { - Identifier id; - id.mDeclaration = "Built-in function"; - langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); - } - - langDef.mTokenRegexStrings.push_back(std::make_pair("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String)); - langDef.mTokenRegexStrings.push_back(std::make_pair("\\'\\\\?[^\\']\\'", PaletteIndex::String)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation)); - - langDef.mCommentStart = "/*"; - langDef.mCommentEnd = "*/"; - langDef.mSingleLineComment = "//"; - - langDef.mCaseSensitive = true; - langDef.mAutoIndentation = true; - - langDef.mName = "AngelScript"; - - inited = true; - } - return langDef; -} - -const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::Lua() -{ - static bool inited = false; - static LanguageDefinition langDef; - if (!inited) - { - static const char* const keywords[] = { - "and", "break", "do", "", "else", "elseif", "end", "false", "for", "function", "if", "in", "", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" - }; - - for (auto& k : keywords) - langDef.mKeywords.insert(k); - - static const char* const identifiers[] = { - "assert", "collectgarbage", "dofile", "error", "getmetatable", "ipairs", "loadfile", "load", "loadstring", "next", "pairs", "pcall", "print", "rawequal", "rawlen", "rawget", "rawset", - "select", "setmetatable", "tonumber", "tostring", "type", "xpcall", "_G", "_VERSION","arshift", "band", "bnot", "bor", "bxor", "btest", "extract", "lrotate", "lshift", "replace", - "rrotate", "rshift", "create", "resume", "running", "status", "wrap", "yield", "isyieldable", "debug","getuservalue", "gethook", "getinfo", "getlocal", "getregistry", "getmetatable", - "getupvalue", "upvaluejoin", "upvalueid", "setuservalue", "sethook", "setlocal", "setmetatable", "setupvalue", "traceback", "close", "flush", "input", "lines", "open", "output", "popen", - "read", "tmpfile", "type", "write", "close", "flush", "lines", "read", "seek", "setvbuf", "write", "__gc", "__tostring", "abs", "acos", "asin", "atan", "ceil", "cos", "deg", "exp", "tointeger", - "floor", "fmod", "ult", "log", "max", "min", "modf", "rad", "random", "randomseed", "sin", "sqrt", "string", "tan", "type", "atan2", "cosh", "sinh", "tanh", - "pow", "frexp", "ldexp", "log10", "pi", "huge", "maxinteger", "mininteger", "loadlib", "searchpath", "seeall", "preload", "cpath", "path", "searchers", "loaded", "module", "require", "clock", - "date", "difftime", "execute", "exit", "getenv", "remove", "rename", "setlocale", "time", "tmpname", "byte", "char", "dump", "find", "format", "gmatch", "gsub", "len", "lower", "match", "rep", - "reverse", "sub", "upper", "pack", "packsize", "unpack", "concat", "maxn", "insert", "pack", "unpack", "remove", "move", "sort", "offset", "codepoint", "char", "len", "codes", "charpattern", - "coroutine", "table", "io", "os", "string", "utf8", "bit32", "math", "debug", "package" - }; - for (auto& k : identifiers) - { - Identifier id; - id.mDeclaration = "Built-in function"; - langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); - } - - langDef.mTokenRegexStrings.push_back(std::make_pair("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String)); - langDef.mTokenRegexStrings.push_back(std::make_pair("\\\'[^\\\']*\\\'", PaletteIndex::String)); - langDef.mTokenRegexStrings.push_back(std::make_pair("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier)); - langDef.mTokenRegexStrings.push_back(std::make_pair("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation)); - - langDef.mCommentStart = "--[["; - langDef.mCommentEnd = "]]"; - langDef.mSingleLineComment = "--"; - - langDef.mCaseSensitive = true; - langDef.mAutoIndentation = false; - - langDef.mName = "Lua"; - - inited = true; - } - return langDef; -} diff --git a/source/imgui/TextEditor.h b/source/imgui/TextEditor.h index bd52e13..e0e86cd 100644 --- a/source/imgui/TextEditor.h +++ b/source/imgui/TextEditor.h @@ -174,12 +174,6 @@ public: } static const LanguageDefinition& CPlusPlus(); - static const LanguageDefinition& HLSL(); - static const LanguageDefinition& GLSL(); - static const LanguageDefinition& C(); - static const LanguageDefinition& SQL(); - static const LanguageDefinition& AngelScript(); - static const LanguageDefinition& Lua(); }; TextEditor(); diff --git a/source/imgui/imgui.h b/source/imgui/imgui.h index 182c46a..8d2b376 100644 --- a/source/imgui/imgui.h +++ b/source/imgui/imgui.h @@ -243,9 +243,9 @@ typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11) IM_MSVC_RUNTIME_CHECKS_OFF struct ImVec2 { - float x, y; - ImVec2() { x = y = 0.0f; } - ImVec2(float _x, float _y) { x = _x; y = _y; } + float x = 0.f, y = 0.f; + constexpr ImVec2() = default; + constexpr ImVec2(float _x, float _y) : x(_x), y(_y) {} float operator[] (size_t idx) const { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. float& operator[] (size_t idx) { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. #ifdef IM_VEC2_CLASS_EXTRA diff --git a/source/logview.cpp b/source/logview.cpp new file mode 100644 index 0000000..267cecb --- /dev/null +++ b/source/logview.cpp @@ -0,0 +1,82 @@ +#include "logview.h" + +LogView::LogView() +{ + Clear(); +} + +void LogView::Clear() +{ + Buf.clear(); + LineOffsets.clear(); + LineOffsets.push_back(0); + updated = false; +} + +void LogView::AddLog(const std::string& str) +{ + AddLog(str.c_str()); +} + +void LogView::AddLog(const char* fmt, ...) +{ + int old_size = Buf.size(); + va_list args; + va_start(args, fmt); + Buf.appendfv(fmt, args); + Buf.appendfv("\n", args); + va_end(args); + for (int new_size = Buf.size(); old_size < new_size; old_size++) + if (Buf[old_size] == '\n') + LineOffsets.push_back(old_size + 1); + updated = true; +} + +void LogView::Draw(const char* title, bool* p_open, ImGuiWindowFlags flags) +{ + if (!ImGui::Begin(title, p_open, flags)) + { + ImGui::End(); + return; + } + + ImGui::Text("Log "); + ImGui::SameLine(); + if (ImGui::Button("Clear")) + Clear(); + ImGui::SameLine(); + if (ImGui::Button("Copy")) + ImGui::LogToClipboard(); + ImGui::Separator(); + ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); + + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + const char* buf = Buf.begin(); + const char* buf_end = Buf.end(); + + ImGuiListClipper clipper; + clipper.Begin(LineOffsets.Size); + + while (clipper.Step()) + { + for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) + { + const char* line_start = buf + LineOffsets[line_no]; + const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + ImGui::TextUnformatted(line_start, line_end); + } + } + clipper.End(); + + ImGui::PopStyleVar(); + + if (updated) { + ImGui::SetScrollHereY(); + updated = false; + } + + ImGui::EndChild(); + ImGui::End(); +} + diff --git a/source/logview.h b/source/logview.h index 4ab2c94..3c6acf1 100644 --- a/source/logview.h +++ b/source/logview.h @@ -3,87 +3,23 @@ #include +#include "imgui.h" + // Adapted from ExampleAppLog from imgui_demo.cpp class LogView { public: - LogView() - { - Clear(); - } - - void Clear() - { - Buf.clear(); - LineOffsets.clear(); - LineOffsets.push_back(0); - } - - void AddLog(const std::string& str) - { - AddLog(str.c_str()); - } - - void AddLog(const char* fmt, ...) IM_FMTARGS(2) - { - int old_size = Buf.size(); - va_list args; - va_start(args, fmt); - Buf.appendfv(fmt, args); - Buf.appendfv("\n", args); - va_end(args); - for (int new_size = Buf.size(); old_size < new_size; old_size++) - if (Buf[old_size] == '\n') - LineOffsets.push_back(old_size + 1); - } - - void Draw(const char* title, bool* p_open = NULL, ImGuiWindowFlags flags = 0) - { - if (!ImGui::Begin(title, p_open, flags)) - { - ImGui::End(); - return; - } - - ImGui::Text("Log "); - ImGui::SameLine(); - if (ImGui::Button("Clear")) - Clear(); - ImGui::SameLine(); - if (ImGui::Button("Copy")) - ImGui::LogToClipboard(); - ImGui::Separator(); - ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); - - - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - const char* buf = Buf.begin(); - const char* buf_end = Buf.end(); - ImGuiListClipper clipper; - clipper.Begin(LineOffsets.Size); - while (clipper.Step()) - { - for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) - { - const char* line_start = buf + LineOffsets[line_no]; - const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; - ImGui::TextUnformatted(line_start, line_end); - } - } - clipper.End(); - - ImGui::PopStyleVar(); - - if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) - ImGui::SetScrollHereY(1.0f); + LogView(); - ImGui::EndChild(); - ImGui::End(); - } + void Clear(); + void AddLog(const std::string& str); + void AddLog(const char* fmt, ...) IM_FMTARGS(2); + void Draw(const char* title, bool* p_open = NULL, ImGuiWindowFlags flags = 0); private: ImGuiTextBuffer Buf; ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls. + bool updated; }; #endif // LOGVIEW_H diff --git a/source/main.cpp b/source/main.cpp index 20c8ea1..5eac338 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -25,27 +25,24 @@ extern ImFont *fontSans; extern ImFont *fontMono; -extern bool guiInitialize(); -extern void guiHandleEvents(bool& done); -extern void guiShutdown(); -extern void guiRender(void (*func)()); +bool guiInitialize(); +bool guiHandleEvents(); +void guiShutdown(); +void guiRender(void (*func)()); -extern void fileRenderMenu(); -extern void fileRenderDialog(); -extern void fileInit(); +void fileRenderMenu(); +void fileRenderDialog(); +void fileInit(); -extern void codeEditorInit(); -extern void codeRenderMenu(); -extern void codeRenderToolbar(); -extern void codeRenderWidgets(); +void codeEditorInit(); +void codeRenderMenu(); +void codeRenderToolbar(); +void codeRenderWidgets(); -extern void deviceRenderDraw(); -extern void deviceRenderMenu(); -extern void deviceRenderToolbar(); -extern void deviceRenderWidgets(); - -// Globals that live here -bool done = false; +void deviceRenderDraw(); +void deviceRenderMenu(); +void deviceRenderToolbar(); +void deviceRenderWidgets(); static LogView logView; @@ -54,6 +51,8 @@ void log(const std::string& str) logView.AddLog(str); } +static void renderWindow(); + int main(int, char **) { if (!guiInitialize()) @@ -62,62 +61,72 @@ int main(int, char **) codeEditorInit(); fileInit(); - while (!done) { - auto endTime = std::chrono::steady_clock::now() + - std::chrono::milliseconds(static_cast(std::floor(1000. / 60.))); - - guiHandleEvents(done); - - // Start the new window frame and render the menu bar. - ImGui_ImplOpenGL2_NewFrame(); - ImGui_ImplSDL2_NewFrame(); - ImGui::NewFrame(); + while (1) { + constexpr std::chrono::duration fpsDelay (1. / 60.); + const auto endTime = std::chrono::steady_clock::now() + fpsDelay; - if (ImGui::BeginMainMenuBar()) { - fileRenderMenu(); - deviceRenderMenu(); - codeRenderMenu(); - ImGui::EndMainMenuBar(); + const bool isDone = guiHandleEvents(); + if (!isDone) { + renderWindow(); + std::this_thread::sleep_until(endTime); + } else { + break; } + } - // Begin the main view which the controls will be drawn onto. - ImGui::SetNextWindowPos({0, 22}); - ImGui::SetNextWindowSize({WINDOW_WIDTH, WINDOW_HEIGHT - 22 - 200}); - ImGui::Begin("main", nullptr, - ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration | - ImGuiWindowFlags_NoBringToFrontOnFocus); - - // Render main controls (order is important). - { - ImGui::PushFont(fontSans); - codeRenderToolbar(); - deviceRenderToolbar(); - fileRenderDialog(); - deviceRenderWidgets(); - ImGui::PopFont(); - - ImGui::PushFont(fontMono); - codeRenderWidgets(); - ImGui::SetNextWindowPos({0, WINDOW_HEIGHT - 200}); - ImGui::SetNextWindowSize({WINDOW_WIDTH, 200}); - logView.Draw("log", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus); - ImGui::PopFont(); - } + guiShutdown(); + return 0; +} - ImGui::End(); +void renderWindow() +{ + // Start the new window frame and render the menu bar. + ImGui_ImplOpenGL2_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + ImGui::NewFrame(); + + if (ImGui::BeginMainMenuBar()) { + fileRenderMenu(); + deviceRenderMenu(); + codeRenderMenu(); + ImGui::EndMainMenuBar(); + } - deviceRenderDraw(); + // Begin the main view which the controls will be drawn onto. + constexpr float LOGVIEW_HEIGHT = 200; + constexpr ImVec2 WINDOW_POS (0, 22); + constexpr ImVec2 WINDOW_SIZE (WINDOW_WIDTH, WINDOW_HEIGHT - 22 - LOGVIEW_HEIGHT); + ImGui::SetNextWindowPos(WINDOW_POS); + ImGui::SetNextWindowSize(WINDOW_SIZE); + ImGui::Begin("main", nullptr, + ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoBringToFrontOnFocus); + + // Render main controls (order is important). + { + ImGui::PushFont(fontSans); + codeRenderToolbar(); + deviceRenderToolbar(); + fileRenderDialog(); + deviceRenderWidgets(); + ImGui::PopFont(); + + ImGui::PushFont(fontMono); + codeRenderWidgets(); + ImGui::SetNextWindowPos({0, WINDOW_HEIGHT - LOGVIEW_HEIGHT}); + ImGui::SetNextWindowSize({WINDOW_WIDTH, LOGVIEW_HEIGHT}); + logView.Draw("log", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus); + ImGui::PopFont(); + } - // Draw everything to the screen. - ImGui::Render(); - guiRender([] { - ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); - }); + ImGui::End(); - std::this_thread::sleep_until(endTime); - } + deviceRenderDraw(); - guiShutdown(); - return 0; + // Draw everything to the screen. + ImGui::Render(); + guiRender([] { + ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); + }); }