mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-04 06:40:07 +00:00
Merge branch 'timeline-thumbnails3' of https://github.com/pseudogames/aseprite into pseudogames-timeline-thumbnails3
This commit is contained in:
commit
8da12cde1d
@ -275,10 +275,10 @@
|
||||
<option id="color2" type="app::Color" default="app::Color::fromRgb(192, 192, 192)" migrate="Option.CheckedBgColor2" />
|
||||
</section>
|
||||
<section id="thumbnails">
|
||||
<option id="zoom" type="double" default="1" />
|
||||
<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="opacity" type="int" default="255" />
|
||||
</section>
|
||||
<section id="onionskin">
|
||||
<option id="active" type="bool" default="false" migrate="Onionskin.Enabled" />
|
||||
|
@ -13,9 +13,9 @@
|
||||
|
||||
<separator cell_hspan="2" text="Thumbnails:" left="true" horizontal="true" />
|
||||
<grid columns="3">
|
||||
<check id="thumb_enabled" text="Enabled" />
|
||||
<label text="Opacity:" />
|
||||
<slider min="0" max="255" id="thumb_opacity" cell_align="horizontal" width="128" />
|
||||
<check id="thumb_enabled" text="Force" />
|
||||
<label text="Zoom:" />
|
||||
<slider min="1" max="10" id="zoom" cell_align="horizontal" width="128" />
|
||||
|
||||
<check id="thumb_overlay_enabled" text="Overlay"/>
|
||||
<label text="Size:" />
|
||||
|
@ -31,7 +31,6 @@ namespace app {
|
||||
|
||||
DocumentPreferences& docPref = Preferences::instance().document(document);
|
||||
|
||||
int opacity = docPref.thumbnails.opacity();
|
||||
doc::color_t bg1 = color_utils::color_for_image(docPref.bg.color1(), image->pixelFormat());
|
||||
doc::color_t bg2 = color_utils::color_for_image(docPref.bg.color2(), image->pixelFormat());
|
||||
|
||||
@ -55,7 +54,7 @@ namespace app {
|
||||
base::UniquePtr<doc::Image> thumb_img(doc::Image::create(
|
||||
image->pixelFormat(), thumb_size.w, thumb_size.h));
|
||||
|
||||
double alpha = opacity / 255.0;
|
||||
double alpha = 255.0;
|
||||
uint8_t bg_r[] = { rgba_getr(bg1), rgba_getr(bg2) };
|
||||
uint8_t bg_g[] = { rgba_getg(bg1), rgba_getg(bg2) };
|
||||
uint8_t bg_b[] = { rgba_getb(bg1), rgba_getb(bg2) };
|
||||
@ -100,7 +99,7 @@ namespace app {
|
||||
sprite->palette(frame),
|
||||
cel_image_on_thumb.x,
|
||||
cel_image_on_thumb.y,
|
||||
opacity, BlendMode::NORMAL);
|
||||
255, BlendMode::NORMAL);
|
||||
|
||||
she::Surface* thumb_surf = she::instance()->createRgbaSurface(
|
||||
thumb_img->width(), thumb_img->height());
|
||||
|
@ -62,7 +62,7 @@ ConfigureTimelinePopup::ConfigureTimelinePopup()
|
||||
m_box->behind()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onPositionChange, this));
|
||||
m_box->infront()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onPositionChange, this));
|
||||
|
||||
m_box->thumbOpacity()->Change.connect(base::Bind<void>(&ConfigureTimelinePopup::onThumbOpacityChange, this));
|
||||
m_box->zoom()->Change.connect(base::Bind<void>(&ConfigureTimelinePopup::onZoomChange, this));
|
||||
m_box->thumbEnabled()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onThumbEnabledChange, this));
|
||||
m_box->thumbOverlayEnabled()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onThumbOverlayEnabledChange, this));
|
||||
m_box->thumbOverlaySize()->Change.connect(base::Bind<void>(&ConfigureTimelinePopup::onThumbOverlaySizeChange, this));
|
||||
@ -123,7 +123,7 @@ void ConfigureTimelinePopup::updateWidgetsFromCurrentSettings()
|
||||
break;
|
||||
}
|
||||
|
||||
m_box->thumbOpacity()->setValue(docPref.thumbnails.opacity());
|
||||
m_box->zoom()->setValue(docPref.thumbnails.zoom());
|
||||
m_box->thumbEnabled()->setSelected(docPref.thumbnails.enabled());
|
||||
m_box->thumbOverlayEnabled()->setSelected(docPref.thumbnails.overlayEnabled());
|
||||
m_box->thumbOverlaySize()->setValue(docPref.thumbnails.overlaySize());
|
||||
@ -212,9 +212,9 @@ void ConfigureTimelinePopup::onPositionChange()
|
||||
render::OnionskinPosition::INFRONT);
|
||||
}
|
||||
|
||||
void ConfigureTimelinePopup::onThumbOpacityChange()
|
||||
void ConfigureTimelinePopup::onZoomChange()
|
||||
{
|
||||
docPref().thumbnails.opacity(m_box->thumbOpacity()->getValue());
|
||||
docPref().thumbnails.zoom(m_box->zoom()->getValue());
|
||||
}
|
||||
|
||||
void ConfigureTimelinePopup::onThumbEnabledChange()
|
||||
@ -232,5 +232,4 @@ void ConfigureTimelinePopup::onThumbOverlaySizeChange()
|
||||
docPref().thumbnails.overlaySize(m_box->thumbOverlaySize()->getValue());
|
||||
}
|
||||
|
||||
|
||||
} // namespace app
|
||||
|
@ -41,7 +41,7 @@ namespace app {
|
||||
void onCurrentLayerChange();
|
||||
void onPositionChange();
|
||||
|
||||
void onThumbOpacityChange();
|
||||
void onZoomChange();
|
||||
void onThumbEnabledChange();
|
||||
void onThumbOverlayEnabledChange();
|
||||
void onThumbOverlaySizeChange();
|
||||
|
@ -146,7 +146,7 @@ Timeline::Timeline()
|
||||
, m_scroll(false)
|
||||
, m_fromTimeline(false)
|
||||
, m_thumbnailsOverlayVisible(false)
|
||||
, m_thumbnailsOverlayDirection(int(frameBoxWidth()*1.5),
|
||||
, m_thumbnailsOverlayDirection(int(frameBoxWidth()*1.0),
|
||||
int(frameBoxWidth()*0.5))
|
||||
{
|
||||
enableFlags(CTRL_RIGHT_CLICK);
|
||||
@ -178,8 +178,15 @@ Timeline::~Timeline()
|
||||
delete m_confPopup;
|
||||
}
|
||||
|
||||
void Timeline::setZoom(double zoom)
|
||||
{
|
||||
m_zoom = MID(1.0, zoom, 10.0);
|
||||
}
|
||||
|
||||
void Timeline::onThumbnailsPrefChange()
|
||||
{
|
||||
setZoom(docPref().thumbnails.zoom());
|
||||
m_thumbnailsOverlayDirection = gfx::Point(int(frameBoxWidth()*1.0), int(frameBoxWidth()*0.5));
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@ -215,6 +222,8 @@ void Timeline::updateUsingEditor(Editor* editor)
|
||||
m_thumbnailsPrefConn = docPref.thumbnails.AfterChange.connect(
|
||||
base::Bind<void>(&Timeline::onThumbnailsPrefChange, this));
|
||||
|
||||
setZoom(docPref.thumbnails.zoom());
|
||||
|
||||
// If we are already in the same position as the "editor", we don't
|
||||
// need to update the at all timeline.
|
||||
if (m_document == site.document() &&
|
||||
@ -1074,8 +1083,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
break;
|
||||
|
||||
case kTouchMagnifyMessage:
|
||||
m_zoom = m_zoom + m_zoom * static_cast<ui::TouchMessage*>(msg)->magnification();
|
||||
m_zoom = MID(1.0, m_zoom, 10.0);
|
||||
setZoom(m_zoom + m_zoom * static_cast<ui::TouchMessage*>(msg)->magnification());
|
||||
invalidate();
|
||||
break;
|
||||
}
|
||||
@ -1694,6 +1702,7 @@ void Timeline::drawCel(ui::Graphics* g, layer_t layerIndex, frame_t frame, Cel*
|
||||
isFrameActive(frame));
|
||||
const bool is_empty = (image == nullptr);
|
||||
gfx::Rect bounds = getPartBounds(Hit(PART_CEL, layerIndex, frame));
|
||||
gfx::Rect full_bounds = bounds;
|
||||
IntersectClip clip(g, bounds);
|
||||
if (!clip)
|
||||
return;
|
||||
@ -1703,12 +1712,29 @@ void Timeline::drawCel(ui::Graphics* g, layer_t layerIndex, frame_t frame, Cel*
|
||||
else
|
||||
drawPart(g, bounds, NULL, styles.timelineBox(), is_active, is_hover);
|
||||
|
||||
if ((docPref().thumbnails.enabled() || m_zoom > 1) && image) {
|
||||
gfx::Rect thumb_bounds = gfx::Rect(bounds).shrink(guiscale()).inflate(guiscale(), guiscale());
|
||||
if(m_zoom > 1)
|
||||
thumb_bounds.inflate(0, -headerBoxHeight()).offset(0, headerBoxHeight());
|
||||
|
||||
if(!thumb_bounds.isEmpty()) {
|
||||
she::Surface* thumb_surf = thumb::get_cel_thumbnail(cel, thumb_bounds.size());
|
||||
|
||||
g->drawRgbaSurface(thumb_surf, thumb_bounds.x, thumb_bounds.y);
|
||||
|
||||
thumb_surf->dispose();
|
||||
}
|
||||
}
|
||||
|
||||
if (!docPref().thumbnails.enabled() || m_zoom > 1 || !image) {
|
||||
bounds.h = headerBoxHeight();
|
||||
|
||||
// Fill with an user-defined custom color.
|
||||
if (cel && cel->data()) {
|
||||
doc::color_t celColor = cel->data()->userData().color();
|
||||
if (doc::rgba_geta(celColor) > 0) {
|
||||
auto b2 = bounds;
|
||||
b2.shrink(1*guiscale()).inflate(1*guiscale());
|
||||
b2.shrink(1 * guiscale()).inflate(1 * guiscale());
|
||||
g->fillRect(gfx::rgba(doc::rgba_getr(celColor),
|
||||
doc::rgba_getg(celColor),
|
||||
doc::rgba_getb(celColor),
|
||||
@ -1717,6 +1743,8 @@ void Timeline::drawCel(ui::Graphics* g, layer_t layerIndex, frame_t frame, Cel*
|
||||
}
|
||||
}
|
||||
|
||||
bounds.w = headerBoxWidth();
|
||||
|
||||
skin::Style* style;
|
||||
bool fromLeft = false;
|
||||
bool fromRight = false;
|
||||
@ -1747,18 +1775,19 @@ void Timeline::drawCel(ui::Graphics* g, layer_t layerIndex, frame_t frame, Cel*
|
||||
}
|
||||
drawPart(g, bounds, NULL, style, is_active, is_hover);
|
||||
|
||||
if (m_zoom > 1) {
|
||||
if (style == styles.timelineFromBoth() ||
|
||||
style == styles.timelineFromRight()) {
|
||||
style = styles.timelineFromBoth();
|
||||
while ((bounds.x += bounds.w) < full_bounds.x + full_bounds.w) {
|
||||
drawPart(g, bounds, NULL, style, is_active, is_hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw decorators to link the activeCel with its links.
|
||||
if (data && data->activeIt != data->end)
|
||||
drawCelLinkDecorators(g, bounds, cel, frame, is_active, is_hover, data);
|
||||
|
||||
if (docPref().thumbnails.enabled() && image) {
|
||||
gfx::Rect thumb_bounds = gfx::Rect(bounds).offset(1,1).inflate(-1,-1);
|
||||
|
||||
she::Surface* thumb_surf = thumb::get_cel_thumbnail(cel, thumb_bounds.size());
|
||||
|
||||
g->drawRgbaSurface(thumb_surf, thumb_bounds.x, thumb_bounds.y);
|
||||
|
||||
thumb_surf->dispose();
|
||||
drawCelLinkDecorators(g, full_bounds, cel, frame, is_active, is_hover, data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1769,7 +1798,7 @@ void Timeline::updateCelOverlayBounds(const Hit& hit)
|
||||
if (docPref().thumbnails.overlayEnabled() && hit.part == PART_CEL) {
|
||||
m_thumbnailsOverlayHit = hit;
|
||||
|
||||
int max_size = frameBoxWidth() * docPref().thumbnails.overlaySize();
|
||||
int max_size = headerBoxWidth() * docPref().thumbnails.overlaySize();
|
||||
int width, height;
|
||||
if (m_sprite->width() > m_sprite->height()) {
|
||||
width = max_size;
|
||||
@ -1793,7 +1822,7 @@ void Timeline::updateCelOverlayBounds(const Hit& hit)
|
||||
|
||||
if (!client_bounds.contains(inner)) {
|
||||
m_thumbnailsOverlayDirection = gfx::Point(
|
||||
bounds_cel.x < center.x ? (int)(frameBoxWidth()*1.5) : -width -(int)(frameBoxWidth()*0.5),
|
||||
bounds_cel.x < center.x ? (int)(frameBoxWidth()*1.0) : -width,
|
||||
bounds_cel.y < center.y ? (int)(frameBoxWidth()*0.5) : -height+(int)(frameBoxWidth()*0.5)
|
||||
);
|
||||
inner.setOrigin(gfx::Point(
|
||||
@ -1868,13 +1897,16 @@ void Timeline::drawCelOverlay(ui::Graphics* g)
|
||||
overlay_surf->dispose();
|
||||
}
|
||||
|
||||
void Timeline::drawCelLinkDecorators(ui::Graphics* g, const gfx::Rect& bounds,
|
||||
void Timeline::drawCelLinkDecorators(ui::Graphics* g, const gfx::Rect& full_bounds,
|
||||
Cel* cel, frame_t frame, bool is_active, bool is_hover,
|
||||
DrawCelData* data)
|
||||
{
|
||||
SkinTheme::Styles& styles = skinTheme()->styles;
|
||||
ObjectId imageId = (*data->activeIt)->image()->id();
|
||||
|
||||
gfx::Rect bounds = gfx::Rect(full_bounds).setSize(gfx::Size(headerBoxWidth(), headerBoxHeight()));
|
||||
skin::Style* style = NULL;
|
||||
|
||||
// Links at the left or right side
|
||||
bool left = (data->firstLink != data->end ? frame > (*data->firstLink)->frame(): false);
|
||||
bool right = (data->lastLink != data->end ? frame < (*data->lastLink)->frame(): false);
|
||||
@ -1883,17 +1915,28 @@ void Timeline::drawCelLinkDecorators(ui::Graphics* g, const gfx::Rect& bounds,
|
||||
if (left) {
|
||||
Cel* prevCel = m_layer->cel(cel->frame()-1);
|
||||
if (!prevCel || prevCel->image()->id() != imageId)
|
||||
drawPart(g, bounds, NULL, styles.timelineLeftLink(), is_active, is_hover);
|
||||
style = styles.timelineLeftLink();
|
||||
}
|
||||
if (right) {
|
||||
Cel* nextCel = m_layer->cel(cel->frame()+1);
|
||||
if (!nextCel || nextCel->image()->id() != imageId)
|
||||
drawPart(g, bounds, NULL, styles.timelineRightLink(), is_active, is_hover);
|
||||
style = styles.timelineRightLink();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (left && right)
|
||||
drawPart(g, bounds, NULL, styles.timelineBothLinks(), is_active, is_hover);
|
||||
style = styles.timelineBothLinks();
|
||||
}
|
||||
|
||||
if (style) {
|
||||
drawPart(g, bounds, NULL, style, is_active, is_hover);
|
||||
|
||||
if (m_zoom > 1 && (style == styles.timelineBothLinks() || style == styles.timelineRightLink())) {
|
||||
style = styles.timelineBothLinks();
|
||||
while ((bounds.x += bounds.w) < full_bounds.x + full_bounds.w) {
|
||||
drawPart(g, bounds, NULL, style, is_active, is_hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2123,28 +2166,28 @@ gfx::Rect Timeline::getPartBounds(const Hit& hit) const
|
||||
m_separator_x + m_separator_w, bounds.h - y);
|
||||
|
||||
case PART_HEADER_EYE:
|
||||
return gfx::Rect(bounds.x + frameBoxWidth()*0, bounds.y + y,
|
||||
frameBoxWidth(), headerBoxHeight());
|
||||
return gfx::Rect(bounds.x + headerBoxWidth()*0, bounds.y + y,
|
||||
headerBoxWidth(), headerBoxHeight());
|
||||
|
||||
case PART_HEADER_PADLOCK:
|
||||
return gfx::Rect(bounds.x + frameBoxWidth()*1, bounds.y + y,
|
||||
frameBoxWidth(), headerBoxHeight());
|
||||
return gfx::Rect(bounds.x + headerBoxWidth()*1, bounds.y + y,
|
||||
headerBoxWidth(), headerBoxHeight());
|
||||
|
||||
case PART_HEADER_CONTINUOUS:
|
||||
return gfx::Rect(bounds.x + frameBoxWidth()*2, bounds.y + y,
|
||||
frameBoxWidth(), headerBoxHeight());
|
||||
return gfx::Rect(bounds.x + headerBoxWidth()*2, bounds.y + y,
|
||||
headerBoxWidth(), headerBoxHeight());
|
||||
|
||||
case PART_HEADER_GEAR:
|
||||
return gfx::Rect(bounds.x + frameBoxWidth()*3, bounds.y + y,
|
||||
frameBoxWidth(), headerBoxHeight());
|
||||
return gfx::Rect(bounds.x + headerBoxWidth()*3, bounds.y + y,
|
||||
headerBoxWidth(), headerBoxHeight());
|
||||
|
||||
case PART_HEADER_ONIONSKIN:
|
||||
return gfx::Rect(bounds.x + frameBoxWidth()*4, bounds.y + y,
|
||||
frameBoxWidth(), headerBoxHeight());
|
||||
return gfx::Rect(bounds.x + headerBoxWidth()*4, bounds.y + y,
|
||||
headerBoxWidth(), headerBoxHeight());
|
||||
|
||||
case PART_HEADER_LAYER:
|
||||
return gfx::Rect(bounds.x + frameBoxWidth()*5, bounds.y + y,
|
||||
m_separator_x - frameBoxWidth()*5, headerBoxHeight());
|
||||
return gfx::Rect(bounds.x + headerBoxWidth()*5, bounds.y + y,
|
||||
m_separator_x - headerBoxWidth()*5, headerBoxHeight());
|
||||
|
||||
case PART_HEADER_FRAME:
|
||||
return gfx::Rect(
|
||||
@ -2170,29 +2213,29 @@ gfx::Rect Timeline::getPartBounds(const Hit& hit) const
|
||||
if (validLayer(hit.layer)) {
|
||||
return gfx::Rect(bounds.x,
|
||||
bounds.y + y + headerBoxHeight() + layerBoxHeight()*(lastLayer()-hit.layer) - viewScroll().y,
|
||||
frameBoxWidth(), layerBoxHeight());
|
||||
headerBoxWidth(), layerBoxHeight());
|
||||
}
|
||||
break;
|
||||
|
||||
case PART_LAYER_PADLOCK_ICON:
|
||||
if (validLayer(hit.layer)) {
|
||||
return gfx::Rect(bounds.x + frameBoxWidth(),
|
||||
return gfx::Rect(bounds.x + headerBoxWidth(),
|
||||
bounds.y + y + headerBoxHeight() + layerBoxHeight()*(lastLayer()-hit.layer) - viewScroll().y,
|
||||
frameBoxWidth(), layerBoxHeight());
|
||||
headerBoxWidth(), layerBoxHeight());
|
||||
}
|
||||
break;
|
||||
|
||||
case PART_LAYER_CONTINUOUS_ICON:
|
||||
if (validLayer(hit.layer)) {
|
||||
return gfx::Rect(bounds.x + 2*frameBoxWidth(),
|
||||
return gfx::Rect(bounds.x + 2* headerBoxWidth(),
|
||||
bounds.y + y + headerBoxHeight() + layerBoxHeight()*(lastLayer()-hit.layer) - viewScroll().y,
|
||||
frameBoxWidth(), layerBoxHeight());
|
||||
headerBoxWidth(), layerBoxHeight());
|
||||
}
|
||||
break;
|
||||
|
||||
case PART_LAYER_TEXT:
|
||||
if (validLayer(hit.layer)) {
|
||||
int x = frameBoxWidth()*3;
|
||||
int x = headerBoxWidth()*3;
|
||||
return gfx::Rect(bounds.x + x,
|
||||
bounds.y + y + headerBoxHeight() + layerBoxHeight()*(lastLayer()-hit.layer) - viewScroll().y,
|
||||
m_separator_x - x, layerBoxHeight());
|
||||
@ -2972,18 +3015,22 @@ skin::SkinTheme* Timeline::skinTheme() const
|
||||
|
||||
gfx::Size Timeline::celBoxSize() const
|
||||
{
|
||||
int s = int(m_zoom*12*guiscale());
|
||||
return gfx::Size(s, s);
|
||||
return gfx::Size(frameBoxWidth(), layerBoxHeight());
|
||||
}
|
||||
|
||||
int Timeline::headerBoxWidth() const
|
||||
{
|
||||
return int(12 * guiscale());
|
||||
}
|
||||
|
||||
int Timeline::headerBoxHeight() const
|
||||
{
|
||||
return int(m_zoom*12*guiscale());
|
||||
return int(12 * guiscale());
|
||||
}
|
||||
|
||||
int Timeline::layerBoxHeight() const
|
||||
{
|
||||
return int(m_zoom*12*guiscale());
|
||||
return int(m_zoom*12*guiscale() + (int)(m_zoom > 1) * headerBoxHeight());
|
||||
}
|
||||
|
||||
int Timeline::frameBoxWidth() const
|
||||
|
@ -301,6 +301,7 @@ namespace app {
|
||||
// Theme/dimensions
|
||||
skin::SkinTheme* skinTheme() const;
|
||||
gfx::Size celBoxSize() const;
|
||||
int headerBoxWidth() const;
|
||||
int headerBoxHeight() const;
|
||||
int layerBoxHeight() const;
|
||||
int frameBoxWidth() const;
|
||||
@ -309,6 +310,7 @@ namespace app {
|
||||
void updateCelOverlayBounds(const Hit& hit);
|
||||
void drawCelOverlay(ui::Graphics* g);
|
||||
void onThumbnailsPrefChange();
|
||||
void setZoom(double zoom);
|
||||
|
||||
ui::ScrollBar m_hbar;
|
||||
ui::ScrollBar m_vbar;
|
||||
|
Loading…
x
Reference in New Issue
Block a user