Almost working c++ status bar

Signed-off-by: tamasmeszaros <meszaros.q@gmail.com>
This commit is contained in:
tamasmeszaros 2018-08-29 18:02:10 +02:00
parent 5ee106fbf9
commit 9e2d48ff3b
13 changed files with 442 additions and 156 deletions

View File

@ -62,13 +62,14 @@ sub new {
eval { Wx::ToolTip::SetAutoPop(32767) };
# initialize status bar
$self->{statusbar} = Slic3r::GUI::ProgressStatusBar->new($self, Wx::NewId);
$self->{statusbar} = Slic3r::GUI::ProgressStatusBar->new();
# $self->{statusbar}->SetParent($self, Wx::NewId);
$self->{statusbar}->Embed;
$self->{statusbar}->SetStatusText(L("Version ").$Slic3r::VERSION.L(" - Remember to check for updates at http://github.com/prusa3d/slic3r/releases"));
$self->SetStatusBar($self->{statusbar});
# Make the global status bar and its progress indicator available in C++
$appController->set_global_progress_indicator(
$self->{statusbar}->{prog}->GetId(),
$self->{statusbar}->GetProgId(),
$self->{statusbar}->GetId(),
);

View File

@ -4,141 +4,143 @@ package Slic3r::GUI::ProgressStatusBar;
use strict;
use warnings;
use Wx qw(:gauge :misc);
use base 'Wx::StatusBar';
# use Wx qw(:gauge :misc);
# use base 'Wx::StatusBar';
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
$self->{busy} = 0;
$self->{timer} = Wx::Timer->new($self);
$self->{prog} = Wx::Gauge->new($self, wxGA_HORIZONTAL, 100, wxDefaultPosition, wxDefaultSize);
$self->{prog}->Hide;
$self->{cancelbutton} = Wx::Button->new($self, -1, "Cancel", wxDefaultPosition, wxDefaultSize);
$self->{cancelbutton}->Hide;
$self->SetFieldsCount(3);
$self->SetStatusWidths(-1, 150, 155);
Wx::Event::EVT_TIMER($self, \&OnTimer, $self->{timer});
Wx::Event::EVT_SIZE($self, \&OnSize);
Wx::Event::EVT_BUTTON($self, $self->{cancelbutton}, sub {
$self->{cancel_cb}->();
$self->{cancelbutton}->Hide;
});
return $self;
}
our $cancel_cb;
sub DESTROY {
my $self = shift;
$self->{timer}->Stop if $self->{timer} && $self->{timer}->IsRunning;
}
sub OnSize {
my ($self, $event) = @_;
# sub new {
# my $class = shift;
# my $self = $class->SUPER::new(@_);
my %fields = (
# 0 is reserved for status text
1 => $self->{cancelbutton},
2 => $self->{prog},
);
foreach (keys %fields) {
my $rect = $self->GetFieldRect($_);
my $offset = &Wx::wxGTK ? 1 : 0; # add a cosmetic 1 pixel offset on wxGTK
my $pos = [$rect->GetX + $offset, $rect->GetY + $offset];
$fields{$_}->Move($pos);
$fields{$_}->SetSize($rect->GetWidth - $offset, $rect->GetHeight);
}
$event->Skip;
}
sub OnTimer {
my ($self, $event) = @_;
# $self->{busy} = 0;
# $self->{timer} = Wx::Timer->new($self);
# $self->{prog} = Wx::Gauge->new($self, wxGA_HORIZONTAL, 100, wxDefaultPosition, wxDefaultSize);
# $self->{prog}->Hide;
# $self->{cancelbutton} = Wx::Button->new($self, -1, "Cancel", wxDefaultPosition, wxDefaultSize);
# $self->{cancelbutton}->Hide;
if ($self->{prog}->IsShown) {
$self->{timer}->Stop;
}
$self->{prog}->Pulse if $self->{_busy};
}
# $self->SetFieldsCount(3);
# $self->SetStatusWidths(-1, 150, 155);
# Wx::Event::EVT_TIMER($self, \&OnTimer, $self->{timer});
# Wx::Event::EVT_SIZE($self, \&OnSize);
# Wx::Event::EVT_BUTTON($self, $self->{cancelbutton}, sub {
# $self->{cancel_cb}->();
# $self->{cancelbutton}->Hide;
# });
# return $self;
# }
# sub DESTROY {
# my $self = shift;
# $self->{timer}->Stop if $self->{timer} && $self->{timer}->IsRunning;
# }
# sub OnSize {
# my ($self, $event) = @_;
# my %fields = (
# # 0 is reserved for status text
# 1 => $self->{cancelbutton},
# 2 => $self->{prog},
# );
# foreach (keys %fields) {
# my $rect = $self->GetFieldRect($_);
# my $offset = &Wx::wxGTK ? 1 : 0; # add a cosmetic 1 pixel offset on wxGTK
# my $pos = [$rect->GetX + $offset, $rect->GetY + $offset];
# $fields{$_}->Move($pos);
# $fields{$_}->SetSize($rect->GetWidth - $offset, $rect->GetHeight);
# }
# $event->Skip;
# }
# sub OnTimer {
# my ($self, $event) = @_;
# if ($self->{prog}->IsShown) {
# $self->{timer}->Stop;
# }
# $self->{prog}->Pulse if $self->{_busy};
# }
sub SetCancelCallback {
my $self = shift;
my ($cb) = @_;
$self->{cancel_cb} = $cb;
$cb ? $self->{cancelbutton}->Show : $self->{cancelbutton}->Hide;
$cancel_cb = $cb;
# $cb ? $self->{cancelbutton}->Show : $self->{cancelbutton}->Hide;
}
sub Run {
my $self = shift;
my $rate = shift || 100;
if (!$self->{timer}->IsRunning) {
$self->{timer}->Start($rate);
}
}
# sub Run {
# my $self = shift;
# my $rate = shift || 100;
# if (!$self->{timer}->IsRunning) {
# $self->{timer}->Start($rate);
# }
# }
sub GetProgress {
my $self = shift;
return $self->{prog}->GetValue;
}
# sub GetProgress {
# my $self = shift;
# return $self->{prog}->GetValue;
# }
sub SetProgress {
my $self = shift;
my ($val) = @_;
if (!$self->{prog}->IsShown) {
$self->ShowProgress(1);
}
if ($val == $self->{prog}->GetRange) {
$self->{prog}->SetValue(0);
$self->ShowProgress(0);
} else {
$self->{prog}->SetValue($val);
}
}
# sub SetProgress {
# my $self = shift;
# my ($val) = @_;
# if (!$self->{prog}->IsShown) {
# $self->ShowProgress(1);
# }
# if ($val == $self->{prog}->GetRange) {
# $self->{prog}->SetValue(0);
# $self->ShowProgress(0);
# } else {
# $self->{prog}->SetValue($val);
# }
# }
sub SetRange {
my $self = shift;
my ($val) = @_;
# sub SetRange {
# my $self = shift;
# my ($val) = @_;
if ($val != $self->{prog}->GetRange) {
$self->{prog}->SetRange($val);
}
}
# if ($val != $self->{prog}->GetRange) {
# $self->{prog}->SetRange($val);
# }
# }
sub ShowProgress {
my $self = shift;
my ($show) = @_;
# sub ShowProgress {
# my $self = shift;
# my ($show) = @_;
$self->{prog}->Show($show);
$self->{prog}->Pulse;
}
# $self->{prog}->Show($show);
# $self->{prog}->Pulse;
# }
sub StartBusy {
my $self = shift;
my $rate = shift || 100;
# sub StartBusy {
# my $self = shift;
# my $rate = shift || 100;
$self->{_busy} = 1;
$self->ShowProgress(1);
if (!$self->{timer}->IsRunning) {
$self->{timer}->Start($rate);
}
}
# $self->{_busy} = 1;
# $self->ShowProgress(1);
# if (!$self->{timer}->IsRunning) {
# $self->{timer}->Start($rate);
# }
# }
sub StopBusy {
my $self = shift;
# sub StopBusy {
# my $self = shift;
$self->{timer}->Stop;
$self->ShowProgress(0);
$self->{prog}->SetValue(0);
$self->{_busy} = 0;
}
# $self->{timer}->Stop;
# $self->ShowProgress(0);
# $self->{prog}->SetValue(0);
# $self->{_busy} = 0;
# }
sub IsBusy {
my $self = shift;
return $self->{_busy};
}
# sub IsBusy {
# my $self = shift;
# return $self->{_busy};
# }
1;

View File

@ -247,6 +247,8 @@ add_library(libslic3r_gui STATIC
${LIBDIR}/slic3r/GUI/UpdateDialogs.hpp
${LIBDIR}/slic3r/GUI/FirmwareDialog.cpp
${LIBDIR}/slic3r/GUI/FirmwareDialog.hpp
${LIBDIR}/slic3r/GUI/ProgressStatusBar.hpp
${LIBDIR}/slic3r/GUI/ProgressStatusBar.cpp
${LIBDIR}/slic3r/Utils/Http.cpp
${LIBDIR}/slic3r/Utils/Http.hpp
${LIBDIR}/slic3r/Utils/FixModelByWin10.cpp
@ -267,7 +269,7 @@ add_library(libslic3r_gui STATIC
${LIBDIR}/slic3r/Utils/Time.hpp
${LIBDIR}/slic3r/Utils/HexFile.cpp
${LIBDIR}/slic3r/Utils/HexFile.hpp
${LIBDIR}/slic3r/IProgressIndicator.hpp
${LIBDIR}/slic3r/ProgressIndicator.hpp
${LIBDIR}/slic3r/AppController.hpp
${LIBDIR}/slic3r/AppController.cpp
${LIBDIR}/slic3r/AppControllerWx.cpp
@ -420,6 +422,7 @@ set(XS_XSP_FILES
${XSP_DIR}/Utils_PrintHost.xsp
${XSP_DIR}/Utils_PresetUpdater.xsp
${XSP_DIR}/AppController.xsp
${XSP_DIR}/ProgressStatusBar.xsp
${XSP_DIR}/XS.xsp
)
foreach (file ${XS_XSP_FILES})

View File

@ -63,6 +63,7 @@ REGISTER_CLASS(Preset, "GUI::Preset");
REGISTER_CLASS(PresetCollection, "GUI::PresetCollection");
REGISTER_CLASS(PresetBundle, "GUI::PresetBundle");
REGISTER_CLASS(TabIface, "GUI::Tab");
REGISTER_CLASS(ProgressStatusBar, "GUI::ProgressStatusBar");
REGISTER_CLASS(PresetUpdater, "PresetUpdater");
REGISTER_CLASS(AppController, "AppController");
REGISTER_CLASS(PrintController, "PrintController");

View File

@ -290,26 +290,22 @@ const PrintConfig &PrintController::config() const
void AppController::arrange_model()
{
auto ftr = std::async(
supports_asynch()? std::launch::async : std::launch::deferred,
[this]()
{
using Coord = libnest2d::TCoord<libnest2d::PointImpl>;
using Coord = libnest2d::TCoord<libnest2d::PointImpl>;
unsigned count = 0;
for(auto obj : model_->objects) count += obj->instances.size();
unsigned count = 0;
for(auto obj : model_->objects) count += obj->instances.size();
auto pind = global_progress_indicator();
auto pind = global_progress_indicator();
float pmax = 1.0;
float pmax = 1.0;
if(pind) {
pmax = pind->max();
if(pind) {
pmax = pind->max();
// Set the range of the progress to the object count
pind->max(count);
// Set the range of the progress to the object count
pind->max(count);
}
}
auto dist = print_ctl()->config().min_object_distance();
@ -341,16 +337,38 @@ void AppController::arrange_model()
_(L("Exception occurred")));
}
// Restore previous max value
if(pind) {
pind->max(pmax);
pind->update(0, _(L("Arranging done.")));
}
});
// Create the arranger config
auto min_obj_distance = static_cast<Coord>(dist/SCALING_FACTOR);
while( ftr.wait_for(std::chrono::milliseconds(10))
!= std::future_status::ready) {
process_events();
auto& bedpoints = print_ctl()->config().bed_shape.values;
Polyline bed; bed.points.reserve(bedpoints.size());
for(auto& v : bedpoints)
bed.append(Point::new_scale(v(0), v(1)));
if(pind) pind->update(0, _(L("Arranging objects...")));
try {
arr::arrange(*model_,
min_obj_distance,
bed,
arr::BOX,
false, // create many piles not just one pile
[pind, count](unsigned rem) {
if(pind)
pind->update(count - rem, _(L("Arranging objects...")));
});
} catch(std::exception& e) {
std::cerr << e.what() << std::endl;
report_issue(IssueType::ERR,
_(L("Could not arrange model objects! "
"Some geometries may be invalid.")),
_(L("Exception occurred")));
}
// Restore previous max value
if(pind) {
pind->max(pmax);
pind->update(0, _(L("Arranging done.")));
}
}

View File

@ -7,7 +7,7 @@
#include <atomic>
#include <iostream>
#include "IProgressIndicator.hpp"
#include "ProgressIndicator.hpp"
namespace Slic3r {
@ -33,7 +33,7 @@ class AppControllerBoilerplate {
public:
/// A Progress indicator object smart pointer
using ProgresIndicatorPtr = std::shared_ptr<IProgressIndicator>;
using ProgresIndicatorPtr = std::shared_ptr<ProgressIndicator>;
private:
class PriData; // Some structure to store progress indication data

View File

@ -104,10 +104,10 @@ namespace {
* the main thread as well.
*/
class GuiProgressIndicator:
public IProgressIndicator, public wxEvtHandler {
public ProgressIndicator, public wxEvtHandler {
wxProgressDialog gauge_;
using Base = IProgressIndicator;
using Base = ProgressIndicator;
wxString message_;
int range_; wxString title_;
bool is_asynch_ = false;
@ -153,7 +153,7 @@ public:
virtual void cancel() override {
update(max(), "Abort");
IProgressIndicator::cancel();
ProgressIndicator::cancel();
}
virtual void state(float val) override {
@ -211,10 +211,10 @@ AppControllerBoilerplate::create_progress_indicator(unsigned statenum,
namespace {
// A wrapper progress indicator class around the statusbar created in perl.
class Wrapper: public IProgressIndicator, public wxEvtHandler {
class Wrapper: public ProgressIndicator, public wxEvtHandler {
wxGauge *gauge_;
wxStatusBar *stbar_;
using Base = IProgressIndicator;
using Base = ProgressIndicator;
std::string message_;
AppControllerBoilerplate& ctl_;
@ -223,7 +223,7 @@ class Wrapper: public IProgressIndicator, public wxEvtHandler {
}
void _state(unsigned st) {
if( st <= IProgressIndicator::max() ) {
if( st <= ProgressIndicator::max() ) {
Base::state(st);
if(!gauge_->IsShown()) showProgress(true);
@ -266,7 +266,7 @@ public:
virtual void max(float val) override {
if(val > 1.0) {
gauge_->SetRange(static_cast<int>(val));
IProgressIndicator::max(val);
ProgressIndicator::max(val);
}
}

View File

@ -0,0 +1,156 @@
#include "ProgressStatusBar.hpp"
#include <wx/timer.h>
#include <wx/gauge.h>
#include <wx/button.h>
#include <wx/statusbr.h>
#include <wx/frame.h>
#include "GUI.hpp"
#include <iostream>
namespace Slic3r {
ProgressStatusBar::ProgressStatusBar(wxWindow *parent, int id):
self(new wxStatusBar(parent ? parent : GUI::get_main_frame(),
id == -1? wxID_ANY : id)),
timer_(new wxTimer(self)),
prog_ (new wxGauge(self,
wxGA_HORIZONTAL,
100,
wxDefaultPosition,
wxDefaultSize)),
cancelbutton_(new wxButton(self,
-1,
"Cancel",
wxDefaultPosition,
wxDefaultSize))
{
prog_->Hide();
cancelbutton_->Hide();
self->SetFieldsCount(3);
int w[] = {-1, 150, 155};
self->SetStatusWidths(3, w);
self->Bind(wxEVT_TIMER, [this](const wxTimerEvent&) {
if (prog_->IsShown()) timer_->Stop();
if(is_busy()) prog_->Pulse();
});
self->Bind(wxEVT_SIZE, [this](wxSizeEvent& event){
wxRect rect;
self->GetFieldRect(1, rect);
auto offset = 0;
cancelbutton_->Move(rect.GetX() + offset, rect.GetY() + offset);
cancelbutton_->SetSize(rect.GetWidth() - offset, rect.GetHeight());
self->GetFieldRect(2, rect);
prog_->Move(rect.GetX() + offset, rect.GetY() + offset);
prog_->SetSize(rect.GetWidth() - offset, rect.GetHeight());
event.Skip();
});
cancelbutton_->Bind(wxEVT_BUTTON, [this](const wxCommandEvent&) {
if(cancel_cb_) cancel_cb_();
cancelbutton_->Hide();
});
}
//ProgressStatusBar::ProgressStatusBar(): ProgressStatusBar(nullptr, wxID_ANY)
//{
//}
ProgressStatusBar::~ProgressStatusBar() {
if(timer_->IsRunning()) timer_->Stop();
}
int ProgressStatusBar::get_progress() const
{
return prog_->GetValue();
}
void ProgressStatusBar::set_progress(int val)
{
if(!prog_->IsShown()) show_progress(true);
if(val == prog_->GetRange()) {
prog_->SetValue(0);
show_progress(false);
} else {
prog_->SetValue(val);
}
}
void ProgressStatusBar::set_range(int val)
{
if(val != prog_->GetRange()) {
prog_->SetRange(val);
}
}
void ProgressStatusBar::show_progress(bool show)
{
prog_->Show(show);
prog_->Pulse();
}
void ProgressStatusBar::start_busy(int rate)
{
busy_ = true;
show_progress(true);
if (!timer_->IsRunning()) {
timer_->Start(rate);
}
}
void ProgressStatusBar::stop_busy()
{
timer_->Stop();
show_progress(false);
prog_->SetValue(0);
busy_ = false;
}
void ProgressStatusBar::set_cancel_callback(ProgressStatusBar::CancelFn ccb) {
cancel_cb_ = ccb;
if(ccb) cancelbutton_->Show();
else cancelbutton_->Hide();
}
void ProgressStatusBar::run(int rate)
{
if(!timer_->IsRunning()) {
timer_->Start(rate);
}
}
void ProgressStatusBar::Embed()
{
std::cout << "Embedding" << std::endl;
wxFrame* mf = GUI::get_main_frame();
std::cout << mf->GetName() << std::endl;
std::cout << self->GetName() << std::endl;
mf->SetStatusBar(self);
}
void ProgressStatusBar::SetStatusText(std::string txt)
{
self->SetStatusText(txt);
}
int ProgressStatusBar::GetId()
{
return self->GetId();
}
int ProgressStatusBar::GetProgId()
{
return prog_->GetId();
}
}

View File

@ -0,0 +1,61 @@
#ifndef PROGRESSSTATUSBAR_HPP
#define PROGRESSSTATUSBAR_HPP
#include <memory>
#include <functional>
class wxTimer;
class wxGauge;
class wxButton;
class wxTimerEvent;
class wxStatusBar;
class wxWindow;
namespace Slic3r {
/**
* @brief The ProgressStatusBar class is the widgets occupying the lower area
* of the Slicer main window. It consists of a message area to the left and a
* progress indication area to the right with an optional cancel button.
*/
class ProgressStatusBar {
wxStatusBar *self; // we cheat! It should be the base class but: perl!
wxTimer *timer_;
wxGauge *prog_;
wxButton *cancelbutton_;
public:
/// Cancel callback function type
using CancelFn = std::function<void()>;
ProgressStatusBar(wxWindow *parent = nullptr, int id = -1);
~ProgressStatusBar();
int get_progress() const;
void set_progress(int);
void set_range(int = 100);
void show_progress(bool);
void start_busy(int = 100);
void stop_busy();
inline bool is_busy() const { return busy_; }
void set_cancel_callback(CancelFn);
void run(int rate);
// Temporary methods to satisfy Perl side
void Embed();
void SetStatusText(std::string txt);
int GetId();
int GetProgId();
private:
bool busy_ = false;
CancelFn cancel_cb_;
};
namespace GUI {
using Slic3r::ProgressStatusBar;
}
}
#endif // PROGRESSSTATUSBAR_HPP

View File

@ -10,7 +10,7 @@ namespace Slic3r {
/**
* @brief Generic progress indication interface.
*/
class IProgressIndicator {
class ProgressIndicator {
public:
using CancelFn = std::function<void(void)>; // Cancel functio signature.
@ -20,7 +20,7 @@ private:
public:
inline virtual ~IProgressIndicator() {}
inline virtual ~ProgressIndicator() {}
/// Get the maximum of the progress range.
float max() const { return max_; }

View File

@ -0,0 +1,41 @@
%module{Slic3r::XS};
%{
#include <xsinit.h>
#include "slic3r/GUI/ProgressStatusBar.hpp"
%}
%name{Slic3r::GUI::ProgressStatusBar} class ProgressStatusBar {
ProgressStatusBar();
~ProgressStatusBar();
int GetProgress() const
%code%{ RETVAL=THIS->get_progress(); %};
void SetProgress(int val)
%code%{ THIS->set_progress(val); %};
void SetRange(int val = 100)
%code%{ THIS->set_range(val); %};
void ShowProgress(bool show)
%code%{ THIS->show_progress(show); %};
void StartBusy(int val = 100)
%code%{ THIS->start_busy(val); %};
void StopBusy()
%code%{ THIS->stop_busy(); %};
bool IsBusy() const
%code%{ RETVAL=THIS->is_busy(); %};
void Run(int rate)
%code%{ THIS->run(rate); %};
void Embed();
void SetStatusText(std::string txt);
int GetId();
int GetProgId();
};

View File

@ -233,8 +233,10 @@ PresetCollection* O_OBJECT_SLIC3R
Ref<PresetCollection> O_OBJECT_SLIC3R_T
PresetBundle* O_OBJECT_SLIC3R
Ref<PresetBundle> O_OBJECT_SLIC3R_T
TabIface* O_OBJECT_SLIC3R
Ref<TabIface> O_OBJECT_SLIC3R_T
TabIface* O_OBJECT_SLIC3R
Ref<TabIface> O_OBJECT_SLIC3R_T
ProgressStatusBar* O_OBJECT_SLIC3R
Ref<ProgressStatusBar> O_OBJECT_SLIC3R_T
PresetUpdater* O_OBJECT_SLIC3R
Ref<PresetUpdater> O_OBJECT_SLIC3R_T

View File

@ -213,6 +213,7 @@
%typemap{PresetHints*};
%typemap{Ref<PresetHints>}{simple};
%typemap{TabIface*};
%typemap{ProgressStatusBar*};
%typemap{PrintRegionPtrs*};
%typemap{PrintObjectPtrs*};