Cancel only text update job
This commit is contained in:
parent
feb9eda0c8
commit
394a59d44f
4 changed files with 143 additions and 76 deletions
|
@ -69,7 +69,7 @@ GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent)
|
|||
, m_is_initialized(false) // initialize on first opening gizmo
|
||||
, m_rotate_gizmo(parent, GLGizmoRotate::Axis::Z) // grab id = 2 (Z axis)
|
||||
, m_font_manager(m_imgui->get_glyph_ranges())
|
||||
, m_update_job_cancel(std::make_shared<bool>(false))
|
||||
, m_update_job_cancel(nullptr)
|
||||
{
|
||||
m_rotate_gizmo.set_group_id(0);
|
||||
// TODO: add suggestion to use https://fontawesome.com/
|
||||
|
@ -749,20 +749,26 @@ bool GLGizmoEmboss::process()
|
|||
// no volume is selected -> selection from right panel
|
||||
if (m_volume == nullptr) return false;
|
||||
|
||||
// exist loaded font?
|
||||
Emboss::FontFileWithCache font = m_font_manager.get_font().font_file_with_cache;
|
||||
if (!font.has_value()) return false;
|
||||
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||
// cancel must be befor create new data
|
||||
|
||||
*m_update_job_cancel = true; // set old job to cancel
|
||||
m_update_job_cancel = std::make_shared<bool>(false); // create new shared ptr
|
||||
// without text there is no to emboss
|
||||
if (m_text.empty()) return false;
|
||||
|
||||
// IMPROVE: Cancel only EmbossUpdateJob no others
|
||||
worker.cancel();
|
||||
// exist loaded font
|
||||
if (!m_font_manager.is_activ_font()) return false;
|
||||
Emboss::FontFileWithCache font = m_font_manager.get_font().font_file_with_cache;
|
||||
assert(font.has_value());
|
||||
if (!font.has_value()) return false;
|
||||
|
||||
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||
// Can't use cancel, because I want cancel only previous update job
|
||||
// worker.cancel();
|
||||
|
||||
// Cancel only EmbossUpdateJob no others
|
||||
if (m_update_job_cancel != nullptr)
|
||||
m_update_job_cancel->store(true);
|
||||
// create new shared ptr to cancel new job
|
||||
m_update_job_cancel = std::make_shared<std::atomic<bool> >(false);
|
||||
EmbossDataUpdate data{font, create_configuration(), create_volume_name(),
|
||||
m_volume->id(), m_update_job_cancel};
|
||||
|
||||
queue_job(worker, std::make_unique<EmbossUpdateJob>(std::move(data)));
|
||||
|
||||
// notification is removed befor object is changed by job
|
||||
|
@ -944,58 +950,90 @@ void GLGizmoEmboss::draw_text_input()
|
|||
if (exist_change) m_font_manager.clear_imgui_font();
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::draw_font_list()
|
||||
//#define DEBUG_NOT_LOADABLE_FONTS
|
||||
|
||||
/// <summary>
|
||||
/// Keep list of loadable OS fonts
|
||||
/// Filtrate which can be loaded.
|
||||
/// Sort alphanumerical.
|
||||
/// </summary>
|
||||
class MyFontEnumerator : public wxFontEnumerator
|
||||
{
|
||||
class MyFontEnumerator : public wxFontEnumerator
|
||||
{
|
||||
wxArrayString m_facenames;
|
||||
wxFontEncoding m_encoding;
|
||||
bool m_fixed_width_only;
|
||||
bool m_is_init;
|
||||
public:
|
||||
MyFontEnumerator(wxFontEncoding encoding, bool fixed_width_only)
|
||||
: m_encoding(encoding)
|
||||
, m_fixed_width_only(fixed_width_only)
|
||||
, m_is_init(false)
|
||||
{}
|
||||
const wxArrayString& get_facenames() const{ return m_facenames; }
|
||||
bool is_init() const { return m_is_init; }
|
||||
bool init() {
|
||||
if (m_is_init) return false;
|
||||
m_is_init = true;
|
||||
if (!wxFontEnumerator::EnumerateFacenames(m_encoding, m_fixed_width_only)) return false;
|
||||
if (m_facenames.empty()) return false;
|
||||
std::sort(m_facenames.begin(), m_facenames.end());
|
||||
return true;
|
||||
}
|
||||
wxArrayString m_facenames;
|
||||
wxFontEncoding m_encoding;
|
||||
bool m_fixed_width_only;
|
||||
bool m_is_init;
|
||||
public:
|
||||
MyFontEnumerator()
|
||||
: m_encoding(wxFontEncoding::wxFONTENCODING_SYSTEM)
|
||||
, m_fixed_width_only(false)
|
||||
, m_is_init(false)
|
||||
{}
|
||||
const wxArrayString& get_facenames() const { return m_facenames; }
|
||||
const wxFontEncoding& get_encoding() const { return m_encoding; }
|
||||
bool is_init() const { return m_is_init; }
|
||||
bool init() {
|
||||
if (m_is_init) return false;
|
||||
m_is_init = true;
|
||||
if (!wxFontEnumerator::EnumerateFacenames(m_encoding, m_fixed_width_only)) return false;
|
||||
if (m_facenames.empty()) return false;
|
||||
std::sort(m_facenames.begin(), m_facenames.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> m_efacenames;
|
||||
protected:
|
||||
virtual bool OnFacename(const wxString& facename) wxOVERRIDE {
|
||||
// vertical font start with @, we will filter it out
|
||||
if (facename.empty() || facename[0] == '@') return true;
|
||||
wxFont wx_font(wxFontInfo().FaceName(facename).Encoding(m_encoding));
|
||||
//*
|
||||
if (!WxFontUtils::can_load(wx_font)) return true; // can't load
|
||||
/*/
|
||||
auto ff = WxFontUtils::create_font_file(wx_font);
|
||||
if (ff == nullptr) {
|
||||
m_efacenames.emplace_back(facename.c_str());
|
||||
return true; // can't create font file
|
||||
} // */
|
||||
m_facenames.Add(facename);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
wxFontEncoding encoding = wxFontEncoding::wxFONTENCODING_SYSTEM;
|
||||
bool fixed_width_only = false;
|
||||
static MyFontEnumerator fontEnumerator(encoding, fixed_width_only);
|
||||
void del_facename(const wxString &facename) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef DEBUG_NOT_LOADABLE_FONTS
|
||||
std::vector<std::string> m_efacenames;
|
||||
#endif // DEBUG_NOT_LOADABLE_FONTS
|
||||
|
||||
protected:
|
||||
/// <summary>
|
||||
/// Called by wxFontEnumerator::EnumerateFacenames() for each match.
|
||||
/// </summary>
|
||||
/// <param name="facename">name identificator to load face by wxFont</param>
|
||||
/// <returns> True to continue enumeration or false to stop it.</returns>
|
||||
virtual bool OnFacename(const wxString& facename) wxOVERRIDE {
|
||||
// vertical font start with @, we will filter it out
|
||||
if (facename.empty() || facename[0] == '@') return true;
|
||||
wxFont wx_font(wxFontInfo().FaceName(facename).Encoding(m_encoding));
|
||||
|
||||
//*
|
||||
// Faster chech if wx_font is loadable but not 100%
|
||||
// names could contain not loadable font
|
||||
if (!WxFontUtils::can_load(wx_font)) {
|
||||
#ifdef DEBUG_NOT_LOADABLE_FONTS
|
||||
m_efacenames.emplace_back(facename.c_str());
|
||||
#endif // DEBUG_NOT_LOADABLE_FONTS
|
||||
return true; // can't load
|
||||
}
|
||||
/*/
|
||||
// Slow copy of font files to try load font
|
||||
// After this all files are loadable
|
||||
auto ff = WxFontUtils::create_font_file(wx_font);
|
||||
if (ff == nullptr) {
|
||||
#ifdef DEBUG_NOT_LOADABLE_FONTS
|
||||
m_efacenames.emplace_back(facename.c_str());
|
||||
#endif // DEBUG_NOT_LOADABLE_FONTS
|
||||
return true; // can't create font file
|
||||
} // */
|
||||
m_facenames.Add(facename);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void GLGizmoEmboss::draw_font_list()
|
||||
{
|
||||
static MyFontEnumerator fontEnumerator;
|
||||
std::optional<wxFont> &wx_font_opt = m_font_manager.get_wx_font();
|
||||
wxString actual_face_name = wx_font_opt.has_value() ?
|
||||
wx_font_opt->GetFaceName() : "";
|
||||
const char * selected = (!actual_face_name.empty()) ?
|
||||
actual_face_name.ToUTF8().data() : " --- ";
|
||||
|
||||
wxString del_facename;
|
||||
if (ImGui::BeginCombo("##font_selector", selected)) {
|
||||
if(!fontEnumerator.is_init()) fontEnumerator.init();
|
||||
const wxArrayString &face_names = fontEnumerator.get_facenames();
|
||||
|
@ -1006,7 +1044,7 @@ void GLGizmoEmboss::draw_font_list()
|
|||
if (ImGui::Selectable(face_name.ToUTF8().data(), is_selected) &&
|
||||
wxFontEnumerator::IsValidFacename(face_name)) {
|
||||
// Select font
|
||||
wxFont wx_font(wxFontInfo().FaceName(face_name).Encoding(encoding));
|
||||
wxFont wx_font(wxFontInfo().FaceName(face_name).Encoding(fontEnumerator.get_encoding()));
|
||||
if(m_font_manager.set_wx_font(wx_font))
|
||||
process();
|
||||
}
|
||||
|
@ -1019,6 +1057,10 @@ void GLGizmoEmboss::draw_font_list()
|
|||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
// delete unloadable face name when appear
|
||||
if (!del_facename.empty())
|
||||
fontEnumerator.del_facename(del_facename);
|
||||
|
||||
#ifdef ALLOW_ADD_FONT_BY_FILE
|
||||
ImGui::SameLine();
|
||||
// select font file by file browser
|
||||
|
@ -1318,7 +1360,8 @@ void GLGizmoEmboss::draw_style_list() {
|
|||
m_font_manager = FontManager(m_imgui->get_glyph_ranges());
|
||||
FontList font_list = create_default_font_list();
|
||||
m_font_manager.add_fonts(font_list);
|
||||
// TODO: What to do when NO one default font is loadable?
|
||||
// What to do when NO one default font is loadable?
|
||||
[[maybe_unused]]
|
||||
bool success = m_font_manager.load_first_valid_font();
|
||||
assert(success);
|
||||
select_stored_font_item();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
#include "libslic3r/Emboss.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
@ -207,7 +208,7 @@ private:
|
|||
std::string m_text;
|
||||
|
||||
// cancel for previous update of volume to cancel finalize part
|
||||
std::shared_ptr<bool> m_update_job_cancel;
|
||||
std::shared_ptr<std::atomic<bool>> m_update_job_cancel;
|
||||
|
||||
// actual volume
|
||||
ModelVolume *m_volume;
|
||||
|
|
|
@ -28,12 +28,13 @@ namespace priv{
|
|||
/// <param name="font">Define shape of characters.
|
||||
/// NOTE: Can't be const cache glyphs</param>
|
||||
/// <param name="font_prop">Property of font</param>
|
||||
/// <param name="ctl">Control for job, check of cancelation</param>
|
||||
/// <param name="was_canceled">Lambda returning bool to check if process was canceled</param>
|
||||
/// <returns>Triangle mesh model</returns>
|
||||
template<typename Fnc>
|
||||
static TriangleMesh create_mesh(const char *text,
|
||||
Emboss::FontFileWithCache &font,
|
||||
const FontProp &font_prop,
|
||||
GUI::Job::Ctl &ctl);
|
||||
Fnc was_canceled);
|
||||
/// <summary>
|
||||
/// Create default mesh for embossed text
|
||||
/// </summary>
|
||||
|
@ -46,18 +47,27 @@ static TriangleMesh create_default_mesh();
|
|||
/// Update Volume
|
||||
EmbossUpdateJob::EmbossUpdateJob(EmbossDataUpdate&& input)
|
||||
: m_input(std::move(input))
|
||||
{}
|
||||
{
|
||||
assert(m_input.cancel != nullptr);
|
||||
assert(m_input.font_file.has_value());
|
||||
assert(!m_input.text_configuration.text.empty());
|
||||
}
|
||||
|
||||
void EmbossUpdateJob::process(Ctl &ctl)
|
||||
{
|
||||
auto was_canceled = [&ctl, &cancel = m_input.cancel]()->bool {
|
||||
if (cancel->load()) return true;
|
||||
return ctl.was_canceled();
|
||||
};
|
||||
|
||||
// check if exist valid font
|
||||
if (!m_input.font_file.has_value()) return;
|
||||
|
||||
const TextConfiguration &cfg = m_input.text_configuration;
|
||||
m_result = priv::create_mesh(cfg.text.c_str(), m_input.font_file,
|
||||
cfg.font_item.prop, ctl);
|
||||
cfg.font_item.prop, was_canceled);
|
||||
if (m_result.its.empty()) return;
|
||||
if (ctl.was_canceled()) return;
|
||||
if (was_canceled()) return;
|
||||
|
||||
// center triangle mesh
|
||||
Vec3d shift = m_result.bounding_box().center();
|
||||
|
@ -66,7 +76,7 @@ void EmbossUpdateJob::process(Ctl &ctl)
|
|||
|
||||
void EmbossUpdateJob::finalize(bool canceled, std::exception_ptr &)
|
||||
{
|
||||
if (canceled || *m_input.cancel) return;
|
||||
if (canceled || m_input.cancel->load()) return;
|
||||
|
||||
// for sure that some object is created from shape
|
||||
if (m_result.its.indices.empty()) return;
|
||||
|
@ -133,11 +143,11 @@ void EmbossCreateVolumeJob::process(Ctl &ctl) {
|
|||
// Emboss text window is opened by creation new emboss text object
|
||||
const char *text = m_input.text_configuration.text.c_str();
|
||||
FontProp &prop = m_input.text_configuration.font_item.prop;
|
||||
|
||||
m_result = priv::create_mesh(text, m_input.font_file, prop, ctl);
|
||||
auto was_canceled = [&ctl]()->bool { return ctl.was_canceled(); };
|
||||
m_result = priv::create_mesh(text, m_input.font_file, prop, was_canceled);
|
||||
if (m_result.its.empty()) m_result = priv::create_default_mesh();
|
||||
|
||||
if (ctl.was_canceled()) return;
|
||||
if (was_canceled()) return;
|
||||
|
||||
// Create new volume inside of object
|
||||
const FontProp &font_prop = m_input.text_configuration.font_item.prop;
|
||||
|
@ -217,15 +227,16 @@ void EmbossCreateObjectJob::process(Ctl &ctl)
|
|||
// It is neccessary to create some shape
|
||||
// Emboss text window is opened by creation new emboss text object
|
||||
const char *text = m_input.text_configuration.text.c_str();
|
||||
FontProp &prop = m_input.text_configuration.font_item.prop;
|
||||
FontProp &prop = m_input.text_configuration.font_item.prop;
|
||||
auto was_canceled = [&ctl]()->bool { return ctl.was_canceled(); };
|
||||
if (!m_input.font_file.has_value())
|
||||
m_result = priv::create_default_mesh();
|
||||
else
|
||||
m_result = priv::create_mesh(text, m_input.font_file, prop, ctl);
|
||||
m_result = priv::create_mesh(text, m_input.font_file, prop, was_canceled);
|
||||
if (m_result.its.empty())
|
||||
m_result = priv::create_default_mesh();
|
||||
|
||||
if (ctl.was_canceled()) return;
|
||||
if (was_canceled()) return;
|
||||
|
||||
// Create new object
|
||||
// calculate X,Y offset position for lay on platter in place of
|
||||
|
@ -281,24 +292,25 @@ void EmbossCreateObjectJob::finalize(bool canceled, std::exception_ptr &)
|
|||
|
||||
////////////////////////////
|
||||
/// private namespace implementation
|
||||
template<typename Fnc>
|
||||
TriangleMesh priv::create_mesh(const char *text,
|
||||
Emboss::FontFileWithCache &font,
|
||||
const FontProp &font_prop,
|
||||
GUI::Job::Ctl &ctl)
|
||||
Fnc was_canceled)
|
||||
{
|
||||
assert(font.has_value());
|
||||
if (!font.has_value()) return {};
|
||||
|
||||
ExPolygons shapes = Emboss::text2shapes(font, text, font_prop);
|
||||
if (shapes.empty()) return {};
|
||||
if (ctl.was_canceled()) return {};
|
||||
if (was_canceled()) return {};
|
||||
|
||||
int unit_per_em = font.font_file->unit_per_em;
|
||||
float scale = font_prop.size_in_mm / unit_per_em;
|
||||
float depth = font_prop.emboss / scale;
|
||||
auto projectZ = std::make_unique<Emboss::ProjectZ>(depth);
|
||||
Emboss::ProjectScale project(std::move(projectZ), scale);
|
||||
if (ctl.was_canceled()) return {};
|
||||
if (was_canceled()) return {};
|
||||
return TriangleMesh(Emboss::polygons2model(shapes, project));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef slic3r_EmbossJob_hpp_
|
||||
#define slic3r_EmbossJob_hpp_
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <libslic3r/Emboss.hpp>
|
||||
#include <libslic3r/ModelVolumeType.hpp>
|
||||
#include "slic3r/Utils/RaycastManager.hpp"
|
||||
|
@ -37,7 +40,7 @@ struct EmbossDataUpdate : public EmbossDataBase
|
|||
|
||||
// flag that job is canceled
|
||||
// for time after process.
|
||||
std::shared_ptr<bool> cancel;
|
||||
std::shared_ptr<std::atomic<bool> > cancel;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
@ -83,14 +86,20 @@ struct EmbossDataCreateObject : public EmbossDataBase
|
|||
|
||||
/// <summary>
|
||||
/// Update text shape in existing text volume
|
||||
/// Predict that there is only one runnig(not canceled) instance of it
|
||||
/// </summary>
|
||||
class EmbossUpdateJob : public Job
|
||||
{
|
||||
EmbossDataUpdate m_input;
|
||||
TriangleMesh m_result;
|
||||
|
||||
public:
|
||||
// only move params to private variable
|
||||
EmbossUpdateJob(EmbossDataUpdate&& input);
|
||||
|
||||
/// <summary>
|
||||
/// Create volume movel by input data
|
||||
/// </summary>
|
||||
/// <param name="ctl">Control containing cancel flag</param>
|
||||
void process(Ctl &ctl) override;
|
||||
|
||||
/// <summary>
|
||||
|
@ -106,6 +115,7 @@ public:
|
|||
|
||||
/// <summary>
|
||||
/// Create new TextVolume on the surface of ModelObject
|
||||
/// Should not be stopped
|
||||
/// </summary>
|
||||
class EmbossCreateVolumeJob : public Job
|
||||
{
|
||||
|
@ -121,6 +131,7 @@ public:
|
|||
|
||||
/// <summary>
|
||||
/// Create new TextObject on the platter
|
||||
/// Should not be stopped
|
||||
/// </summary>
|
||||
class EmbossCreateObjectJob : public Job
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue