Fix regression with timeline thumbnails (fix #5083)

This fix adds an option to scale timeline thumbnails to fill
the entire cell, or simply leave the timeline thumbnails at 1:1 scale
as before issue #4974.
This commit is contained in:
Gaspar Capello 2025-03-31 18:43:27 -03:00 committed by David Capello
parent 39d69ac8cf
commit 3549d3538f
9 changed files with 40 additions and 9 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Aseprite -->
<!-- Copyright (C) 2018-2024 Igara Studio S.A. -->
<!-- Copyright (C) 2018-2025 Igara Studio S.A. -->
<!-- Copyright (C) 2014-2018 David Capello -->
<preferences>
@ -550,6 +550,7 @@
<option id="enabled" type="bool" default="false" />
<option id="overlay_enabled" type="bool" default="false" />
<option id="overlay_size" type="int" default="5" />
<option id="scale_up_to_fit" type="bool" default="false" />
</section>
<section id="onionskin">
<option id="active" type="bool" default="false" />

View File

@ -1843,6 +1843,7 @@ first_frame = First Frame:
thumbnails = Thumbnails
thumbnail_size = Thumbnail Size:
overlay_size = Overlay Size:
scale_up_to_fit = Scale up to fit
onion_skin = Onion Skin:
merge_frames = Merge Frames
red_blue_tint = Red/Blue Tint

View File

@ -1,4 +1,5 @@
<!-- Aseprite -->
<!-- Copyright (C) 2025 Igara Studio S.A. -->
<!-- Copyright (C) 2014-2018 by David Capello -->
<gui>
<vbox id="timeline_conf">
@ -30,6 +31,7 @@
<check id="thumb_overlay_enabled" text="@.overlay_size"/>
<slider min="2" max="10" id="thumb_overlay_size" cell_align="horizontal" width="128" />
<check id="thumb_scale_up_to_fit" text="@.scale_up_to_fit" cell_hspan="2" />
</grid>
</vbox>
</hbox>

View File

@ -21,9 +21,17 @@
namespace app { namespace thumb {
os::SurfaceRef get_cel_thumbnail(const doc::Cel* cel, const gfx::Size& fitInSize)
os::SurfaceRef get_cel_thumbnail(const doc::Cel* cel,
const bool scaleUpToFit,
const gfx::Size& fitInSize)
{
gfx::Size newSize(gfx::Rect(cel->bounds()).fitIn(gfx::Rect(fitInSize)).size());
gfx::Size newSize;
if (scaleUpToFit || cel->bounds().w > fitInSize.w || cel->bounds().h > fitInSize.h)
newSize = gfx::Rect(cel->bounds()).fitIn(gfx::Rect(fitInSize)).size();
else
newSize = cel->bounds().size();
if (newSize.w < 1 || newSize.h < 1)
return nullptr;

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2019-2025 Igara Studio S.A.
// Copyright (C) 2016 Carlo Caputo
//
// This program is distributed under the terms of
@ -22,7 +22,9 @@ class Surface;
namespace app { namespace thumb {
os::SurfaceRef get_cel_thumbnail(const doc::Cel* cel, const gfx::Size& fitInSize);
os::SurfaceRef get_cel_thumbnail(const doc::Cel* cel,
const bool scaleUpToFit,
const gfx::Size& fitInSize);
}} // namespace app::thumb

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2020-2021 Igara Studio S.A.
// Copyright (C) 2020-2025 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -69,6 +69,7 @@ ConfigureTimelinePopup::ConfigureTimelinePopup()
m_box->thumbEnabled()->Click.connect([this] { onThumbEnabledChange(); });
m_box->thumbOverlayEnabled()->Click.connect([this] { onThumbOverlayEnabledChange(); });
m_box->thumbOverlaySize()->Change.connect([this] { onThumbOverlaySizeChange(); });
m_box->thumbScaleUpToFit()->Click.connect([this] { onScaleUpToFitChange(); });
const bool visibleThumb = docPref().thumbnails.enabled();
m_box->thumbHSeparator()->setVisible(visibleThumb);
@ -128,6 +129,7 @@ void ConfigureTimelinePopup::updateWidgetsFromCurrentSettings()
m_box->thumbBox()->setVisible(visibleThumb);
m_box->thumbOverlayEnabled()->setSelected(docPref.thumbnails.overlayEnabled());
m_box->thumbOverlaySize()->setValue(docPref.thumbnails.overlaySize());
m_box->thumbScaleUpToFit()->setSelected(docPref.thumbnails.scaleUpToFit());
expandWindow(sizeHint());
}
@ -237,4 +239,9 @@ void ConfigureTimelinePopup::onThumbOverlaySizeChange()
docPref().thumbnails.overlaySize(m_box->thumbOverlaySize()->getValue());
}
void ConfigureTimelinePopup::onScaleUpToFitChange()
{
docPref().thumbnails.scaleUpToFit(m_box->thumbScaleUpToFit()->isSelected());
}
} // namespace app

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2025 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -46,6 +47,7 @@ protected:
void onThumbEnabledChange();
void onThumbOverlayEnabledChange();
void onThumbOverlaySizeChange();
void onScaleUpToFitChange();
private:
void updateWidgetsFromCurrentSettings();

View File

@ -234,6 +234,7 @@ Timeline::Timeline(TooltipManager* tooltipManager)
, m_hbar(HORIZONTAL, this)
, m_vbar(VERTICAL, this)
, m_zoom(1.0)
, m_scaleUpToFit(false)
, m_context(UIContext::instance())
, m_editor(NULL)
, m_document(NULL)
@ -308,6 +309,10 @@ void Timeline::setZoomAndUpdate(const double zoom, const bool updatePref)
void Timeline::onThumbnailsPrefChange()
{
if (m_scaleUpToFit != docPref().thumbnails.scaleUpToFit()) {
m_scaleUpToFit = docPref().thumbnails.scaleUpToFit();
invalidate();
}
setZoomAndUpdate(docPref().thumbnails.enabled() ? docPref().thumbnails.zoom() : 1.0, false);
}
@ -357,6 +362,7 @@ void Timeline::updateUsingEditor(Editor* editor)
m_thumbnailsPrefConn = docPref.thumbnails.AfterChange.connect(
[this] { onThumbnailsPrefChange(); });
setZoom(docPref.thumbnails.enabled() ? docPref.thumbnails.zoom() : 1.0);
m_scaleUpToFit = docPref.thumbnails.scaleUpToFit();
m_state = STATE_STANDBY;
m_hot.part = PART_NOTHING;
@ -2516,7 +2522,8 @@ void Timeline::drawCel(ui::Graphics* g,
gfx::Rect thumb_bounds = gfx::Rect(bounds).shrink(skinTheme()->calcBorder(this, style));
if (!thumb_bounds.isEmpty()) {
if (os::SurfaceRef surface = thumb::get_cel_thumbnail(cel, thumb_bounds.size())) {
if (os::SurfaceRef surface =
thumb::get_cel_thumbnail(cel, m_scaleUpToFit, thumb_bounds.size())) {
const int t = std::clamp(thumb_bounds.w / 8, 4, 16);
draw_checkered_grid(g, thumb_bounds, gfx::Size(t, t), docPref());
@ -2608,7 +2615,7 @@ void Timeline::drawCelOverlay(ui::Graphics* g)
return;
gfx::Rect rc = m_sprite->bounds().fitIn(gfx::Rect(m_thumbnailsOverlayBounds).shrink(1));
if (os::SurfaceRef surface = thumb::get_cel_thumbnail(cel, rc.size())) {
if (os::SurfaceRef surface = thumb::get_cel_thumbnail(cel, m_scaleUpToFit, rc.size())) {
draw_checkered_grid(g, rc, gfx::Size(8, 8) * ui::guiscale(), docPref());
g->drawRgbaSurface(surface.get(),

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018-2024 Igara Studio S.A.
// Copyright (C) 2018-2025 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -410,6 +410,7 @@ private:
ui::ScrollBar m_vbar;
gfx::Rect m_viewportArea;
double m_zoom;
bool m_scaleUpToFit;
Context* m_context;
Editor* m_editor;
Doc* m_document;