diff --git a/Mosaic.qbs b/Mosaic.qbs index d43fa76..39450c1 100644 --- a/Mosaic.qbs +++ b/Mosaic.qbs @@ -16,6 +16,8 @@ Project{ "src/MosaicTheme.h", "src/SplashScreen.cpp", "src/SplashScreen.h", + "src/TextEditor.cpp", + "src/TextEditor.h", "src/config.h", "src/includes.h", 'src/main.cpp', @@ -25,7 +27,6 @@ Project{ of.addons: [ 'ofxImGui', - 'ofxLoggerChannel', 'ofxModal', 'ofxSimpleHttp', 'ofxVisualProgramming' diff --git a/README.md b/README.md index 918ca16..9a4e150 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,6 @@ Mosaic, ofxVisualProgramming, openframeworks, linux, macOS, windows, creative-co #### [ofxGLEditor](https://github.com/d3cod3/ofxGLEditor) -- Fork -#### [ofxGLError](https://github.com/armadillu/ofxGLError) - #### [ofxHistoryPlot](https://github.com/armadillu/ofxHistoryPlot) #### [ofxHttpForm](https://github.com/armadillu/ofxHttpForm) @@ -96,12 +94,10 @@ Mosaic, ofxVisualProgramming, openframeworks, linux, macOS, windows, creative-co #### [ofxJSON](https://github.com/jeffcrouse/ofxJSON) -#### [ofxImGui](https://github.com/jvcleave/ofxImGui) +#### [ofxImGui](https://github.com/d3cod3/ofxImGui) -- Fork #### [ofxInfiniteCanvas](https://github.com/d3cod3/ofxInfiniteCanvas) -- Fork -#### [ofxLoggerChannel](https://github.com/d3cod3/ofxLoggerChannel) -- Fork - #### [ofxLua](https://github.com/d3cod3/ofxLua) -- Fork #### [ofxMidi](https://github.com/d3cod3/ofxMidi) -- Fork @@ -126,8 +122,6 @@ Mosaic, ofxVisualProgramming, openframeworks, linux, macOS, windows, creative-co #### [ofxThreadedFileDialog](https://github.com/d3cod3/ofxThreadedFileDialog) -#### [ofxThreadedYouTubeVideo](http://github.com/pierrep/ofxThreadedYouTubeVideo) - #### [ofxTimeline](https://github.com/d3cod3/ofxTimeline) -- Fork #### [ofxTimeMeasurements](https://github.com/armadillu/ofxTimeMeasurements) @@ -195,9 +189,8 @@ git clone https://github.com/armadillu/ofxHistoryPlot git clone https://github.com/armadillu/ofxHttpForm git clone https://github.com/d3cod3/ofxJava git clone https://github.com/jeffcrouse/ofxJSON -git clone https://github.com/jvcleave/ofxImGui +git clone https://github.com/d3cod3/ofxImGui git clone https://github.com/d3cod3/ofxInfiniteCanvas -git clone https://github.com/d3cod3/ofxLoggerChannel git clone --branch=of-0.10.0 https://github.com/d3cod3/ofxLua git clone https://github.com/d3cod3/ofxMidi git clone https://github.com/d3cod3/ofxModal @@ -210,7 +203,6 @@ git clone https://github.com/d3cod3/ofxPdExternals git clone https://github.com/npisanti/ofxPDSP git clone https://github.com/armadillu/ofxSimpleHttp git clone https://github.com/d3cod3/ofxThreadedFileDialog -git clone http://github.com/pierrep/ofxThreadedYouTubeVideo git clone https://github.com/d3cod3/ofxTimeline git clone https://github.com/armadillu/ofxTimeMeasurements git clone https://github.com/d3cod3/ofxVisualProgramming diff --git a/src/MosaicTheme.cpp b/src/MosaicTheme.cpp index 03e03bf..c30c9b0 100644 --- a/src/MosaicTheme.cpp +++ b/src/MosaicTheme.cpp @@ -197,3 +197,20 @@ void MosaicTheme::drawDemoComboBox(){ MosaicTheme::TextInputComboBox("Objects", buffer, 20, items, IM_ARRAYSIZE(items)); ImGui::End(); } + +//-------------------------------------------------------------- +void MosaicTheme::drawMosaicLogDemo(){ + static MosaicLoggerChannel log; + + // Demo: add random items (unless Ctrl is held) + static double last_time = -1.0; + double time = ImGui::GetTime(); + if (time - last_time >= 0.20f && !ImGui::GetIO().KeyCtrl) + { + const char* random_words[] = { "system", "info", "warning", "error", "fatal", "notice", "log" }; + log.AddLog("[%s] Hello, time is %.1f, frame count is %d\n", random_words[rand() % IM_ARRAYSIZE(random_words)], time, ImGui::GetFrameCount()); + last_time = time; + } + + log.Draw("Example: Log"); +} diff --git a/src/MosaicTheme.h b/src/MosaicTheme.h index f5eb2d2..74c7f4e 100644 --- a/src/MosaicTheme.h +++ b/src/MosaicTheme.h @@ -50,5 +50,112 @@ class MosaicTheme : public ofxImGui::BaseTheme{ static bool TextInputComboBox(const char* id, char* buffer, size_t maxInputSize, const char* items[], size_t item_len); static void drawDemoComboBox(); + static void drawMosaicLogDemo(); + +}; + +class MosaicLoggerChannel : public ofBaseLoggerChannel +{ +public: + + ImVector Items; + bool scrollToBottom; + + MosaicLoggerChannel() { + scrollToBottom = true; + } + + void log( ofLogLevel level, const std::string & module, const std::string & message ){ + std::ostringstream oss; + oss << ofGetTimestampString("%H:%M:%S:%i") << " "; + oss << "[" << ofGetLogLevelName(level, true) << "] "; + if (module != "") { + oss << module << ": "; + } + oss << message << endl; + + AddLog("%s\n", oss.str().c_str()); + } + void log( ofLogLevel level, const std::string & module, const char* format, ... ) OF_PRINTF_ATTR( 4, 5 ){ + va_list args; + va_start(args, format); + log(level, module, format, args); + va_end(args); + } + void log( ofLogLevel level, const std::string & module, const char* format, va_list args ){ + // Compose the message. + std::ostringstream oss; + oss << ofGetTimestampString("%H:%M:%S:%i") << " "; + oss << "[" << ofGetLogLevelName(level, true) << "] "; + if (module != "") { + oss << module << ": "; + } + + oss << ofVAArgsToString(format, args) << endl; + + AddLog("%s\n", oss.str().c_str()); + } + + void Clear() { + for (int i = 0; i < Items.Size; i++){ + free(Items[i]); + } + Items.clear(); + } + + void AddLog(const char* fmt, ...) IM_FMTARGS(2){ + char buf[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); + buf[IM_ARRAYSIZE(buf)-1] = 0; + va_end(args); + Items.push_back(strdup(buf)); + scrollToBottom = true; + } + + void Draw(const char* title){ + + if (!ImGui::Begin(title)) + { + ImGui::End(); + return; + } + if (ImGui::Button("Clear")) Clear(); + + ImGui::Separator(); + ImGui::BeginChild("scrolling", ImVec2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing + + ImVec4 col_default_text = ImGui::GetStyleColorVec4(ImGuiCol_Text); + for (int i = 0; i < Items.Size; i++){ + const char* item = Items[i]; + ImVec4 col = col_default_text; + if (strstr(item, "[notice")) col = ImGui::GetStyleColorVec4(ImGuiCol_Text); + else if (strstr(item, "[warning")) col = ImColor(1.0f,0.5f,0.0f,1.0f); + else if (strstr(item, "[ error")) col = ImColor(1.0f,0.176f,0.176f,1.0f); + else if (strstr(item, "[silent")) col = ImColor(1.0f,0.78f,0.58f,1.0f); + else if (strncmp(item, "# ", 2) == 0) col = ImColor(1.0f,0.78f,0.58f,1.0f); + + // force verbose + if(strstr(item, "[verbose]")){ + col = ImColor(0.235f,1.0f,0.235f,1.0f); + } + + ImGui::PushStyleColor(ImGuiCol_Text, col); + ImGui::TextUnformatted(item); + ImGui::PopStyleColor(); + } + + if(scrollToBottom){ + scrollToBottom = false; + ImGui::SetScrollHere(1.0f); + } + + + ImGui::EndChild(); + ImGui::End(); + } }; diff --git a/src/includes.h b/src/includes.h index 63447cf..f833c27 100644 --- a/src/includes.h +++ b/src/includes.h @@ -34,7 +34,6 @@ #include "ofxVisualProgramming.h" #include "ofxImGui.h" -#include "ofxScreenLoggerChannel.h" #include "ofxModal.h" #include "ofxSimpleHttp.h" diff --git a/src/ofApp.cpp b/src/ofApp.cpp index 269d197..3c2fa79 100644 --- a/src/ofApp.cpp +++ b/src/ofApp.cpp @@ -90,27 +90,12 @@ void ofApp::setup(){ isInited = false; isWindowResized = false; isLoggerON = false; - loggerBounds = new ofRectangle(); - screenLoggerChannel = shared_ptr(new ofxScreenLoggerChannel()); - ofSetLoggerChannel(screenLoggerChannel); - screenLoggerChannel->setBackgroundColor(ofColor(0,0,0,200)); - screenLoggerChannel->setTextColor(ofColor(203,224,254)); - // RETINA FIX - if(ofGetScreenWidth() >= RETINA_MIN_WIDTH && ofGetScreenHeight() >= RETINA_MIN_HEIGHT){ - screenLoggerChannel->setup(MAIN_FONT,26); - screenLoggerChannel->setIsRetina(); - }else{ - screenLoggerChannel->setup(MAIN_FONT,14); - } - screenLoggerChannel->setPrefixTimestamp(true); - screenLoggerChannel->setMaxBufferCount(512); + mosaicLoggerChannel = shared_ptr(new MosaicLoggerChannel()); + ofSetLoggerChannel(mosaicLoggerChannel); - ofLog(OF_LOG_NOTICE," "); ofLog(OF_LOG_NOTICE,"%s | %s <%s>",WINDOW_TITLE,DESCRIPTION,MOSAIC_WWW); - ofLog(OF_LOG_NOTICE," "); ofLog(OF_LOG_NOTICE," an open project by Emanuele Mazza aka n3m3da"); - ofLog(OF_LOG_NOTICE," "); - ofLog(OF_LOG_NOTICE,"This project deals with the idea of integrate/amplify human-machine communication, offering a real-time flowchart based visual interface for high level creative coding. As live-coding scripting languages offer a high level coding environment, ofxVisualProgramming and the Mosaic Project as his parent layer container, aim at a high level visual-programming environment, with embedded multi scripting languages availability (Processing/Java, Lua, Python, GLSL and BASH)."); + ofLog(OF_LOG_NOTICE,"This project deals with the idea of integrate/amplify human-machine communication, offering a real-time flowchart based visual interface for high level creative coding.\nAs live-coding scripting languages offer a high level coding environment, ofxVisualProgramming and the Mosaic Project as his parent layer container,\naim at a high level visual-programming environment, with embedded multi scripting languages availability (Processing/Java, Lua, Python, GLSL and BASH).\n"); // Visual Programming Environment Load visualProgramming = new ofxVisualProgramming(); @@ -133,6 +118,8 @@ void ofApp::setup(){ io.Fonts->AddFontFromFileTTF(absPath.c_str(),14.0f); } + loggerRect.set(0,ofGetWindowHeight()-(258*visualProgramming->scaleFactor),ofGetWindowWidth(),240*visualProgramming->scaleFactor); + #ifdef TARGET_LINUX shortcutFunc = "CTRL"; #elif defined(TARGET_OSX) @@ -145,7 +132,9 @@ void ofApp::setup(){ mainMenu.setup(); mainMenu.setTheme(new MosaicTheme()); showRightClickMenu = false; + showConsoleWindow = false; isHoverMenu = false; + isHoverLogger = false; // MODALS modalTheme = make_shared(); @@ -192,6 +181,7 @@ void ofApp::update(){ // Visual Programming Environment visualProgramming->update(); visualProgramming->setIsHoverMenu(isHoverMenu); + visualProgramming->setIsHoverLogger(isHoverLogger); if(loadNewPatch){ loadNewPatch = false; if(patchToLoad != ""){ @@ -212,16 +202,10 @@ void ofApp::update(){ if(isWindowResized){ isWindowResized = false; visualProgramming->updateCanvasViewport(); - loggerBounds->width = ofGetWindowWidth(); - loggerBounds->y = ofGetWindowHeight() - (258*visualProgramming->scaleFactor); - screenLoggerChannel->setDrawBounds(*loggerBounds); } if(!isInited){ isInited = true; - // set logger dimensions - loggerBounds->set(0,ofGetWindowHeight()-(258*visualProgramming->scaleFactor),ofGetWindowWidth(),240*visualProgramming->scaleFactor); - screenLoggerChannel->setDrawBounds(*loggerBounds); // reinit DSP resetInitDSP = ofGetElapsedTimeMillis(); autoinitDSP = true; @@ -287,12 +271,7 @@ void ofApp::draw(){ // MAIN MENU ofSetColor(255,255,255); - drawMainMenu(); - - // LOGGER - if(isLoggerON){ - screenLoggerChannel->draw(); - } + drawImGuiInterface(); if(setupLoaded && ofGetElapsedTimeMillis() > 1000){ setupLoaded = false; @@ -302,7 +281,7 @@ void ofApp::draw(){ } //-------------------------------------------------------------- -void ofApp::drawMainMenu(){ +void ofApp::drawImGuiInterface(){ mainMenu.begin(); { @@ -423,7 +402,7 @@ void ofApp::drawMainMenu(){ TIME_SAMPLE_SET_ENABLED(visualProgramming->profilerActive); } if(ImGui::Checkbox("Logger",&isLoggerON)){ - + showConsoleWindow = isLoggerON; } ImGui::Spacing(); ImGui::Separator(); @@ -460,15 +439,28 @@ void ofApp::drawMainMenu(){ ImGui::EndMainMenuBar(); + + // floating logger window + if(showConsoleWindow){ + ImGui::SetNextWindowSize(ImVec2(ofGetWindowWidth(),240*visualProgramming->scaleFactor), ImGuiCond_Always); + ImGui::SetNextWindowPos(ImVec2(0,ofGetWindowHeight()-(258*visualProgramming->scaleFactor)), ImGuiCond_Always); + mosaicLoggerChannel->Draw("Logger"); + + isHoverLogger = loggerRect.inside(ofGetMouseX(),ofGetMouseY()); + }else{ + isHoverLogger = false; + } + + // right click menu if(showRightClickMenu){ - ImGui::SetNextWindowSize(ofVec2f(200*visualProgramming->scaleFactor,340*visualProgramming->scaleFactor), ImGuiSetCond_FirstUseEver); - ImGui::SetNextWindowPos(ofVec2f(ofGetMouseX(),ofGetMouseY()), ImGuiSetCond_Appearing); + ImGui::SetNextWindowSize(ImVec2(200*visualProgramming->scaleFactor,280*visualProgramming->scaleFactor), ImGuiCond_Always); + ImGui::SetNextWindowPos(ImVec2(ofGetMouseX(),ofGetMouseY()), ImGuiSetCond_Appearing); ImGui::Begin("Objects", &showRightClickMenu,ImGuiWindowFlags_NoSavedSettings); MosaicTheme::TextInputComboBox("Objects", searchedObject, 30, ofxVP_objectsArray, IM_ARRAYSIZE(ofxVP_objectsArray)); - isHoverMenu = ImGui::IsWindowHovered() || ImGui::IsAnyItemHovered(); + isHoverMenu = ImGui::IsAnyWindowHovered() || ImGui::IsAnyItemHovered(); for(map>::iterator it = visualProgramming->objectsMatrix.begin(); it != visualProgramming->objectsMatrix.end(); it++ ){ if(ImGui::BeginMenu(it->first.c_str())){ @@ -616,7 +608,7 @@ void ofApp::onModalEvent(ofxModalEvent e){ #endif #ifdef TARGET_LINUX - ofLaunchBrowser("https://gist.github.com/d3cod3/2704377f0e7b9e844d775ae0151cd688#file-update_mosaic-sh"); + //ofLaunchBrowser("https://gist.github.com/d3cod3/2704377f0e7b9e844d775ae0151cd688#file-update_mosaic-sh"); #else if(mosaicURL != ""){ http.setUserAgent(USER_AGENT); @@ -637,8 +629,16 @@ void ofApp::onFileDialogResponse(ofxThreadedFileDialogResponse &response){ if (file.exists()){ string fileExtension = ofToUpper(file.getExtension()); if(fileExtension == "XML") { - patchToLoad = file.getAbsolutePath(); - loadNewPatch = true; + ofxXmlSettings XML; + + if (XML.loadFile(file.getAbsolutePath())){ + if (XML.getValue("www","") == "https://mosaic.d3cod3.org"){ + patchToLoad = file.getAbsolutePath(); + loadNewPatch = true; + }else{ + ofLog(OF_LOG_ERROR, "The opened file: %s, is not a Mosaic patch!",file.getAbsolutePath().c_str()); + } + } } } }else if(response.id == "open patch source"){ @@ -837,7 +837,6 @@ bool ofApp::checkInternetReachability(){ #endif if (execFile){ - ofLog(OF_LOG_NOTICE," "); ofLog(OF_LOG_NOTICE,"CHECKING INTERNET CONNECTIVITY..."); char buffer[128]; @@ -882,7 +881,6 @@ bool ofApp::checkInternetReachability(){ //-------------------------------------------------------------- void ofApp::checkForUpdates(){ - ofLog(OF_LOG_NOTICE," "); ofLog(OF_LOG_NOTICE,"CHECKING FOR MOSAIC UPDATES..."); string actualVersion = VERSION; @@ -982,14 +980,22 @@ void ofApp::createObjectFromFile(ofFile file,bool temp){ //ofLog(OF_LOG_NOTICE,"%s : %s",file.getEnclosingDirectory().substr(tempstr.find_last_of('/')+1,file.getEnclosingDirectory().find_last_of('/')-tempstr.find_last_of('/')-1).c_str(), file.getFileName().substr(0,file.getFileName().find_last_of('.')).c_str()); string fileExtension = ofToUpper(file.getExtension()); if(fileExtension == "XML") { - if(temp){ - visualProgramming->newTempPatchFromFile(file.getAbsolutePath()); - }else{ - visualProgramming->openPatch(file.getAbsolutePath()); + ofxXmlSettings XML; + + if (XML.loadFile(file.getAbsolutePath())){ + if (XML.getValue("www","") == "https://mosaic.d3cod3.org"){ + if(temp){ + visualProgramming->newTempPatchFromFile(file.getAbsolutePath()); + }else{ + visualProgramming->openPatch(file.getAbsolutePath()); + } + // reinit DSP + resetInitDSP = ofGetElapsedTimeMillis(); + autoinitDSP = true; + }else{ + ofLog(OF_LOG_ERROR, "The opened file: %s, is not a Mosaic patch!",file.getAbsolutePath().c_str()); + } } - // reinit DSP - resetInitDSP = ofGetElapsedTimeMillis(); - autoinitDSP = true; }else if(fileExtension == "MOV" || fileExtension == "MP4" || fileExtension == "MPEG" || fileExtension == "MPG" || fileExtension == "AVI"){ visualProgramming->addObject("video player",ofVec2f(visualProgramming->canvas.getMovingPoint().x + 20,visualProgramming->canvas.getMovingPoint().y + 20)); if(visualProgramming->getLastAddedObject() != nullptr){ diff --git a/src/ofApp.h b/src/ofApp.h index 7adb11c..98f7785 100644 --- a/src/ofApp.h +++ b/src/ofApp.h @@ -51,7 +51,7 @@ class ofApp : public ofBaseApp{ void draw(); void exit(); - void drawMainMenu(); + void drawImGuiInterface(); // Keyboard Events void keyPressed(ofKeyEventArgs &e); @@ -106,11 +106,13 @@ class ofApp : public ofBaseApp{ shared_ptr modalTheme; string shortcutFunc; string searchedObject; + bool showConsoleWindow; bool showRightClickMenu; bool isHoverMenu; + ofRectangle loggerRect; + bool isHoverLogger; // LOGGER - ofRectangle *loggerBounds; bool isInited; bool isWindowResized; bool isLoggerON; @@ -135,7 +137,8 @@ class ofApp : public ofBaseApp{ private: - shared_ptr screenLoggerChannel; + shared_ptr mosaicLoggerChannel; + string lastScreenshot; bool takeScreenshot; bool saveNewScreenshot;