Merge branch 'timeline-thumbnails3' of https://github.com/pseudogames/aseprite into pseudogames-timeline-thumbnails3

This commit is contained in:
David Capello 2016-09-26 12:11:43 -03:00
commit 8da12cde1d
7 changed files with 137 additions and 90 deletions

View File

@ -275,10 +275,10 @@
<option id="color2" type="app::Color" default="app::Color::fromRgb(192, 192, 192)" migrate="Option.CheckedBgColor2" /> <option id="color2" type="app::Color" default="app::Color::fromRgb(192, 192, 192)" migrate="Option.CheckedBgColor2" />
</section> </section>
<section id="thumbnails"> <section id="thumbnails">
<option id="zoom" type="double" default="1" />
<option id="enabled" type="bool" default="false" /> <option id="enabled" type="bool" default="false" />
<option id="overlay_enabled" type="bool" default="false" /> <option id="overlay_enabled" type="bool" default="false" />
<option id="overlay_size" type="int" default="5" /> <option id="overlay_size" type="int" default="5" />
<option id="opacity" type="int" default="255" />
</section> </section>
<section id="onionskin"> <section id="onionskin">
<option id="active" type="bool" default="false" migrate="Onionskin.Enabled" /> <option id="active" type="bool" default="false" migrate="Onionskin.Enabled" />

View File

@ -13,9 +13,9 @@
<separator cell_hspan="2" text="Thumbnails:" left="true" horizontal="true" /> <separator cell_hspan="2" text="Thumbnails:" left="true" horizontal="true" />
<grid columns="3"> <grid columns="3">
<check id="thumb_enabled" text="Enabled" /> <check id="thumb_enabled" text="Force" />
<label text="Opacity:" /> <label text="Zoom:" />
<slider min="0" max="255" id="thumb_opacity" cell_align="horizontal" width="128" /> <slider min="1" max="10" id="zoom" cell_align="horizontal" width="128" />
<check id="thumb_overlay_enabled" text="Overlay"/> <check id="thumb_overlay_enabled" text="Overlay"/>
<label text="Size:" /> <label text="Size:" />

View File

@ -31,7 +31,6 @@ namespace app {
DocumentPreferences& docPref = Preferences::instance().document(document); 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 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()); 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( base::UniquePtr<doc::Image> thumb_img(doc::Image::create(
image->pixelFormat(), thumb_size.w, thumb_size.h)); 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_r[] = { rgba_getr(bg1), rgba_getr(bg2) };
uint8_t bg_g[] = { rgba_getg(bg1), rgba_getg(bg2) }; uint8_t bg_g[] = { rgba_getg(bg1), rgba_getg(bg2) };
uint8_t bg_b[] = { rgba_getb(bg1), rgba_getb(bg2) }; uint8_t bg_b[] = { rgba_getb(bg1), rgba_getb(bg2) };
@ -100,7 +99,7 @@ namespace app {
sprite->palette(frame), sprite->palette(frame),
cel_image_on_thumb.x, cel_image_on_thumb.x,
cel_image_on_thumb.y, cel_image_on_thumb.y,
opacity, BlendMode::NORMAL); 255, BlendMode::NORMAL);
she::Surface* thumb_surf = she::instance()->createRgbaSurface( she::Surface* thumb_surf = she::instance()->createRgbaSurface(
thumb_img->width(), thumb_img->height()); thumb_img->width(), thumb_img->height());

View File

@ -62,7 +62,7 @@ ConfigureTimelinePopup::ConfigureTimelinePopup()
m_box->behind()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onPositionChange, this)); m_box->behind()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onPositionChange, this));
m_box->infront()->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->thumbEnabled()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onThumbEnabledChange, this));
m_box->thumbOverlayEnabled()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onThumbOverlayEnabledChange, this)); m_box->thumbOverlayEnabled()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onThumbOverlayEnabledChange, this));
m_box->thumbOverlaySize()->Change.connect(base::Bind<void>(&ConfigureTimelinePopup::onThumbOverlaySizeChange, this)); m_box->thumbOverlaySize()->Change.connect(base::Bind<void>(&ConfigureTimelinePopup::onThumbOverlaySizeChange, this));
@ -123,7 +123,7 @@ void ConfigureTimelinePopup::updateWidgetsFromCurrentSettings()
break; break;
} }
m_box->thumbOpacity()->setValue(docPref.thumbnails.opacity()); m_box->zoom()->setValue(docPref.thumbnails.zoom());
m_box->thumbEnabled()->setSelected(docPref.thumbnails.enabled()); m_box->thumbEnabled()->setSelected(docPref.thumbnails.enabled());
m_box->thumbOverlayEnabled()->setSelected(docPref.thumbnails.overlayEnabled()); m_box->thumbOverlayEnabled()->setSelected(docPref.thumbnails.overlayEnabled());
m_box->thumbOverlaySize()->setValue(docPref.thumbnails.overlaySize()); m_box->thumbOverlaySize()->setValue(docPref.thumbnails.overlaySize());
@ -212,9 +212,9 @@ void ConfigureTimelinePopup::onPositionChange()
render::OnionskinPosition::INFRONT); 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() void ConfigureTimelinePopup::onThumbEnabledChange()
@ -232,5 +232,4 @@ void ConfigureTimelinePopup::onThumbOverlaySizeChange()
docPref().thumbnails.overlaySize(m_box->thumbOverlaySize()->getValue()); docPref().thumbnails.overlaySize(m_box->thumbOverlaySize()->getValue());
} }
} // namespace app } // namespace app

View File

@ -41,7 +41,7 @@ namespace app {
void onCurrentLayerChange(); void onCurrentLayerChange();
void onPositionChange(); void onPositionChange();
void onThumbOpacityChange(); void onZoomChange();
void onThumbEnabledChange(); void onThumbEnabledChange();
void onThumbOverlayEnabledChange(); void onThumbOverlayEnabledChange();
void onThumbOverlaySizeChange(); void onThumbOverlaySizeChange();

View File

@ -146,7 +146,7 @@ Timeline::Timeline()
, m_scroll(false) , m_scroll(false)
, m_fromTimeline(false) , m_fromTimeline(false)
, m_thumbnailsOverlayVisible(false) , m_thumbnailsOverlayVisible(false)
, m_thumbnailsOverlayDirection(int(frameBoxWidth()*1.5), , m_thumbnailsOverlayDirection(int(frameBoxWidth()*1.0),
int(frameBoxWidth()*0.5)) int(frameBoxWidth()*0.5))
{ {
enableFlags(CTRL_RIGHT_CLICK); enableFlags(CTRL_RIGHT_CLICK);
@ -178,8 +178,15 @@ Timeline::~Timeline()
delete m_confPopup; delete m_confPopup;
} }
void Timeline::setZoom(double zoom)
{
m_zoom = MID(1.0, zoom, 10.0);
}
void Timeline::onThumbnailsPrefChange() void Timeline::onThumbnailsPrefChange()
{ {
setZoom(docPref().thumbnails.zoom());
m_thumbnailsOverlayDirection = gfx::Point(int(frameBoxWidth()*1.0), int(frameBoxWidth()*0.5));
invalidate(); invalidate();
} }
@ -215,6 +222,8 @@ void Timeline::updateUsingEditor(Editor* editor)
m_thumbnailsPrefConn = docPref.thumbnails.AfterChange.connect( m_thumbnailsPrefConn = docPref.thumbnails.AfterChange.connect(
base::Bind<void>(&Timeline::onThumbnailsPrefChange, this)); base::Bind<void>(&Timeline::onThumbnailsPrefChange, this));
setZoom(docPref.thumbnails.zoom());
// If we are already in the same position as the "editor", we don't // If we are already in the same position as the "editor", we don't
// need to update the at all timeline. // need to update the at all timeline.
if (m_document == site.document() && if (m_document == site.document() &&
@ -1074,8 +1083,7 @@ bool Timeline::onProcessMessage(Message* msg)
break; break;
case kTouchMagnifyMessage: case kTouchMagnifyMessage:
m_zoom = m_zoom + m_zoom * static_cast<ui::TouchMessage*>(msg)->magnification(); setZoom(m_zoom + m_zoom * static_cast<ui::TouchMessage*>(msg)->magnification());
m_zoom = MID(1.0, m_zoom, 10.0);
invalidate(); invalidate();
break; break;
} }
@ -1694,6 +1702,7 @@ void Timeline::drawCel(ui::Graphics* g, layer_t layerIndex, frame_t frame, Cel*
isFrameActive(frame)); isFrameActive(frame));
const bool is_empty = (image == nullptr); const bool is_empty = (image == nullptr);
gfx::Rect bounds = getPartBounds(Hit(PART_CEL, layerIndex, frame)); gfx::Rect bounds = getPartBounds(Hit(PART_CEL, layerIndex, frame));
gfx::Rect full_bounds = bounds;
IntersectClip clip(g, bounds); IntersectClip clip(g, bounds);
if (!clip) if (!clip)
return; return;
@ -1703,62 +1712,82 @@ void Timeline::drawCel(ui::Graphics* g, layer_t layerIndex, frame_t frame, Cel*
else else
drawPart(g, bounds, NULL, styles.timelineBox(), is_active, is_hover); drawPart(g, bounds, NULL, styles.timelineBox(), is_active, is_hover);
// Fill with an user-defined custom color. if ((docPref().thumbnails.enabled() || m_zoom > 1) && image) {
if (cel && cel->data()) { gfx::Rect thumb_bounds = gfx::Rect(bounds).shrink(guiscale()).inflate(guiscale(), guiscale());
doc::color_t celColor = cel->data()->userData().color(); if(m_zoom > 1)
if (doc::rgba_geta(celColor) > 0) { thumb_bounds.inflate(0, -headerBoxHeight()).offset(0, headerBoxHeight());
auto b2 = bounds;
b2.shrink(1*guiscale()).inflate(1*guiscale()); if(!thumb_bounds.isEmpty()) {
g->fillRect(gfx::rgba(doc::rgba_getr(celColor), she::Surface* thumb_surf = thumb::get_cel_thumbnail(cel, thumb_bounds.size());
doc::rgba_getg(celColor),
doc::rgba_getb(celColor), g->drawRgbaSurface(thumb_surf, thumb_bounds.x, thumb_bounds.y);
doc::rgba_geta(celColor)),
b2); thumb_surf->dispose();
} }
} }
skin::Style* style; if (!docPref().thumbnails.enabled() || m_zoom > 1 || !image) {
bool fromLeft = false; bounds.h = headerBoxHeight();
bool fromRight = false;
if (is_empty || !data) {
style = styles.timelineEmptyFrame();
}
else {
// Calculate which cel is next to this one (in previous and next
// frame).
Cel* left = (data->prevIt != data->end ? *data->prevIt: nullptr);
Cel* right = (data->nextIt != data->end ? *data->nextIt: nullptr);
if (left && left->frame() != frame-1) left = nullptr;
if (right && right->frame() != frame+1) right = nullptr;
ObjectId leftImg = (left ? left->image()->id(): 0); // Fill with an user-defined custom color.
ObjectId rightImg = (right ? right->image()->id(): 0); if (cel && cel->data()) {
fromLeft = (leftImg == cel->image()->id()); doc::color_t celColor = cel->data()->userData().color();
fromRight = (rightImg == cel->image()->id()); if (doc::rgba_geta(celColor) > 0) {
auto b2 = bounds;
b2.shrink(1 * guiscale()).inflate(1 * guiscale());
g->fillRect(gfx::rgba(doc::rgba_getr(celColor),
doc::rgba_getg(celColor),
doc::rgba_getb(celColor),
doc::rgba_geta(celColor)),
b2);
}
}
if (fromLeft && fromRight) bounds.w = headerBoxWidth();
style = styles.timelineFromBoth();
else if (fromLeft)
style = styles.timelineFromLeft();
else if (fromRight)
style = styles.timelineFromRight();
else
style = styles.timelineKeyframe();
}
drawPart(g, bounds, NULL, style, is_active, is_hover);
// Draw decorators to link the activeCel with its links. skin::Style* style;
if (data && data->activeIt != data->end) bool fromLeft = false;
drawCelLinkDecorators(g, bounds, cel, frame, is_active, is_hover, data); bool fromRight = false;
if (is_empty || !data) {
style = styles.timelineEmptyFrame();
}
else {
// Calculate which cel is next to this one (in previous and next
// frame).
Cel* left = (data->prevIt != data->end ? *data->prevIt: nullptr);
Cel* right = (data->nextIt != data->end ? *data->nextIt: nullptr);
if (left && left->frame() != frame-1) left = nullptr;
if (right && right->frame() != frame+1) right = nullptr;
if (docPref().thumbnails.enabled() && image) { ObjectId leftImg = (left ? left->image()->id(): 0);
gfx::Rect thumb_bounds = gfx::Rect(bounds).offset(1,1).inflate(-1,-1); ObjectId rightImg = (right ? right->image()->id(): 0);
fromLeft = (leftImg == cel->image()->id());
fromRight = (rightImg == cel->image()->id());
she::Surface* thumb_surf = thumb::get_cel_thumbnail(cel, thumb_bounds.size()); if (fromLeft && fromRight)
style = styles.timelineFromBoth();
else if (fromLeft)
style = styles.timelineFromLeft();
else if (fromRight)
style = styles.timelineFromRight();
else
style = styles.timelineKeyframe();
}
drawPart(g, bounds, NULL, style, is_active, is_hover);
g->drawRgbaSurface(thumb_surf, thumb_bounds.x, thumb_bounds.y); 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);
}
}
}
thumb_surf->dispose(); // Draw decorators to link the activeCel with its links.
if (data && data->activeIt != data->end)
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) { if (docPref().thumbnails.overlayEnabled() && hit.part == PART_CEL) {
m_thumbnailsOverlayHit = hit; m_thumbnailsOverlayHit = hit;
int max_size = frameBoxWidth() * docPref().thumbnails.overlaySize(); int max_size = headerBoxWidth() * docPref().thumbnails.overlaySize();
int width, height; int width, height;
if (m_sprite->width() > m_sprite->height()) { if (m_sprite->width() > m_sprite->height()) {
width = max_size; width = max_size;
@ -1793,7 +1822,7 @@ void Timeline::updateCelOverlayBounds(const Hit& hit)
if (!client_bounds.contains(inner)) { if (!client_bounds.contains(inner)) {
m_thumbnailsOverlayDirection = gfx::Point( 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) bounds_cel.y < center.y ? (int)(frameBoxWidth()*0.5) : -height+(int)(frameBoxWidth()*0.5)
); );
inner.setOrigin(gfx::Point( inner.setOrigin(gfx::Point(
@ -1868,13 +1897,16 @@ void Timeline::drawCelOverlay(ui::Graphics* g)
overlay_surf->dispose(); 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, Cel* cel, frame_t frame, bool is_active, bool is_hover,
DrawCelData* data) DrawCelData* data)
{ {
SkinTheme::Styles& styles = skinTheme()->styles; SkinTheme::Styles& styles = skinTheme()->styles;
ObjectId imageId = (*data->activeIt)->image()->id(); 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 // Links at the left or right side
bool left = (data->firstLink != data->end ? frame > (*data->firstLink)->frame(): false); bool left = (data->firstLink != data->end ? frame > (*data->firstLink)->frame(): false);
bool right = (data->lastLink != data->end ? frame < (*data->lastLink)->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) { if (left) {
Cel* prevCel = m_layer->cel(cel->frame()-1); Cel* prevCel = m_layer->cel(cel->frame()-1);
if (!prevCel || prevCel->image()->id() != imageId) if (!prevCel || prevCel->image()->id() != imageId)
drawPart(g, bounds, NULL, styles.timelineLeftLink(), is_active, is_hover); style = styles.timelineLeftLink();
} }
if (right) { if (right) {
Cel* nextCel = m_layer->cel(cel->frame()+1); Cel* nextCel = m_layer->cel(cel->frame()+1);
if (!nextCel || nextCel->image()->id() != imageId) if (!nextCel || nextCel->image()->id() != imageId)
drawPart(g, bounds, NULL, styles.timelineRightLink(), is_active, is_hover); style = styles.timelineRightLink();
} }
} }
else { else {
if (left && right) 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); m_separator_x + m_separator_w, bounds.h - y);
case PART_HEADER_EYE: case PART_HEADER_EYE:
return gfx::Rect(bounds.x + frameBoxWidth()*0, bounds.y + y, return gfx::Rect(bounds.x + headerBoxWidth()*0, bounds.y + y,
frameBoxWidth(), headerBoxHeight()); headerBoxWidth(), headerBoxHeight());
case PART_HEADER_PADLOCK: case PART_HEADER_PADLOCK:
return gfx::Rect(bounds.x + frameBoxWidth()*1, bounds.y + y, return gfx::Rect(bounds.x + headerBoxWidth()*1, bounds.y + y,
frameBoxWidth(), headerBoxHeight()); headerBoxWidth(), headerBoxHeight());
case PART_HEADER_CONTINUOUS: case PART_HEADER_CONTINUOUS:
return gfx::Rect(bounds.x + frameBoxWidth()*2, bounds.y + y, return gfx::Rect(bounds.x + headerBoxWidth()*2, bounds.y + y,
frameBoxWidth(), headerBoxHeight()); headerBoxWidth(), headerBoxHeight());
case PART_HEADER_GEAR: case PART_HEADER_GEAR:
return gfx::Rect(bounds.x + frameBoxWidth()*3, bounds.y + y, return gfx::Rect(bounds.x + headerBoxWidth()*3, bounds.y + y,
frameBoxWidth(), headerBoxHeight()); headerBoxWidth(), headerBoxHeight());
case PART_HEADER_ONIONSKIN: case PART_HEADER_ONIONSKIN:
return gfx::Rect(bounds.x + frameBoxWidth()*4, bounds.y + y, return gfx::Rect(bounds.x + headerBoxWidth()*4, bounds.y + y,
frameBoxWidth(), headerBoxHeight()); headerBoxWidth(), headerBoxHeight());
case PART_HEADER_LAYER: case PART_HEADER_LAYER:
return gfx::Rect(bounds.x + frameBoxWidth()*5, bounds.y + y, return gfx::Rect(bounds.x + headerBoxWidth()*5, bounds.y + y,
m_separator_x - frameBoxWidth()*5, headerBoxHeight()); m_separator_x - headerBoxWidth()*5, headerBoxHeight());
case PART_HEADER_FRAME: case PART_HEADER_FRAME:
return gfx::Rect( return gfx::Rect(
@ -2170,29 +2213,29 @@ gfx::Rect Timeline::getPartBounds(const Hit& hit) const
if (validLayer(hit.layer)) { if (validLayer(hit.layer)) {
return gfx::Rect(bounds.x, return gfx::Rect(bounds.x,
bounds.y + y + headerBoxHeight() + layerBoxHeight()*(lastLayer()-hit.layer) - viewScroll().y, bounds.y + y + headerBoxHeight() + layerBoxHeight()*(lastLayer()-hit.layer) - viewScroll().y,
frameBoxWidth(), layerBoxHeight()); headerBoxWidth(), layerBoxHeight());
} }
break; break;
case PART_LAYER_PADLOCK_ICON: case PART_LAYER_PADLOCK_ICON:
if (validLayer(hit.layer)) { 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, bounds.y + y + headerBoxHeight() + layerBoxHeight()*(lastLayer()-hit.layer) - viewScroll().y,
frameBoxWidth(), layerBoxHeight()); headerBoxWidth(), layerBoxHeight());
} }
break; break;
case PART_LAYER_CONTINUOUS_ICON: case PART_LAYER_CONTINUOUS_ICON:
if (validLayer(hit.layer)) { 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, bounds.y + y + headerBoxHeight() + layerBoxHeight()*(lastLayer()-hit.layer) - viewScroll().y,
frameBoxWidth(), layerBoxHeight()); headerBoxWidth(), layerBoxHeight());
} }
break; break;
case PART_LAYER_TEXT: case PART_LAYER_TEXT:
if (validLayer(hit.layer)) { if (validLayer(hit.layer)) {
int x = frameBoxWidth()*3; int x = headerBoxWidth()*3;
return gfx::Rect(bounds.x + x, return gfx::Rect(bounds.x + x,
bounds.y + y + headerBoxHeight() + layerBoxHeight()*(lastLayer()-hit.layer) - viewScroll().y, bounds.y + y + headerBoxHeight() + layerBoxHeight()*(lastLayer()-hit.layer) - viewScroll().y,
m_separator_x - x, layerBoxHeight()); m_separator_x - x, layerBoxHeight());
@ -2972,18 +3015,22 @@ skin::SkinTheme* Timeline::skinTheme() const
gfx::Size Timeline::celBoxSize() const gfx::Size Timeline::celBoxSize() const
{ {
int s = int(m_zoom*12*guiscale()); return gfx::Size(frameBoxWidth(), layerBoxHeight());
return gfx::Size(s, s); }
int Timeline::headerBoxWidth() const
{
return int(12 * guiscale());
} }
int Timeline::headerBoxHeight() const int Timeline::headerBoxHeight() const
{ {
return int(m_zoom*12*guiscale()); return int(12 * guiscale());
} }
int Timeline::layerBoxHeight() const 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 int Timeline::frameBoxWidth() const

View File

@ -301,6 +301,7 @@ namespace app {
// Theme/dimensions // Theme/dimensions
skin::SkinTheme* skinTheme() const; skin::SkinTheme* skinTheme() const;
gfx::Size celBoxSize() const; gfx::Size celBoxSize() const;
int headerBoxWidth() const;
int headerBoxHeight() const; int headerBoxHeight() const;
int layerBoxHeight() const; int layerBoxHeight() const;
int frameBoxWidth() const; int frameBoxWidth() const;
@ -309,6 +310,7 @@ namespace app {
void updateCelOverlayBounds(const Hit& hit); void updateCelOverlayBounds(const Hit& hit);
void drawCelOverlay(ui::Graphics* g); void drawCelOverlay(ui::Graphics* g);
void onThumbnailsPrefChange(); void onThumbnailsPrefChange();
void setZoom(double zoom);
ui::ScrollBar m_hbar; ui::ScrollBar m_hbar;
ui::ScrollBar m_vbar; ui::ScrollBar m_vbar;