mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-10 01:13:49 +00:00
Add thumbnails in timeline (#340)
Reviewed-by: David Capello <davidcapello@gmail.com>
This commit is contained in:
parent
7849b8804d
commit
57567af06b
@ -106,6 +106,7 @@
|
||||
<key command="SnapToGrid" shortcut="Shift+S" />
|
||||
<key command="SetLoopSection" shortcut="F2" />
|
||||
<key command="ShowOnionSkin" shortcut="F3" />
|
||||
<key command="ToggleTimelineThumbnails" shortcut="F6" />
|
||||
<key command="Timeline" shortcut="Tab">
|
||||
<param name="switch" value="true" />
|
||||
</key>
|
||||
|
@ -197,6 +197,9 @@
|
||||
<section id="symmetry_mode">
|
||||
<option id="enabled" type="bool" default="false" />
|
||||
</section>
|
||||
<section id="thumbnails">
|
||||
<option id="cache_limit" type="int" default="5000" />
|
||||
</section>
|
||||
</global>
|
||||
|
||||
<tool>
|
||||
@ -253,6 +256,14 @@
|
||||
<option id="color1" type="app::Color" default="app::Color::fromRgb(128, 128, 128)" migrate="Option.CheckedBgColor1" />
|
||||
<option id="color2" type="app::Color" default="app::Color::fromRgb(192, 192, 192)" migrate="Option.CheckedBgColor2" />
|
||||
</section>
|
||||
<section id="thumbnails">
|
||||
<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="quality" type="doc::algorithm::ResizeMethod" default="doc::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR" />
|
||||
<option id="opacity" type="int" default="255" />
|
||||
<option id="background" type="app::Color" default="app::Color::fromRgb(180, 180, 180, 220)" />
|
||||
</section>
|
||||
<section id="onionskin">
|
||||
<option id="active" type="bool" default="false" migrate="Onionskin.Enabled" />
|
||||
<option id="prev_frames" type="int" default="1" migrate="Onionskin.PrevFrames" />
|
||||
|
@ -2,6 +2,23 @@
|
||||
<!-- Copyright (C) 2014, 2015 by David Capello -->
|
||||
<gui>
|
||||
<vbox id="timeline_conf">
|
||||
<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_overlay_enabled" text="Overlay"/>
|
||||
<label text="Size:" />
|
||||
<slider min="2" max="10" id="thumb_overlay_size" cell_align="horizontal" width="128" />
|
||||
|
||||
<label text="Quality:" />
|
||||
<combobox id="thumb_quality" expansive="true" cell_hspan="2" />
|
||||
|
||||
<label text="Background:" />
|
||||
<colorpicker id="thumb_background" expansive="true" cell_hspan="2" />
|
||||
|
||||
</grid>
|
||||
<separator cell_hspan="2" text="Onion Skin:" left="true" horizontal="true" />
|
||||
<grid columns="2">
|
||||
<hbox cell_hspan="2">
|
||||
|
@ -228,6 +228,7 @@ add_library(app-lib
|
||||
commands/cmd_new_layer_set.cpp
|
||||
commands/cmd_new_sprite_from_selection.cpp
|
||||
commands/cmd_onionskin.cpp
|
||||
commands/cmd_toggle_timeline_thumbnails.cpp
|
||||
commands/cmd_open_file.cpp
|
||||
commands/cmd_open_in_folder.cpp
|
||||
commands/cmd_open_with_app.cpp
|
||||
@ -426,6 +427,7 @@ add_library(app-lib
|
||||
ui/workspace_tabs.cpp
|
||||
ui/zoom_entry.cpp
|
||||
ui_context.cpp
|
||||
thumbnails.cpp
|
||||
util/autocrop.cpp
|
||||
util/clipboard.cpp
|
||||
util/clipboard_native.cpp
|
||||
|
50
src/app/commands/cmd_toggle_timeline_thumbnails.cpp
Normal file
50
src/app/commands/cmd_toggle_timeline_thumbnails.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2016 Carlo Caputo
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/context.h"
|
||||
#include "app/document.h"
|
||||
#include "app/pref/preferences.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
class ToggleTimelineThumbnailsCommand : public Command {
|
||||
public:
|
||||
ToggleTimelineThumbnailsCommand()
|
||||
: Command("ToggleTimelineThumbnails",
|
||||
"Toggle Timeline Thumbnails",
|
||||
CmdUIOnlyFlag)
|
||||
{
|
||||
}
|
||||
|
||||
Command* clone() const override { return new ToggleTimelineThumbnailsCommand(*this); }
|
||||
|
||||
protected:
|
||||
bool onChecked(Context* context) override {
|
||||
DocumentPreferences& docPref = Preferences::instance().document(context->activeDocument());
|
||||
return docPref.thumbnails.enabled();
|
||||
}
|
||||
|
||||
void onExecute(Context* context) override {
|
||||
DocumentPreferences& docPref = Preferences::instance().document(context->activeDocument());
|
||||
docPref.thumbnails.enabled(!docPref.thumbnails.enabled());
|
||||
}
|
||||
};
|
||||
|
||||
Command* CommandFactory::createToggleTimelineThumbnailsCommand()
|
||||
{
|
||||
return new ToggleTimelineThumbnailsCommand;
|
||||
}
|
||||
|
||||
} // namespace app
|
@ -122,6 +122,7 @@ FOR_EACH_COMMAND(ShowExtras)
|
||||
FOR_EACH_COMMAND(ShowGrid)
|
||||
FOR_EACH_COMMAND(ShowLayerEdges)
|
||||
FOR_EACH_COMMAND(ShowOnionSkin)
|
||||
FOR_EACH_COMMAND(ToggleTimelineThumbnails)
|
||||
FOR_EACH_COMMAND(ShowPixelGrid)
|
||||
FOR_EACH_COMMAND(ShowSelectionEdges)
|
||||
FOR_EACH_COMMAND(SnapToGrid)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2016 Carlo "zED" Caputo
|
||||
// Copyright (C) 2016 Carlo Caputo
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "gfx/rect.h"
|
||||
#include "render/onionskin_position.h"
|
||||
#include "render/zoom.h"
|
||||
#include "doc/algorithm/resize_image.h"
|
||||
|
||||
#include "pref.xml.h"
|
||||
|
||||
|
96
src/app/thumbnails.cpp
Normal file
96
src/app/thumbnails.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2016 Carlo Caputo
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#include "app/color_utils.h"
|
||||
#include "app/document.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/thumbnails.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/connection.h"
|
||||
#include "base/shared_ptr.h"
|
||||
#include "doc/algorithm/resize_image.h"
|
||||
#include "doc/algorithm/rotate.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/conversion_she.h"
|
||||
#include "doc/doc.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/object.h"
|
||||
#include "doc/object_id.h"
|
||||
#include "render/render.h"
|
||||
#include "she/surface.h"
|
||||
#include "she/system.h"
|
||||
|
||||
namespace app {
|
||||
namespace thumb {
|
||||
|
||||
she::Surface* get_cel_thumbnail(const doc::Cel* cel, const gfx::Rect& bounds)
|
||||
{
|
||||
app::Document* document = static_cast<app::Document*>(cel->sprite()->document());
|
||||
doc::frame_t frame = cel->frame();
|
||||
doc::Image* image = cel->image();
|
||||
|
||||
DocumentPreferences& docPref = Preferences::instance().document(document);
|
||||
|
||||
int opacity = docPref.thumbnails.opacity();
|
||||
gfx::Color background = color_utils::color_for_ui(docPref.thumbnails.background());
|
||||
doc::algorithm::ResizeMethod resize_method = docPref.thumbnails.quality();
|
||||
|
||||
gfx::Size image_size = image->size();
|
||||
gfx::Size thumb_size = bounds.size();
|
||||
|
||||
double zw = thumb_size.w / (double)image_size.w;
|
||||
double zh = thumb_size.h / (double)image_size.h;
|
||||
double zoom = MIN(1, MIN(zw, zh));
|
||||
|
||||
gfx::Rect cel_image_on_thumb(
|
||||
(int)(thumb_size.w * 0.5 - image_size.w * zoom * 0.5),
|
||||
(int)(thumb_size.h * 0.5 - image_size.h * zoom * 0.5),
|
||||
(int)(image_size.w * zoom),
|
||||
(int)(image_size.h * zoom)
|
||||
);
|
||||
|
||||
const doc::Sprite* sprite = document->sprite();
|
||||
base::UniquePtr<doc::Image> thumb_img(doc::Image::create(
|
||||
image->pixelFormat(), thumb_size.w, thumb_size.h));
|
||||
|
||||
clear_image(thumb_img.get(), background);
|
||||
|
||||
base::UniquePtr<doc::Image> scale_img;
|
||||
const doc::Image* source = image;
|
||||
|
||||
if (zoom != 1) {
|
||||
scale_img.reset(doc::Image::create(
|
||||
image->pixelFormat(), cel_image_on_thumb.w, cel_image_on_thumb.h));
|
||||
|
||||
doc::algorithm::resize_image(
|
||||
image, scale_img,
|
||||
resize_method,
|
||||
sprite->palette(frame),
|
||||
sprite->rgbMap(frame),
|
||||
sprite->transparentColor());
|
||||
|
||||
source = scale_img.get();
|
||||
}
|
||||
|
||||
render::composite_image(
|
||||
thumb_img, source,
|
||||
sprite->palette(frame),
|
||||
cel_image_on_thumb.x,
|
||||
cel_image_on_thumb.y,
|
||||
opacity, BlendMode::NORMAL);
|
||||
|
||||
she::Surface* thumb_surf = she::instance()->createRgbaSurface(
|
||||
thumb_img->width(), thumb_img->height());
|
||||
|
||||
convert_image_to_surface(thumb_img, sprite->palette(frame), thumb_surf,
|
||||
0, 0, 0, 0, thumb_img->width(), thumb_img->height());
|
||||
|
||||
return thumb_surf;
|
||||
}
|
||||
|
||||
} // thumb
|
||||
} // app
|
30
src/app/thumbnails.h
Normal file
30
src/app/thumbnails.h
Normal file
@ -0,0 +1,30 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2016 Carlo Caputo
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_THUMBNAILS_H_INCLUDED
|
||||
#define APP_THUMBNAILS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "gfx/rect.h"
|
||||
|
||||
namespace doc {
|
||||
class Cel;
|
||||
}
|
||||
|
||||
namespace she {
|
||||
class Surface;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
namespace thumb {
|
||||
|
||||
she::Surface* get_cel_thumbnail(const doc::Cel* cel, const gfx::Rect& bounds);
|
||||
|
||||
} // thumb
|
||||
} // app
|
||||
|
||||
#endif
|
@ -41,6 +41,8 @@ ConfigureTimelinePopup::ConfigureTimelinePopup()
|
||||
: PopupWindow("Timeline Settings", ClickBehavior::CloseOnClickInOtherWindow)
|
||||
, m_lockUpdates(false)
|
||||
{
|
||||
setHotRegion(gfx::Region(manager()->bounds())); // for the color selector
|
||||
|
||||
setAutoRemap(false);
|
||||
setBorder(gfx::Border(4*guiscale()));
|
||||
|
||||
@ -56,6 +58,17 @@ ConfigureTimelinePopup::ConfigureTimelinePopup()
|
||||
m_box->currentLayer()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onCurrentLayerChange, 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->thumbOpacity()->Change.connect(base::Bind<void>(&ConfigureTimelinePopup::onThumbOpacityChange, this));
|
||||
m_box->thumbBackground()->Change.connect(&ConfigureTimelinePopup::onThumbBackgroundChange, 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));
|
||||
|
||||
m_box->thumbQuality()->addItem("Nearest-neighbor");
|
||||
m_box->thumbQuality()->addItem("Bilinear");
|
||||
// m_box->thumbQuality()->addItem("RotSprite");
|
||||
m_box->thumbQuality()->Change.connect(&ConfigureTimelinePopup::onThumbQualityChange, this);
|
||||
}
|
||||
|
||||
app::Document* ConfigureTimelinePopup::doc()
|
||||
@ -103,6 +116,24 @@ void ConfigureTimelinePopup::updateWidgetsFromCurrentSettings()
|
||||
m_box->infront()->setSelected(true);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (docPref.thumbnails.quality()) {
|
||||
case doc::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR:
|
||||
m_box->thumbQuality()->setSelectedItemIndex(0);
|
||||
break;
|
||||
case doc::algorithm::RESIZE_METHOD_BILINEAR:
|
||||
m_box->thumbQuality()->setSelectedItemIndex(1);
|
||||
break;
|
||||
default:
|
||||
docPref.thumbnails.quality(doc::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR);
|
||||
m_box->thumbQuality()->setSelectedItemIndex(0);
|
||||
}
|
||||
|
||||
m_box->thumbOpacity()->setValue(docPref.thumbnails.opacity());
|
||||
m_box->thumbBackground()->setColor(docPref.thumbnails.background());
|
||||
m_box->thumbEnabled()->setSelected(docPref.thumbnails.enabled());
|
||||
m_box->thumbOverlayEnabled()->setSelected(docPref.thumbnails.overlayEnabled());
|
||||
m_box->thumbOverlaySize()->setValue(docPref.thumbnails.overlaySize());
|
||||
}
|
||||
|
||||
bool ConfigureTimelinePopup::onProcessMessage(ui::Message* msg)
|
||||
@ -112,7 +143,6 @@ bool ConfigureTimelinePopup::onProcessMessage(ui::Message* msg)
|
||||
case kOpenMessage: {
|
||||
updateWidgetsFromCurrentSettings();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return PopupWindow::onProcessMessage(msg);
|
||||
@ -175,4 +205,45 @@ void ConfigureTimelinePopup::onPositionChange()
|
||||
render::OnionskinPosition::INFRONT);
|
||||
}
|
||||
|
||||
void ConfigureTimelinePopup::onThumbOpacityChange()
|
||||
{
|
||||
docPref().thumbnails.opacity(m_box->thumbOpacity()->getValue());
|
||||
}
|
||||
|
||||
void ConfigureTimelinePopup::onThumbQualityChange()
|
||||
{
|
||||
switch (m_box->thumbQuality()->getSelectedItemIndex()) {
|
||||
case 0:
|
||||
docPref().thumbnails.quality(doc::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR);
|
||||
break;
|
||||
case 1:
|
||||
docPref().thumbnails.quality(doc::algorithm::RESIZE_METHOD_BILINEAR);
|
||||
break;
|
||||
default:
|
||||
docPref().thumbnails.quality(doc::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR);
|
||||
m_box->thumbQuality()->setSelectedItemIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureTimelinePopup::onThumbBackgroundChange(const app::Color& color)
|
||||
{
|
||||
docPref().thumbnails.background(color);
|
||||
}
|
||||
|
||||
void ConfigureTimelinePopup::onThumbEnabledChange()
|
||||
{
|
||||
docPref().thumbnails.enabled(m_box->thumbEnabled()->isSelected());
|
||||
}
|
||||
|
||||
void ConfigureTimelinePopup::onThumbOverlayEnabledChange()
|
||||
{
|
||||
docPref().thumbnails.overlayEnabled(m_box->thumbOverlayEnabled()->isSelected());
|
||||
}
|
||||
|
||||
void ConfigureTimelinePopup::onThumbOverlaySizeChange()
|
||||
{
|
||||
docPref().thumbnails.overlaySize(m_box->thumbOverlaySize()->getValue());
|
||||
}
|
||||
|
||||
|
||||
} // namespace app
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "app/pref/preferences.h"
|
||||
#include "doc/anidir.h"
|
||||
#include "ui/popup_window.h"
|
||||
#include "base/connection.h"
|
||||
|
||||
namespace ui {
|
||||
class Button;
|
||||
@ -41,6 +42,13 @@ namespace app {
|
||||
void onCurrentLayerChange();
|
||||
void onPositionChange();
|
||||
|
||||
void onThumbOpacityChange();
|
||||
void onThumbQualityChange();
|
||||
void onThumbBackgroundChange(const app::Color& color);
|
||||
void onThumbEnabledChange();
|
||||
void onThumbOverlayEnabledChange();
|
||||
void onThumbOverlaySizeChange();
|
||||
|
||||
private:
|
||||
void updateWidgetsFromCurrentSettings();
|
||||
app::Document* doc();
|
||||
|
@ -50,6 +50,12 @@
|
||||
#include "she/font.h"
|
||||
#include "ui/scroll_helper.h"
|
||||
#include "ui/ui.h"
|
||||
#include "base/unique_ptr.h"
|
||||
#include "she/surface.h"
|
||||
#include "she/system.h"
|
||||
#include "doc/conversion_she.h"
|
||||
#include "base/bind.h"
|
||||
#include "doc/algorithm/rotate.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
@ -134,6 +140,8 @@ Timeline::Timeline()
|
||||
, m_offset_count(0)
|
||||
, m_scroll(false)
|
||||
, m_fromTimeline(false)
|
||||
, m_thumbnailsOverlayVisible(false)
|
||||
, m_thumbnailsOverlayDirection((int)(FRMSIZE*1.5), (int)(FRMSIZE*0.5))
|
||||
{
|
||||
enableFlags(CTRL_RIGHT_CLICK);
|
||||
|
||||
@ -164,6 +172,11 @@ Timeline::~Timeline()
|
||||
delete m_confPopup;
|
||||
}
|
||||
|
||||
void Timeline::onThumbnailsPrefChange()
|
||||
{
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void Timeline::updateUsingEditor(Editor* editor)
|
||||
{
|
||||
m_aniControls.updateUsingEditor(editor);
|
||||
@ -206,6 +219,10 @@ void Timeline::updateUsingEditor(Editor* editor)
|
||||
m_hot.part = PART_NOTHING;
|
||||
m_clk.part = PART_NOTHING;
|
||||
|
||||
m_thumbnailsPrefConn.disconnect();
|
||||
m_thumbnailsPrefConn = docPref().thumbnails.AfterChange.connect(
|
||||
base::Bind<void>(&Timeline::onThumbnailsPrefChange, this));
|
||||
|
||||
setFocusStop(true);
|
||||
regenerateLayers();
|
||||
setViewScroll(viewScroll());
|
||||
@ -545,6 +562,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
}
|
||||
|
||||
updateStatusBar(msg);
|
||||
updateCelOverlayBounds(hit);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1036,6 +1054,7 @@ void Timeline::onPaint(ui::PaintEvent& ev)
|
||||
drawFrameTags(g);
|
||||
drawRangeOutline(g);
|
||||
drawClipboardRange(g);
|
||||
drawCelOverlay(g);
|
||||
|
||||
#if 0 // Use this code to debug the calculated m_dropRange by updateDropRange()
|
||||
{
|
||||
@ -1067,8 +1086,10 @@ void Timeline::onAfterCommandExecution(CommandExecutionEvent& ev)
|
||||
|
||||
void Timeline::onRemoveDocument(doc::Document* document)
|
||||
{
|
||||
if (document == m_document)
|
||||
if (document == m_document) {
|
||||
m_thumbnailsPrefConn.disconnect();
|
||||
detachDocument();
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::onGeneralUpdate(DocumentEvent& ev)
|
||||
@ -1518,6 +1539,131 @@ void Timeline::drawCel(ui::Graphics* g, LayerIndex layerIndex, frame_t frame, Ce
|
||||
// Draw decorators to link the activeCel with its links.
|
||||
if (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);
|
||||
|
||||
g->drawRgbaSurface(thumb_surf, thumb_bounds.x, thumb_bounds.y);
|
||||
|
||||
thumb_surf->dispose();
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::updateCelOverlayBounds(const Hit& hit)
|
||||
{
|
||||
gfx::Rect inner, outer;
|
||||
|
||||
if (docPref().thumbnails.overlayEnabled() && hit.part == PART_CEL) {
|
||||
m_thumbnailsOverlayHit = hit;
|
||||
|
||||
int max_size = FRMSIZE * docPref().thumbnails.overlaySize();
|
||||
int width, height;
|
||||
if (m_sprite->width() > m_sprite->height()) {
|
||||
width = max_size;
|
||||
height = max_size * m_sprite->height() / m_sprite->width();
|
||||
}
|
||||
else {
|
||||
width = max_size * m_sprite->width() / m_sprite->height();
|
||||
height = max_size;
|
||||
}
|
||||
|
||||
gfx::Rect client_bounds = clientBounds();
|
||||
gfx::Point center = client_bounds.center();
|
||||
|
||||
gfx::Rect bounds_cel = getPartBounds(m_thumbnailsOverlayHit);
|
||||
inner = gfx::Rect(
|
||||
bounds_cel.x + m_thumbnailsOverlayDirection.x,
|
||||
bounds_cel.y + m_thumbnailsOverlayDirection.y,
|
||||
width,
|
||||
height
|
||||
);
|
||||
|
||||
if (!client_bounds.contains(inner)) {
|
||||
m_thumbnailsOverlayDirection = gfx::Point(
|
||||
bounds_cel.x < center.x ? (int)(FRMSIZE*1.5) : -width -(int)(FRMSIZE*0.5),
|
||||
bounds_cel.y < center.y ? (int)(FRMSIZE*0.5) : -height+(int)(FRMSIZE*0.5)
|
||||
);
|
||||
inner.setOrigin(gfx::Point(
|
||||
bounds_cel.x + m_thumbnailsOverlayDirection.x,
|
||||
bounds_cel.y + m_thumbnailsOverlayDirection.y
|
||||
));
|
||||
}
|
||||
|
||||
outer = gfx::Rect(inner).enlarge(1);
|
||||
}
|
||||
else {
|
||||
outer = gfx::Rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
if (outer != m_thumbnailsOverlayOuter) {
|
||||
if (!m_thumbnailsOverlayOuter.isEmpty()) {
|
||||
invalidateRect(gfx::Rect(m_thumbnailsOverlayOuter).offset(origin()));
|
||||
}
|
||||
if (!outer.isEmpty()) {
|
||||
invalidateRect(gfx::Rect(outer).offset(origin()));
|
||||
}
|
||||
m_thumbnailsOverlayVisible = !outer.isEmpty();
|
||||
m_thumbnailsOverlayOuter = outer;
|
||||
m_thumbnailsOverlayInner = inner;
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::drawCelOverlay(ui::Graphics* g)
|
||||
{
|
||||
if (!m_thumbnailsOverlayVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
Layer *layer = m_layers[m_thumbnailsOverlayHit.layer];
|
||||
Cel *cel = layer->cel(m_thumbnailsOverlayHit.frame);
|
||||
if (!cel) {
|
||||
return;
|
||||
}
|
||||
Image* image = cel->image();
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
IntersectClip clip(g, m_thumbnailsOverlayOuter);
|
||||
if (!clip)
|
||||
return;
|
||||
|
||||
base::UniquePtr<Image> overlay_img(
|
||||
Image::create(image->pixelFormat(),
|
||||
m_thumbnailsOverlayInner.w,
|
||||
m_thumbnailsOverlayInner.h));
|
||||
|
||||
double scale = (
|
||||
m_sprite->width() > m_sprite->height() ?
|
||||
m_thumbnailsOverlayInner.w / (double)m_sprite->width() :
|
||||
m_thumbnailsOverlayInner.h / (double)m_sprite->height()
|
||||
);
|
||||
|
||||
clear_image(overlay_img, 0);
|
||||
algorithm::scale_image(overlay_img, image,
|
||||
(int)(cel->x() * scale),
|
||||
(int)(cel->y() * scale),
|
||||
(int)(image->width() * scale),
|
||||
(int)(image->height() * scale),
|
||||
0, 0, image->width(), image->height());
|
||||
|
||||
she::Surface* overlay_surf = she::instance()->createRgbaSurface(
|
||||
overlay_img->width(),
|
||||
overlay_img->height());
|
||||
|
||||
convert_image_to_surface(overlay_img, m_sprite->palette(m_frame), overlay_surf,
|
||||
0, 0, 0, 0, overlay_img->width(), overlay_img->height());
|
||||
|
||||
gfx::Color background = color_utils::color_for_ui(docPref().thumbnails.background());
|
||||
gfx::Color border = color_utils::blackandwhite_neg(background);
|
||||
g->fillRect(background, m_thumbnailsOverlayInner);
|
||||
g->drawRgbaSurface(overlay_surf,
|
||||
m_thumbnailsOverlayInner.x, m_thumbnailsOverlayInner.y);
|
||||
g->drawRect(border, m_thumbnailsOverlayOuter);
|
||||
|
||||
overlay_surf->dispose();
|
||||
}
|
||||
|
||||
void Timeline::drawCelLinkDecorators(ui::Graphics* g, const gfx::Rect& bounds,
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "ui/scroll_bar.h"
|
||||
#include "ui/timer.h"
|
||||
#include "ui/widget.h"
|
||||
#include "app/thumbnails.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -37,6 +38,10 @@ namespace ui {
|
||||
class Graphics;
|
||||
}
|
||||
|
||||
namespace she {
|
||||
class Surface;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
|
||||
namespace skin {
|
||||
@ -255,6 +260,10 @@ namespace app {
|
||||
DocumentPreferences& docPref() const;
|
||||
skin::SkinTheme* skinTheme() const;
|
||||
|
||||
void updateCelOverlayBounds(const Hit& hit);
|
||||
void drawCelOverlay(ui::Graphics* g);
|
||||
void onThumbnailsPrefChange();
|
||||
|
||||
ui::ScrollBar m_hbar;
|
||||
ui::ScrollBar m_vbar;
|
||||
gfx::Rect m_viewportArea;
|
||||
@ -291,6 +300,13 @@ namespace app {
|
||||
|
||||
AniControls m_aniControls;
|
||||
|
||||
bool m_thumbnailsOverlayVisible;
|
||||
gfx::Rect m_thumbnailsOverlayInner;
|
||||
gfx::Rect m_thumbnailsOverlayOuter;
|
||||
Hit m_thumbnailsOverlayHit;
|
||||
gfx::Point m_thumbnailsOverlayDirection;
|
||||
base::Connection m_thumbnailsPrefConn;
|
||||
|
||||
// Temporal data used to move the range.
|
||||
struct MoveRange {
|
||||
int activeRelativeLayer;
|
||||
|
Loading…
x
Reference in New Issue
Block a user