fix(widget): harden TimelineAndTrackView teardown and TimeScaledObject limits
- TimelineAndTrackView: disconnect the scrollbar sync connections in the destructor. Child views reset their scene during destruction, which can re-emit QScrollBar::valueChanged into a half-destroyed object and trip Qt's assertObjectType abort. - TimeScaledObject: keep minimum <= maximum when setting scale limits so set_scale()'s std::clamp is never called with inverted limits (UB). Setting the maximum below the minimum now pulls the minimum down, and vice versa, matching QAbstractSlider conventions.
This commit is contained in:
@@ -116,6 +116,12 @@ void TimeScaledObject::set_maximum_scale(const double &max)
|
|||||||
{
|
{
|
||||||
max_scale_ = max;
|
max_scale_ = max;
|
||||||
|
|
||||||
|
// Keep min <= max so the clamp in set_scale() is never called with
|
||||||
|
// inverted limits (undefined behavior)
|
||||||
|
if (min_scale_ > max_scale_) {
|
||||||
|
min_scale_ = max_scale_;
|
||||||
|
}
|
||||||
|
|
||||||
if (get_scale() > max_scale_) {
|
if (get_scale() > max_scale_) {
|
||||||
set_scale(max_scale_);
|
set_scale(max_scale_);
|
||||||
}
|
}
|
||||||
@@ -125,6 +131,12 @@ void TimeScaledObject::set_minimum_scale(const double &min)
|
|||||||
{
|
{
|
||||||
min_scale_ = min;
|
min_scale_ = min;
|
||||||
|
|
||||||
|
// Keep min <= max so the clamp in set_scale() is never called with
|
||||||
|
// inverted limits (undefined behavior)
|
||||||
|
if (max_scale_ < min_scale_) {
|
||||||
|
max_scale_ = min_scale_;
|
||||||
|
}
|
||||||
|
|
||||||
if (get_scale() < min_scale_) {
|
if (get_scale() < min_scale_) {
|
||||||
set_scale(min_scale_);
|
set_scale(min_scale_);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,16 @@ TimelineAndTrackView::TimelineAndTrackView(Qt::Alignment vertical_alignment,
|
|||||||
splitter_->setSizes({ 180, width() });
|
splitter_->setSizes({ 180, width() });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TimelineAndTrackView::~TimelineAndTrackView()
|
||||||
|
{
|
||||||
|
// When the child views are destroyed they reset their scene, which can
|
||||||
|
// push a valueChanged through these connections while this object is
|
||||||
|
// already half-destroyed (Qt aborts on a slot invoked past its class's
|
||||||
|
// destructor). Detach first so teardown emissions go nowhere.
|
||||||
|
disconnect(view_->verticalScrollBar(), nullptr, this, nullptr);
|
||||||
|
disconnect(track_view_->verticalScrollBar(), nullptr, this, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
QSplitter *TimelineAndTrackView::splitter() const
|
QSplitter *TimelineAndTrackView::splitter() const
|
||||||
{
|
{
|
||||||
return splitter_;
|
return splitter_;
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ public:
|
|||||||
|
|
||||||
TrackView *track_view() const;
|
TrackView *track_view() const;
|
||||||
|
|
||||||
|
virtual ~TimelineAndTrackView() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSplitter *splitter_;
|
QSplitter *splitter_;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user