mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-26 18:21:18 -06:00
Merge branch 'master' of https://github.com/Prusa3d/PrusaSlicer
This commit is contained in:
commit
03bb8a60a3
23 changed files with 354 additions and 97 deletions
|
|
@ -1337,7 +1337,9 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const
|
|||
}
|
||||
}
|
||||
|
||||
#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
|
||||
#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
|
||||
|
|
@ -1378,7 +1380,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
|
|||
, m_retina_helper(nullptr)
|
||||
#endif
|
||||
, m_in_render(false)
|
||||
, m_render_enabled(true)
|
||||
, m_bed(bed)
|
||||
, m_camera(camera)
|
||||
, m_view_toolbar(view_toolbar)
|
||||
|
|
@ -1508,7 +1509,9 @@ bool GLCanvas3D::init()
|
|||
if (m_selection.is_enabled() && !m_selection.init())
|
||||
return false;
|
||||
|
||||
#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_INIT));
|
||||
#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
m_initialized = true;
|
||||
|
||||
|
|
@ -1791,7 +1794,7 @@ void GLCanvas3D::update_volumes_colors_by_extruder()
|
|||
|
||||
void GLCanvas3D::render()
|
||||
{
|
||||
if (!m_render_enabled || m_in_render)
|
||||
if (m_in_render)
|
||||
{
|
||||
// if called recursively, return
|
||||
m_dirty = true;
|
||||
|
|
@ -4217,6 +4220,11 @@ bool GLCanvas3D::_init_toolbars()
|
|||
if (!_init_undoredo_toolbar())
|
||||
return false;
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
if (!_init_view_toolbar())
|
||||
return false;
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -4474,6 +4482,13 @@ bool GLCanvas3D::_init_undoredo_toolbar()
|
|||
return true;
|
||||
}
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
bool GLCanvas3D::_init_view_toolbar()
|
||||
{
|
||||
return wxGetApp().plater()->init_view_toolbar();
|
||||
}
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
bool GLCanvas3D::_set_current()
|
||||
{
|
||||
return m_context != nullptr && m_canvas->SetCurrent(*m_context);
|
||||
|
|
|
|||
|
|
@ -83,7 +83,9 @@ template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>;
|
|||
|
||||
using HeightProfileSmoothEvent = Event<HeightProfileSmoothingParams>;
|
||||
|
||||
#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
|
||||
#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
|
||||
|
|
@ -417,7 +419,6 @@ private:
|
|||
std::unique_ptr<RetinaHelper> m_retina_helper;
|
||||
#endif
|
||||
bool m_in_render;
|
||||
bool m_render_enabled;
|
||||
LegendTexture m_legend_texture;
|
||||
WarningTexture m_warning_texture;
|
||||
wxTimer m_timer;
|
||||
|
|
@ -555,9 +556,6 @@ public:
|
|||
void enable_dynamic_background(bool enable);
|
||||
void allow_multisample(bool allow);
|
||||
|
||||
void enable_render(bool enable) { m_render_enabled = enable; }
|
||||
bool is_render_enabled() const { return m_render_enabled; }
|
||||
|
||||
void zoom_to_bed();
|
||||
void zoom_to_volumes();
|
||||
void zoom_to_selection();
|
||||
|
|
@ -685,6 +683,9 @@ private:
|
|||
bool _init_toolbars();
|
||||
bool _init_main_toolbar();
|
||||
bool _init_undoredo_toolbar();
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
bool _init_view_toolbar();
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
bool _set_current();
|
||||
void _resize(unsigned int w, unsigned int h);
|
||||
|
|
|
|||
|
|
@ -293,6 +293,9 @@ public:
|
|||
|
||||
bool is_any_item_pressed() const;
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
unsigned int get_items_count() const { return (unsigned int)m_items.size(); }
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
int get_item_id(const std::string& name) const;
|
||||
|
||||
void force_left_action(int item_id, GLCanvas3D& parent) { do_action(GLToolbarItem::Left, item_id, parent, false); }
|
||||
|
|
|
|||
|
|
@ -466,6 +466,9 @@ void GUI_App::recreate_GUI()
|
|||
|
||||
dlg.Update(30, _(L("Recreating")) + dots);
|
||||
topwindow->Destroy();
|
||||
|
||||
// For this moment ConfigWizard is deleted, invalidate it
|
||||
m_wizard = nullptr;
|
||||
}
|
||||
|
||||
dlg.Update(80, _(L("Loading of current presets")) + dots);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,13 @@ std::string GLGizmoMove3D::on_get_name() const
|
|||
return (_(L("Move")) + " [M]").ToUTF8().data();
|
||||
}
|
||||
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
bool GLGizmoMove3D::on_is_activable() const
|
||||
{
|
||||
return !m_parent.get_selection().is_empty();
|
||||
}
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
|
||||
void GLGizmoMove3D::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ public:
|
|||
protected:
|
||||
virtual bool on_init();
|
||||
virtual std::string on_get_name() const;
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
virtual bool on_is_activable() const;
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_stop_dragging();
|
||||
virtual void on_update(const UpdateData& data);
|
||||
|
|
|
|||
|
|
@ -449,6 +449,13 @@ std::string GLGizmoRotate3D::on_get_name() const
|
|||
return (_(L("Rotate")) + " [R]").ToUTF8().data();
|
||||
}
|
||||
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
bool GLGizmoRotate3D::on_is_activable() const
|
||||
{
|
||||
return !m_parent.get_selection().is_empty();
|
||||
}
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
|
||||
void GLGizmoRotate3D::on_start_dragging()
|
||||
{
|
||||
if ((0 <= m_hover_id) && (m_hover_id < 3))
|
||||
|
|
|
|||
|
|
@ -104,6 +104,9 @@ protected:
|
|||
if (id < 3)
|
||||
m_gizmos[id].disable_grabber(0);
|
||||
}
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
virtual bool on_is_activable() const;
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_stop_dragging();
|
||||
virtual void on_update(const UpdateData& data)
|
||||
|
|
|
|||
|
|
@ -49,7 +49,12 @@ std::string GLGizmoScale3D::on_get_name() const
|
|||
|
||||
bool GLGizmoScale3D::on_is_activable() const
|
||||
{
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
return !selection.is_empty() && !selection.is_wipe_tower();
|
||||
#else
|
||||
return !m_parent.get_selection().is_wipe_tower();
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_start_dragging()
|
||||
|
|
|
|||
|
|
@ -885,7 +885,11 @@ void GLGizmosManager::do_render_overlay() const
|
|||
GLGizmoBase* gizmo = m_gizmos[idx].get();
|
||||
|
||||
unsigned int sprite_id = gizmo->get_sprite_id();
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
int icon_idx = (m_current == idx) ? 2 : ((m_hover == idx) ? 1 : (gizmo->is_activable()? 0 : 3));
|
||||
#else
|
||||
int icon_idx = m_current == idx ? 2 : (m_hover == idx ? 1 : 0);
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
|
||||
float u_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_width;
|
||||
float v_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_height;
|
||||
|
|
@ -951,9 +955,12 @@ bool GLGizmosManager::generate_icons_texture() const
|
|||
}
|
||||
|
||||
std::vector<std::pair<int, bool>> states;
|
||||
states.push_back(std::make_pair(1, false));
|
||||
states.push_back(std::make_pair(0, false));
|
||||
states.push_back(std::make_pair(0, true));
|
||||
states.push_back(std::make_pair(1, false)); // Activable
|
||||
states.push_back(std::make_pair(0, false)); // Hovered
|
||||
states.push_back(std::make_pair(0, true)); // Selected
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
states.push_back(std::make_pair(2, false)); // Disabled
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
|
||||
unsigned int sprite_size_px = (unsigned int)(m_overlay_icons_size * m_overlay_scale);
|
||||
// // force even size
|
||||
|
|
|
|||
|
|
@ -129,10 +129,9 @@ MeshRaycaster::MeshRaycaster(const TriangleMesh& mesh)
|
|||
{
|
||||
}
|
||||
|
||||
MeshRaycaster::~MeshRaycaster()
|
||||
{
|
||||
delete m_AABB_wrapper;
|
||||
}
|
||||
// Define the default destructor here. This is needed for the PIMPL with
|
||||
// unique_ptr to work, the AABBWrapper is complete here.
|
||||
MeshRaycaster::~MeshRaycaster() = default;
|
||||
|
||||
Vec3f MeshRaycaster::AABBWrapper::get_hit_pos(const igl::Hit& hit) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace GUI {
|
|||
struct Camera;
|
||||
|
||||
|
||||
|
||||
// lm_FIXME: Following class might possibly be replaced by Eigen::Hyperplane
|
||||
class ClippingPlane
|
||||
{
|
||||
double m_data[4];
|
||||
|
|
@ -67,13 +67,23 @@ public:
|
|||
};
|
||||
|
||||
|
||||
|
||||
// MeshClipper class cuts a mesh and is able to return a triangulated cut.
|
||||
class MeshClipper {
|
||||
public:
|
||||
// Inform MeshClipper about which plane we want to use to cut the mesh
|
||||
// This is supposed to be in world coordinates.
|
||||
void set_plane(const ClippingPlane& plane);
|
||||
|
||||
// Which mesh to cut. MeshClipper remembers const * to it, caller
|
||||
// must make sure that it stays valid.
|
||||
void set_mesh(const TriangleMesh& mesh);
|
||||
|
||||
// Inform the MeshClipper about the transformation that transforms the mesh
|
||||
// into world coordinates.
|
||||
void set_transformation(const Geometry::Transformation& trafo);
|
||||
|
||||
// Return the triangulated cut. The points are returned directly
|
||||
// in world coordinates.
|
||||
const std::vector<Vec3f>& get_triangles();
|
||||
|
||||
private:
|
||||
|
|
@ -90,26 +100,45 @@ private:
|
|||
|
||||
|
||||
|
||||
|
||||
// MeshRaycaster class answers queries such as where on the mesh someone clicked,
|
||||
// whether certain points are visible or obscured by the mesh etc.
|
||||
class MeshRaycaster {
|
||||
public:
|
||||
// The class saves a const* to the mesh, called is responsible
|
||||
// for making sure it does not get invalid.
|
||||
MeshRaycaster(const TriangleMesh& mesh);
|
||||
|
||||
~MeshRaycaster();
|
||||
void set_transformation(const Geometry::Transformation& trafo);
|
||||
void set_camera(const Camera& camera);
|
||||
|
||||
bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||
Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane = nullptr) const;
|
||||
// Given a mouse position, this returns true in case it is on the mesh.
|
||||
bool unproject_on_mesh(
|
||||
const Vec2d& mouse_pos,
|
||||
const Transform3d& trafo, // how to get the mesh into world coords
|
||||
const Camera& camera, // current camera position
|
||||
Vec3f& position, // where to save the positibon of the hit (mesh coords)
|
||||
Vec3f& normal, // normal of the triangle that was hit
|
||||
const ClippingPlane* clipping_plane = nullptr // clipping plane (if active)
|
||||
) const;
|
||||
|
||||
std::vector<unsigned> get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera,
|
||||
const std::vector<Vec3f>& points, const ClippingPlane* clipping_plane = nullptr) const;
|
||||
// Given a vector of points in woorld coordinates, this returns vector
|
||||
// of indices of points that are visible (i.e. not cut by clipping plane
|
||||
// or obscured by part of the mesh.
|
||||
std::vector<unsigned> get_unobscured_idxs(
|
||||
const Geometry::Transformation& trafo, // how to get the mesh into world coords
|
||||
const Camera& camera, // current camera position
|
||||
const std::vector<Vec3f>& points, // points in world coords
|
||||
const ClippingPlane* clipping_plane = nullptr // clipping plane (if active)
|
||||
) const;
|
||||
|
||||
// Given a point in world coords, the method returns closest point on the mesh.
|
||||
// The output is in mesh coords.
|
||||
// normal* can be used to also get normal of the respective triangle.
|
||||
Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const;
|
||||
|
||||
private:
|
||||
// PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here
|
||||
class AABBWrapper;
|
||||
AABBWrapper* m_AABB_wrapper;
|
||||
std::unique_ptr<AABBWrapper> m_AABB_wrapper;
|
||||
const TriangleMesh* m_mesh = nullptr;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1819,6 +1819,10 @@ struct Plater::priv
|
|||
bool is_preview_loaded() const { return preview->is_loaded(); }
|
||||
bool is_view3D_shown() const { return current_panel == view3D; }
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
bool init_view_toolbar();
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
void reset_all_gizmos();
|
||||
void update_ui_from_settings();
|
||||
ProgressStatusBar* statusbar();
|
||||
|
|
@ -1964,7 +1968,9 @@ private:
|
|||
bool complit_init_object_menu();
|
||||
bool complit_init_sla_object_menu();
|
||||
bool complit_init_part_menu();
|
||||
#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
void init_view_toolbar();
|
||||
#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
bool can_split() const;
|
||||
bool layers_height_allowed() const;
|
||||
|
|
@ -2116,7 +2122,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_OBJECTS, &priv::on_action_split_objects, this);
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_VOLUMES, &priv::on_action_split_volumes, this);
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_LAYERSEDITING, &priv::on_action_layersediting, this);
|
||||
#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_INIT, [this](SimpleEvent&) { init_view_toolbar(); });
|
||||
#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [this](SimpleEvent&)
|
||||
{
|
||||
set_bed_shape(config->option<ConfigOptionPoints>("bed_shape")->values,
|
||||
|
|
@ -3221,7 +3229,6 @@ void Plater::priv::reload_from_disk()
|
|||
catch (std::exception&)
|
||||
{
|
||||
// error while loading
|
||||
view3D->get_canvas3d()->enable_render(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3833,8 +3840,18 @@ bool Plater::priv::complit_init_part_menu()
|
|||
return true;
|
||||
}
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
bool Plater::priv::init_view_toolbar()
|
||||
#else
|
||||
void Plater::priv::init_view_toolbar()
|
||||
#endif //!ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
{
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
if (view_toolbar.get_items_count() > 0)
|
||||
// already initialized
|
||||
return true;
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
BackgroundTexture::Metadata background_data;
|
||||
background_data.filename = "toolbar_background.png";
|
||||
background_data.left = 16;
|
||||
|
|
@ -3843,7 +3860,11 @@ void Plater::priv::init_view_toolbar()
|
|||
background_data.bottom = 16;
|
||||
|
||||
if (!view_toolbar.init(background_data))
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
return false;
|
||||
#else
|
||||
return;
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
view_toolbar.set_horizontal_orientation(GLToolbar::Layout::HO_Left);
|
||||
view_toolbar.set_vertical_orientation(GLToolbar::Layout::VO_Bottom);
|
||||
|
|
@ -3858,7 +3879,11 @@ void Plater::priv::init_view_toolbar()
|
|||
item.sprite_id = 0;
|
||||
item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); };
|
||||
if (!view_toolbar.add_item(item))
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
return false;
|
||||
#else
|
||||
return;
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
item.name = "Preview";
|
||||
item.icon_filename = "preview.svg";
|
||||
|
|
@ -3866,10 +3891,18 @@ void Plater::priv::init_view_toolbar()
|
|||
item.sprite_id = 1;
|
||||
item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); };
|
||||
if (!view_toolbar.add_item(item))
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
return false;
|
||||
#else
|
||||
return;
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
view_toolbar.select_item("3D");
|
||||
view_toolbar.set_enabled(true);
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
return true;
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
}
|
||||
|
||||
bool Plater::priv::can_set_instance_to_object() const
|
||||
|
|
@ -5242,6 +5275,13 @@ void Plater::msw_rescale()
|
|||
GetParent()->Layout();
|
||||
}
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
bool Plater::init_view_toolbar()
|
||||
{
|
||||
return p->init_view_toolbar();
|
||||
}
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
const Camera& Plater::get_camera() const
|
||||
{
|
||||
return p->camera;
|
||||
|
|
|
|||
|
|
@ -261,6 +261,10 @@ public:
|
|||
|
||||
void msw_rescale();
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
bool init_view_toolbar();
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
const Camera& get_camera() const;
|
||||
const Mouse3DController& get_mouse3d_controller() const;
|
||||
Mouse3DController& get_mouse3d_controller();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue