mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-10 10:13:35 +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="SnapToGrid" shortcut="Shift+S" />
|
||||||
<key command="SetLoopSection" shortcut="F2" />
|
<key command="SetLoopSection" shortcut="F2" />
|
||||||
<key command="ShowOnionSkin" shortcut="F3" />
|
<key command="ShowOnionSkin" shortcut="F3" />
|
||||||
|
<key command="ToggleTimelineThumbnails" shortcut="F6" />
|
||||||
<key command="Timeline" shortcut="Tab">
|
<key command="Timeline" shortcut="Tab">
|
||||||
<param name="switch" value="true" />
|
<param name="switch" value="true" />
|
||||||
</key>
|
</key>
|
||||||
|
@ -197,6 +197,9 @@
|
|||||||
<section id="symmetry_mode">
|
<section id="symmetry_mode">
|
||||||
<option id="enabled" type="bool" default="false" />
|
<option id="enabled" type="bool" default="false" />
|
||||||
</section>
|
</section>
|
||||||
|
<section id="thumbnails">
|
||||||
|
<option id="cache_limit" type="int" default="5000" />
|
||||||
|
</section>
|
||||||
</global>
|
</global>
|
||||||
|
|
||||||
<tool>
|
<tool>
|
||||||
@ -253,6 +256,14 @@
|
|||||||
<option id="color1" type="app::Color" default="app::Color::fromRgb(128, 128, 128)" migrate="Option.CheckedBgColor1" />
|
<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" />
|
<option id="color2" type="app::Color" default="app::Color::fromRgb(192, 192, 192)" migrate="Option.CheckedBgColor2" />
|
||||||
</section>
|
</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">
|
<section id="onionskin">
|
||||||
<option id="active" type="bool" default="false" migrate="Onionskin.Enabled" />
|
<option id="active" type="bool" default="false" migrate="Onionskin.Enabled" />
|
||||||
<option id="prev_frames" type="int" default="1" migrate="Onionskin.PrevFrames" />
|
<option id="prev_frames" type="int" default="1" migrate="Onionskin.PrevFrames" />
|
||||||
|
@ -2,6 +2,23 @@
|
|||||||
<!-- Copyright (C) 2014, 2015 by David Capello -->
|
<!-- Copyright (C) 2014, 2015 by David Capello -->
|
||||||
<gui>
|
<gui>
|
||||||
<vbox id="timeline_conf">
|
<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" />
|
<separator cell_hspan="2" text="Onion Skin:" left="true" horizontal="true" />
|
||||||
<grid columns="2">
|
<grid columns="2">
|
||||||
<hbox cell_hspan="2">
|
<hbox cell_hspan="2">
|
||||||
|
@ -228,6 +228,7 @@ add_library(app-lib
|
|||||||
commands/cmd_new_layer_set.cpp
|
commands/cmd_new_layer_set.cpp
|
||||||
commands/cmd_new_sprite_from_selection.cpp
|
commands/cmd_new_sprite_from_selection.cpp
|
||||||
commands/cmd_onionskin.cpp
|
commands/cmd_onionskin.cpp
|
||||||
|
commands/cmd_toggle_timeline_thumbnails.cpp
|
||||||
commands/cmd_open_file.cpp
|
commands/cmd_open_file.cpp
|
||||||
commands/cmd_open_in_folder.cpp
|
commands/cmd_open_in_folder.cpp
|
||||||
commands/cmd_open_with_app.cpp
|
commands/cmd_open_with_app.cpp
|
||||||
@ -426,6 +427,7 @@ add_library(app-lib
|
|||||||
ui/workspace_tabs.cpp
|
ui/workspace_tabs.cpp
|
||||||
ui/zoom_entry.cpp
|
ui/zoom_entry.cpp
|
||||||
ui_context.cpp
|
ui_context.cpp
|
||||||
|
thumbnails.cpp
|
||||||
util/autocrop.cpp
|
util/autocrop.cpp
|
||||||
util/clipboard.cpp
|
util/clipboard.cpp
|
||||||
util/clipboard_native.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(ShowGrid)
|
||||||
FOR_EACH_COMMAND(ShowLayerEdges)
|
FOR_EACH_COMMAND(ShowLayerEdges)
|
||||||
FOR_EACH_COMMAND(ShowOnionSkin)
|
FOR_EACH_COMMAND(ShowOnionSkin)
|
||||||
|
FOR_EACH_COMMAND(ToggleTimelineThumbnails)
|
||||||
FOR_EACH_COMMAND(ShowPixelGrid)
|
FOR_EACH_COMMAND(ShowPixelGrid)
|
||||||
FOR_EACH_COMMAND(ShowSelectionEdges)
|
FOR_EACH_COMMAND(ShowSelectionEdges)
|
||||||
FOR_EACH_COMMAND(SnapToGrid)
|
FOR_EACH_COMMAND(SnapToGrid)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2016 Carlo "zED" Caputo
|
// Copyright (C) 2016 Carlo Caputo
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "gfx/rect.h"
|
#include "gfx/rect.h"
|
||||||
#include "render/onionskin_position.h"
|
#include "render/onionskin_position.h"
|
||||||
#include "render/zoom.h"
|
#include "render/zoom.h"
|
||||||
|
#include "doc/algorithm/resize_image.h"
|
||||||
|
|
||||||
#include "pref.xml.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)
|
: PopupWindow("Timeline Settings", ClickBehavior::CloseOnClickInOtherWindow)
|
||||||
, m_lockUpdates(false)
|
, m_lockUpdates(false)
|
||||||
{
|
{
|
||||||
|
setHotRegion(gfx::Region(manager()->bounds())); // for the color selector
|
||||||
|
|
||||||
setAutoRemap(false);
|
setAutoRemap(false);
|
||||||
setBorder(gfx::Border(4*guiscale()));
|
setBorder(gfx::Border(4*guiscale()));
|
||||||
|
|
||||||
@ -56,6 +58,17 @@ ConfigureTimelinePopup::ConfigureTimelinePopup()
|
|||||||
m_box->currentLayer()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onCurrentLayerChange, this));
|
m_box->currentLayer()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onCurrentLayerChange, this));
|
||||||
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->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()
|
app::Document* ConfigureTimelinePopup::doc()
|
||||||
@ -103,6 +116,24 @@ void ConfigureTimelinePopup::updateWidgetsFromCurrentSettings()
|
|||||||
m_box->infront()->setSelected(true);
|
m_box->infront()->setSelected(true);
|
||||||
break;
|
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)
|
bool ConfigureTimelinePopup::onProcessMessage(ui::Message* msg)
|
||||||
@ -112,7 +143,6 @@ bool ConfigureTimelinePopup::onProcessMessage(ui::Message* msg)
|
|||||||
case kOpenMessage: {
|
case kOpenMessage: {
|
||||||
updateWidgetsFromCurrentSettings();
|
updateWidgetsFromCurrentSettings();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PopupWindow::onProcessMessage(msg);
|
return PopupWindow::onProcessMessage(msg);
|
||||||
@ -175,4 +205,45 @@ void ConfigureTimelinePopup::onPositionChange()
|
|||||||
render::OnionskinPosition::INFRONT);
|
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
|
} // namespace app
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "app/pref/preferences.h"
|
#include "app/pref/preferences.h"
|
||||||
#include "doc/anidir.h"
|
#include "doc/anidir.h"
|
||||||
#include "ui/popup_window.h"
|
#include "ui/popup_window.h"
|
||||||
|
#include "base/connection.h"
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
class Button;
|
class Button;
|
||||||
@ -41,6 +42,13 @@ namespace app {
|
|||||||
void onCurrentLayerChange();
|
void onCurrentLayerChange();
|
||||||
void onPositionChange();
|
void onPositionChange();
|
||||||
|
|
||||||
|
void onThumbOpacityChange();
|
||||||
|
void onThumbQualityChange();
|
||||||
|
void onThumbBackgroundChange(const app::Color& color);
|
||||||
|
void onThumbEnabledChange();
|
||||||
|
void onThumbOverlayEnabledChange();
|
||||||
|
void onThumbOverlaySizeChange();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateWidgetsFromCurrentSettings();
|
void updateWidgetsFromCurrentSettings();
|
||||||
app::Document* doc();
|
app::Document* doc();
|
||||||
|
@ -50,6 +50,12 @@
|
|||||||
#include "she/font.h"
|
#include "she/font.h"
|
||||||
#include "ui/scroll_helper.h"
|
#include "ui/scroll_helper.h"
|
||||||
#include "ui/ui.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 <cstdio>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -134,6 +140,8 @@ Timeline::Timeline()
|
|||||||
, m_offset_count(0)
|
, m_offset_count(0)
|
||||||
, m_scroll(false)
|
, m_scroll(false)
|
||||||
, m_fromTimeline(false)
|
, m_fromTimeline(false)
|
||||||
|
, m_thumbnailsOverlayVisible(false)
|
||||||
|
, m_thumbnailsOverlayDirection((int)(FRMSIZE*1.5), (int)(FRMSIZE*0.5))
|
||||||
{
|
{
|
||||||
enableFlags(CTRL_RIGHT_CLICK);
|
enableFlags(CTRL_RIGHT_CLICK);
|
||||||
|
|
||||||
@ -164,6 +172,11 @@ Timeline::~Timeline()
|
|||||||
delete m_confPopup;
|
delete m_confPopup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Timeline::onThumbnailsPrefChange()
|
||||||
|
{
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
void Timeline::updateUsingEditor(Editor* editor)
|
void Timeline::updateUsingEditor(Editor* editor)
|
||||||
{
|
{
|
||||||
m_aniControls.updateUsingEditor(editor);
|
m_aniControls.updateUsingEditor(editor);
|
||||||
@ -206,6 +219,10 @@ void Timeline::updateUsingEditor(Editor* editor)
|
|||||||
m_hot.part = PART_NOTHING;
|
m_hot.part = PART_NOTHING;
|
||||||
m_clk.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);
|
setFocusStop(true);
|
||||||
regenerateLayers();
|
regenerateLayers();
|
||||||
setViewScroll(viewScroll());
|
setViewScroll(viewScroll());
|
||||||
@ -545,6 +562,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateStatusBar(msg);
|
updateStatusBar(msg);
|
||||||
|
updateCelOverlayBounds(hit);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1036,6 +1054,7 @@ void Timeline::onPaint(ui::PaintEvent& ev)
|
|||||||
drawFrameTags(g);
|
drawFrameTags(g);
|
||||||
drawRangeOutline(g);
|
drawRangeOutline(g);
|
||||||
drawClipboardRange(g);
|
drawClipboardRange(g);
|
||||||
|
drawCelOverlay(g);
|
||||||
|
|
||||||
#if 0 // Use this code to debug the calculated m_dropRange by updateDropRange()
|
#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)
|
void Timeline::onRemoveDocument(doc::Document* document)
|
||||||
{
|
{
|
||||||
if (document == m_document)
|
if (document == m_document) {
|
||||||
|
m_thumbnailsPrefConn.disconnect();
|
||||||
detachDocument();
|
detachDocument();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::onGeneralUpdate(DocumentEvent& ev)
|
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.
|
// Draw decorators to link the activeCel with its links.
|
||||||
if (data->activeIt != data->end)
|
if (data->activeIt != data->end)
|
||||||
drawCelLinkDecorators(g, bounds, cel, frame, is_active, is_hover, data);
|
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,
|
void Timeline::drawCelLinkDecorators(ui::Graphics* g, const gfx::Rect& bounds,
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "ui/scroll_bar.h"
|
#include "ui/scroll_bar.h"
|
||||||
#include "ui/timer.h"
|
#include "ui/timer.h"
|
||||||
#include "ui/widget.h"
|
#include "ui/widget.h"
|
||||||
|
#include "app/thumbnails.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -37,6 +38,10 @@ namespace ui {
|
|||||||
class Graphics;
|
class Graphics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace she {
|
||||||
|
class Surface;
|
||||||
|
}
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
namespace skin {
|
namespace skin {
|
||||||
@ -255,6 +260,10 @@ namespace app {
|
|||||||
DocumentPreferences& docPref() const;
|
DocumentPreferences& docPref() const;
|
||||||
skin::SkinTheme* skinTheme() const;
|
skin::SkinTheme* skinTheme() const;
|
||||||
|
|
||||||
|
void updateCelOverlayBounds(const Hit& hit);
|
||||||
|
void drawCelOverlay(ui::Graphics* g);
|
||||||
|
void onThumbnailsPrefChange();
|
||||||
|
|
||||||
ui::ScrollBar m_hbar;
|
ui::ScrollBar m_hbar;
|
||||||
ui::ScrollBar m_vbar;
|
ui::ScrollBar m_vbar;
|
||||||
gfx::Rect m_viewportArea;
|
gfx::Rect m_viewportArea;
|
||||||
@ -291,6 +300,13 @@ namespace app {
|
|||||||
|
|
||||||
AniControls m_aniControls;
|
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.
|
// Temporal data used to move the range.
|
||||||
struct MoveRange {
|
struct MoveRange {
|
||||||
int activeRelativeLayer;
|
int activeRelativeLayer;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user