Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 181 additions & 0 deletions source/MRViewer/MRToolsLibrary.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
#include "MRToolsLibrary.h"
#include "MRMesh/MRStringConvert.h"
#include "MRMesh/MRSystem.h"
#include "MRMesh/MRSceneRoot.h"
#include "MRMesh/MRObjectsAccess.h"
#include "MRMesh/MRObjectMesh.h"
#include "MRMesh/MRMesh.h"
#include "MRMesh/MRMeshSave.h"
#include "MRMesh/MRMeshLoad.h"
#include "MRFileDialog.h"
#include "MRMesh/MRIOFormatsRegistry.h"
#include "MRMesh/MRCylinder.h"
#include "MRUIStyle.h"
#include "MRRibbonConstants.h"
#include <imgui.h>
#include <cassert>

namespace MR
{

const char defaultName[] = "Default";

GcodeToolsLibrary::GcodeToolsLibrary( const std::string& libraryName )
{
assert( !libraryName.empty() );
libraryName_ = libraryName;
if ( !std::filesystem::exists( getFolder_() ) )
std::filesystem::create_directory( getFolder_() );

defaultToolMesh_ = std::make_shared<ObjectMesh>();
defaultToolMesh_->setName( "DefaultToolMesh" );
auto meshPtr = std::make_shared<Mesh>( makeCylinder( 1.f, 8.f, 50 ) );
defaultToolMesh_->setMesh( meshPtr );

toolMesh_ = defaultToolMesh_;
selectedIndex_ = 0;
selectedFileName_ = defaultName;
}

bool GcodeToolsLibrary::drawInterface()
{
bool openSelectMeshPopup = false;
bool result = false;

if ( UI::beginCombo( "Tool Mesh", selectedFileName_ ) )
{
bool selected = selectedFileName_ == defaultName;
if ( ImGui::Selectable( defaultName, &selected ) )
{
toolMesh_ = defaultToolMesh_;
selectedFileName_ = defaultName;
result = true;
ImGui::CloseCurrentPopup();
}

updateFilesList_();
for ( int i = 0; i < filesList_.size(); ++i )
{
selected = selectedFileName_ == filesList_[i];

if ( ImGui::Selectable( filesList_[i].c_str(), &selected ) && selected )
{
result = loadMeshFromFile_( filesList_[i] );
ImGui::CloseCurrentPopup();
}
}

selected = false;
if ( ImGui::Selectable( "<New Tool from File>", &selected ) )
{
addNewToolFromFile_();
result = true;
ImGui::CloseCurrentPopup();
}

const bool anyMeshExist = bool( getDepthFirstObject<ObjectMesh>( &SceneRoot::get(), ObjectSelectivityType::Selectable ) );
if ( !anyMeshExist )
ImGui::PushStyleColor( ImGuiCol_Text, ImGui::GetStyleColorVec4( ImGuiCol_TextDisabled ) );
if ( ImGui::Selectable( "<New Tool from exist Mesh>", &selected ) && anyMeshExist )
{
openSelectMeshPopup = true;
result = true;
ImGui::CloseCurrentPopup();
}
if ( !anyMeshExist )
ImGui::PopStyleColor();

UI::endCombo();
}
const float btnWidth = ImGui::CalcTextSize( "Remove" ).x + ImGui::GetStyle().FramePadding.x * 2.f;
const float btnHeight = ImGui::GetTextLineHeight() + StyleConsts::CustomCombo::framePadding.y * 2.f;
const float btnPosX = ImGui::GetContentRegionAvail().x - btnWidth;

ImGui::SameLine( btnPosX );
if ( UI::button( "Remove", selectedFileName_ != defaultName, {btnWidth, btnHeight}) )
{
std::filesystem::remove( getFolder_() / ( selectedFileName_ + ".mrmesh" ) );
selectedFileName_ = defaultName;
result = true;
toolMesh_ = defaultToolMesh_;
}

if ( openSelectMeshPopup )
ImGui::OpenPopup( "SelectMesh" );
drawSelectMeshPopup_();
return result;
}

std::filesystem::path GcodeToolsLibrary::getFolder_()
{
return getUserConfigDir() / libraryName_;
}

void GcodeToolsLibrary::updateFilesList_()
{
filesList_.clear();
for ( const auto& entry : std::filesystem::directory_iterator( getFolder_() ) )
{
const auto filename = entry.path().filename();
if ( utf8string( filename.extension() ) == ".mrmesh" )
filesList_.push_back( utf8string( filename.stem() ) );
}
}

void GcodeToolsLibrary::addNewToolFromFile_()
{
auto path = openFileDialog( { .filters = MeshLoad::getFilters() } );
if ( path.empty() )
return;

auto loadRes = MeshLoad::fromAnySupportedFormat( path );
if ( !loadRes )
return;

toolMesh_ = std::make_shared<ObjectMesh>();
toolMesh_->setName( utf8string( path.filename().stem() ) );
toolMesh_->setMesh( std::make_shared<Mesh>( *loadRes ) );
MeshSave::toMrmesh( *loadRes, getFolder_() / ( toolMesh_->name() + ".mrmesh" ) );
selectedFileName_ = toolMesh_->name();
}

void GcodeToolsLibrary::addNewToolFromMesh_( const std::shared_ptr<ObjectMesh>& objMesh )
{
toolMesh_ = std::dynamic_pointer_cast< ObjectMesh >( objMesh->clone() );
MeshSave::toMrmesh( *toolMesh_->mesh(), getFolder_() / ( toolMesh_->name() + ".mrmesh" ) );
updateFilesList_();
}

void GcodeToolsLibrary::drawSelectMeshPopup_()
{
if ( !ImGui::BeginPopup( "SelectMesh" ) )
return;

auto objsMesh = getAllObjectsInTree<ObjectMesh>( &SceneRoot::get(), ObjectSelectivityType::Selectable );
for ( int i = 0; i < objsMesh.size(); ++i )
{
bool selected = false;
if ( ImGui::Selectable( objsMesh[i]->name().c_str(), &selected ) )
addNewToolFromMesh_( objsMesh[i] );
}
ImGui::EndPopup();
}

bool GcodeToolsLibrary::loadMeshFromFile_( const std::string& filename )
{
auto path = getFolder_() / ( filename + ".mrmesh" );
if ( !std::filesystem::exists( path ) )
return false;

auto loadRes = MeshLoad::fromMrmesh( path );
if ( !loadRes )
return false;

toolMesh_ = std::make_shared<ObjectMesh>();
toolMesh_->setName( filename );
toolMesh_->setMesh( std::make_shared<Mesh>( *loadRes ) );
selectedFileName_ = filename;
return true;
}

}
45 changes: 45 additions & 0 deletions source/MRViewer/MRToolsLibrary.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once
#include "MRMesh/MRMeshFwd.h"
#include "exports.h"
#include <vector>
#include <string>
#include <filesystem>

namespace MR
{

// class for storing CNC tools
class MRVIEWER_CLASS GcodeToolsLibrary
{
public:
MRVIEWER_API GcodeToolsLibrary( const std::string& libraryName );

// draw interface for interacting with storage (based on UI::combo)
MRVIEWER_API bool drawInterface();

// get selected tool as ObjectMesh
const std::shared_ptr<ObjectMesh>& getToolObject() { return toolMesh_; }
private:

// storage folder
std::filesystem::path getFolder_();
// get valid files in storage folder
void updateFilesList_();
// add new tool in storage from file with mesh
void addNewToolFromFile_();
// add new tool in storage from exist ObjectMesh
void addNewToolFromMesh_( const std::shared_ptr<ObjectMesh>& objMesh );
// draw popup with ObjectMeshes available for adding
void drawSelectMeshPopup_();
// choose mesh from storage (and load it)
bool loadMeshFromFile_( const std::string& filename );

std::string libraryName_;
std::vector<std::string> filesList_;
int selectedIndex_;
std::string selectedFileName_;
std::shared_ptr<ObjectMesh> toolMesh_;
std::shared_ptr<ObjectMesh> defaultToolMesh_; // default mesh
};

}
52 changes: 51 additions & 1 deletion source/MRViewer/MRUIStyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,11 +844,15 @@ bool combo( const char* label, int* v, const std::vector<std::string>& options,
if ( !res )
return false;

bool selected = false;
for ( int i = 0; i < int( options.size() ); ++i )
{
ImGui::PushID( ( label + std::to_string( i ) ).c_str() );
if ( ImGui::Selectable( options[i].c_str(), *v == i ) )
{
selected = true;
*v = i;
}

if ( !tooltips.empty() )
UI::setTooltipIfHovered( tooltips[i], Viewer::instanceRef().getMenuPlugin()->menu_scaling() );
Expand All @@ -859,7 +863,53 @@ bool combo( const char* label, int* v, const std::vector<std::string>& options,
ImGui::EndCombo();
if ( !showPreview )
ImGui::PopItemWidth();
return true;
return selected;
}

bool beginCombo( const char* label, const std::string& text /*= "Not selected" */, bool showPreview /*= true*/ )
{
StyleParamHolder sh;
sh.addVar( ImGuiStyleVar_FramePadding, StyleConsts::CustomCombo::framePadding );

auto context = ImGui::GetCurrentContext();
ImGuiWindow* window = context->CurrentWindow;
const auto& style = ImGui::GetStyle();
const ImVec2 pos = window->DC.CursorPos;
const float arrowSize = 2 * style.FramePadding.y + ImGui::GetTextLineHeight();
if ( !showPreview )
ImGui::PushItemWidth( arrowSize + style.FramePadding.x * 0.5f );

float itemWidth = ( context->NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth ) ? context->NextItemData.Width : window->DC.ItemWidth;
const ImRect boundingBox( pos, { pos.x + itemWidth, pos.y + arrowSize } );
const ImRect arrowBox( { pos.x + boundingBox.GetWidth() - boundingBox.GetHeight() * 6.0f / 7.0f, pos.y }, boundingBox.Max );

auto res = ImGui::BeginCombo( label, nullptr, ImGuiComboFlags_NoArrowButton );
if ( showPreview )
{
ImGui::RenderTextClipped( { boundingBox.Min.x + style.FramePadding.x, boundingBox.Min.y + style.FramePadding.y }, { boundingBox.Max.x - arrowSize, boundingBox.Max.y }, text.c_str(), nullptr, nullptr );
}

const float halfHeight = arrowBox.GetHeight() * 0.5f;
const float arrowHeight = arrowBox.GetHeight() * 5.0f / 42.0f;
const float arrowWidth = arrowBox.GetWidth() * 2.0f / 15.0f;

const float thickness = ImMax( arrowBox.GetHeight() * 0.075f, 1.0f );

const ImVec2 arrowPos{ arrowBox.Min.x, arrowBox.Min.y - thickness };
const ImVec2 startPoint{ arrowPos.x + arrowWidth, arrowPos.y + halfHeight };
const ImVec2 midPoint{ arrowPos.x + 2 * arrowWidth, arrowPos.y + halfHeight + arrowHeight };
const ImVec2 endPoint{ arrowPos.x + 3 * arrowWidth, arrowPos.y + halfHeight };

DrawCustomArrow( window->DrawList, startPoint, midPoint, endPoint, ImGui::GetColorU32( ImGuiCol_Text ), thickness );

return res;
}

void endCombo( bool showPreview /*= true*/ )
{
ImGui::EndCombo();
if ( !showPreview )
ImGui::PopItemWidth();
}

bool inputTextCentered( const char* label, std::string& str, float width /*= 0.0f*/,
Expand Down
5 changes: 5 additions & 0 deletions source/MRViewer/MRUIStyle.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ MRVIEWER_API bool colorEdit4( const char* label, Color& color, ImGuiColorEditFla
MRVIEWER_API bool combo( const char* label, int* v, const std::vector<std::string>& options,
bool showPreview = true, const std::vector<std::string>& tooltips = {}, const std::string& defaultText = "Not selected" );

/// draw custom content combo box
MRVIEWER_API bool beginCombo( const char* label, const std::string& text = "Not selected", bool showPreview = true );
MRVIEWER_API void endCombo( bool showPreview = true );




/// draw input text box with text aligned by center
Expand Down
2 changes: 2 additions & 0 deletions source/MRViewer/MRViewer.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<ClCompile Include="MRCreateShader.cpp" />
<ClCompile Include="MRFrameRedrawRequest.cpp" />
<ClCompile Include="MRGetSystemInfoJson.cpp" />
<ClCompile Include="MRToolsLibrary.cpp" />
<ClCompile Include="MRLinesShader.cpp" />
<ClCompile Include="MRMeshShader.cpp" />
<ClCompile Include="MRMouseController.cpp" />
Expand Down Expand Up @@ -95,6 +96,7 @@
<ClInclude Include="MRFrameRedrawRequest.h" />
<ClInclude Include="MRGetSystemInfoJson.h" />
<ClInclude Include="MRGladGlfw.h" />
<ClInclude Include="MRToolsLibrary.h" />
<ClInclude Include="MRLinesShader.h" />
<ClInclude Include="MRMeshShader.h" />
<ClInclude Include="MRMouse.h" />
Expand Down
6 changes: 6 additions & 0 deletions source/MRViewer/MRViewer.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,9 @@
<ClCompile Include="MRFrameRedrawRequest.cpp">
<Filter>Helpers</Filter>
</ClCompile>
<ClCompile Include="MRToolsLibrary.cpp">
<Filter>Helpers</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ImGuiHelpers.h">
Expand Down Expand Up @@ -527,6 +530,9 @@
<ClInclude Include="MRFrameRedrawRequest.h">
<Filter>Helpers</Filter>
</ClInclude>
<ClInclude Include="MRToolsLibrary.h">
<Filter>Helpers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\MeshLib\source\.editorconfig" />
Expand Down