mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-29 19:20:09 +00:00
Merge branch 'beta' into tilemap-editor
This commit is contained in:
commit
515dace441
24
INSTALL.md
24
INSTALL.md
@ -8,6 +8,7 @@
|
||||
* [Linux dependencies](#linux-dependencies)
|
||||
* [Compiling](#compiling)
|
||||
* [Windows details](#windows-details)
|
||||
* [MinGW](#mingw)
|
||||
* [macOS details](#macos-details)
|
||||
* [Issues with Retina displays](#issues-with-retina-displays)
|
||||
* [Linux details](#linux-details)
|
||||
@ -18,7 +19,7 @@
|
||||
You should be able to compile Aseprite successfully on the following
|
||||
platforms:
|
||||
|
||||
* Windows 10 + [Visual Studio Community 2019 + Windows 10.0.18362.0 SDK](https://imgur.com/a/7zs51IT)
|
||||
* Windows 10 + [Visual Studio Community 2019 + Windows 10.0.18362.0 SDK](https://imgur.com/a/7zs51IT) (we don't support [MinGW](#mingw))
|
||||
* macOS 10.15.3 Mojave + Xcode 11.2.1 + macOS 10.15 SDK (older version might work)
|
||||
* Linux + gcc 9.2 or clang 9.0
|
||||
|
||||
@ -58,8 +59,8 @@ To compile Aseprite you will need:
|
||||
|
||||
## Windows dependencies
|
||||
|
||||
* Windows 10 (**we don't support cross-compiling and don't know if this would be possible**)
|
||||
* [Visual Studio Community 2019](https://visualstudio.microsoft.com/downloads/)
|
||||
* Windows 10 (we don't support cross-compiling)
|
||||
* [Visual Studio Community 2019](https://visualstudio.microsoft.com/downloads/) (we don't support [MinGW](#mingw))
|
||||
* The [Desktop development with C++ item + Windows 10.0.18362.0 SDK](https://imgur.com/a/7zs51IT)
|
||||
from the Visual Studio installer
|
||||
|
||||
@ -130,6 +131,23 @@ And then
|
||||
In this case, `C:\deps\skia` is the directory where Skia was compiled
|
||||
or uncompressed.
|
||||
|
||||
### MinGW
|
||||
|
||||
We don't support MinGW compiler and it might bring some problems into
|
||||
the compilation process. If you see that the detected C++ compiler by
|
||||
cmake is `C:\MinGW\bin\c++.exe` or something similar, you have to get
|
||||
rid of MinGW path (`C:\MinGW\bin`) from the `PATH` environment
|
||||
variable and run cmake again from scratch, so the Visual Studio C++
|
||||
compiler (`cl.exe`) is used instead.
|
||||
|
||||
You can define the `CMAKE_IGNORE_PATH` variable when running cmake for
|
||||
the first time in case that you don't know or don't want to modify the
|
||||
`PATH` variable, e.g.:
|
||||
|
||||
cmake -DCMAKE_IGNORE_PATH=C:\MinGW\bin ...
|
||||
|
||||
More information in [issue #2449](https://github.com/aseprite/aseprite/issues/2449)
|
||||
|
||||
## macOS details
|
||||
|
||||
Run `cmake` with the following parameters and then `ninja`:
|
||||
|
@ -77,7 +77,7 @@ Aseprite includes color palettes created by:
|
||||
It tries to replicate some pixel-art algorithms:
|
||||
|
||||
* [RotSprite](http://forums.sonicretro.org/index.php?showtopic=8848&st=15&p=159754&#entry159754) by Xenowhirl.
|
||||
* [Pixel perfect drawing algorithm](http://deepnight.net/pixel-perfect-drawing/) by [Sébastien Bénard](https://twitter.com/deepnightfr) and [Carduus](https://twitter.com/CarduusHimself/status/420554200737935361).
|
||||
* [Pixel perfect drawing algorithm](https://deepnight.net/blog/tools/pixel-perfect-drawing/) by [Sébastien Bénard](https://twitter.com/deepnightfr) and [Carduus](https://twitter.com/CarduusHimself/status/420554200737935361).
|
||||
|
||||
Thanks to [third-party open source projects](docs/LICENSES.md), to
|
||||
[contributors](https://www.aseprite.org/contributors/), and all the
|
||||
|
@ -132,6 +132,7 @@
|
||||
<key command="Refresh" shortcut="F5" />
|
||||
<key command="TogglePreview" shortcut="F7" />
|
||||
<key command="FullscreenPreview" shortcut="F8" />
|
||||
<key command="FullscreenMode" shortcut="F11" mac="Cmd+Ctrl+F" />
|
||||
<key command="ShowGrid" shortcut="Ctrl+'" mac="Cmd+'" />
|
||||
<key command="ShowPixelGrid" shortcut="Ctrl+Shift+'" mac="Cmd+Shift+'" />
|
||||
<key command="SnapToGrid" shortcut="Shift+S" />
|
||||
@ -949,7 +950,8 @@
|
||||
<param name="switch" value="true" />
|
||||
</item>
|
||||
<item command="TogglePreview" text="@.view_preview" />
|
||||
<item command="AdvancedMode" text="@.view_full_screen_mode" />
|
||||
<item command="AdvancedMode" text="@.view_advanced_mode" />
|
||||
<item command="FullscreenMode" text="@.view_full_screen_mode" />
|
||||
<item command="FullscreenPreview" text="@.view_full_screen_preview" />
|
||||
<item command="Home" text="@.view_home" group="view_controls" />
|
||||
<separator />
|
||||
|
@ -197,6 +197,7 @@
|
||||
<option id="load_wintab_driver" type="bool" default="true" />
|
||||
<option id="flash_layer" type="bool" default="false" />
|
||||
<option id="nonactive_layers_opacity" type="int" default="255" />
|
||||
<option id="rgbmap_algorithm" type="doc::RgbMapAlgorithm" default="doc::RgbMapAlgorithm::DEFAULT" />
|
||||
</section>
|
||||
<section id="news">
|
||||
<option id="cache_file" type="std::string" />
|
||||
@ -266,6 +267,7 @@
|
||||
<option id="dithering_algorithm" type="std::string" />
|
||||
<option id="dithering_factor" type="int" default="100" />
|
||||
<option id="to_gray" type="ToGrayAlgorithm" default="ToGrayAlgorithm::DEFAULT" />
|
||||
<option id="advanced" type="bool" default="false" />
|
||||
</section>
|
||||
<section id="eyedropper" text="Editor">
|
||||
<option id="channel" type="EyedropperChannel" default="EyedropperChannel::COLOR_ALPHA" />
|
||||
@ -329,6 +331,7 @@
|
||||
<option id="show_alert" type="bool" default="true" />
|
||||
<option id="interlaced" type="bool" default="false" />
|
||||
<option id="loop" type="bool" default="true" />
|
||||
<option id="preserve_palette_order" type="bool" default="true" />
|
||||
</section>
|
||||
<section id="jpeg">
|
||||
<option id="show_alert" type="bool" default="true" />
|
||||
|
@ -306,6 +306,7 @@ Flip_Selection = Selection
|
||||
Flip_Vertically = Vertically
|
||||
FrameProperties = Frame Properties
|
||||
FrameTagProperties = Tag Properties
|
||||
FullscreenMode = Toggle Fullscreen Mode
|
||||
FullscreenPreview = Fullscreen Preview
|
||||
GotoFirstFrame = Go to First Frame
|
||||
GotoFirstFrameInTag = Go to First Frame In Tag
|
||||
@ -736,12 +737,14 @@ Check in case that you want to establish
|
||||
the given option as the default option.
|
||||
END
|
||||
reset = Reset
|
||||
advanced_options = Advanced Options
|
||||
|
||||
[gif_options]
|
||||
title = GIF Options
|
||||
general_options = General Options:
|
||||
interlaced = &Interlaced
|
||||
animation_loop = Animation &Loop
|
||||
preserve_palette_order = &Preserve palette order
|
||||
ok = &OK
|
||||
cancel = &Cancel
|
||||
|
||||
@ -983,6 +986,7 @@ view_set_loop_section = Set &Loop Section
|
||||
view_show_onion_skin = Show &Onion Skin
|
||||
view_timeline = &Timeline
|
||||
view_preview = Previe&w
|
||||
view_advanced_mode = &Advanced Mode
|
||||
view_full_screen_mode = &Full Screen Mode
|
||||
view_full_screen_preview = F&ull Screen Preview
|
||||
view_home = &Home
|
||||
@ -1042,12 +1046,16 @@ background = Background:
|
||||
transparent = &Transparent
|
||||
white = &White
|
||||
black = &Black
|
||||
advanced_options = Advanced Options
|
||||
pixel_ratio = Pixel Aspect Ratio:
|
||||
square_pixels = Square Pixels (1:1)
|
||||
double_wide = Double-wide Pixels (2:1)
|
||||
double_high = Double-high Pixels (1:2)
|
||||
|
||||
[rgbmap_algorithm_selector]
|
||||
label = RGB to palette index mapping:
|
||||
rgb5a3 = Table RGB 5 bits + Alpha 3 bits
|
||||
octree = Octree without Alpha
|
||||
|
||||
[open_sequence]
|
||||
title = Notice
|
||||
description = Do you want to load the following files as an animation?
|
||||
@ -1337,7 +1345,7 @@ bg_color = Background Color:
|
||||
|
||||
[palette_from_sprite]
|
||||
title = Palette from Sprite
|
||||
new_palette = Create a new palette with a specific number of colors (or less):
|
||||
new_palette = Create new palette, color count limit:
|
||||
replace_palette = Replace current palette
|
||||
replace_range = Replace current range
|
||||
alpha_channel = Create entries with alpha component
|
||||
|
@ -13,12 +13,21 @@
|
||||
<slider min="0" max="100" id="factor" minwidth="100" />
|
||||
<label text="%" />
|
||||
</hbox>
|
||||
|
||||
<combobox id="to_gray_combobox">
|
||||
<listitem text="!Luminance" />
|
||||
<listitem text="!HSV" />
|
||||
<listitem text="!HSL" />
|
||||
</combobox>
|
||||
|
||||
<check text="@.flatten" id="flatten" />
|
||||
|
||||
<check id="advanced_check" text="@general.advanced_options" cell_hspan="2" />
|
||||
<hbox id="advanced" cell_hspan="2">
|
||||
<label text="@rgbmap_algorithm_selector.label" />
|
||||
<hbox id="rgbmap_algorithm_placeholder" />
|
||||
</hbox>
|
||||
|
||||
<separator horizontal="true" />
|
||||
<hbox>
|
||||
<slider min="0" max="100" id="progress" minwidth="100" />
|
||||
|
@ -1,11 +1,13 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2014-2018 by David Capello -->
|
||||
<!-- Copyright (C) 2020 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2014-2018 David Capello -->
|
||||
<gui>
|
||||
<window id="gif_options" text="@.title">
|
||||
<vbox>
|
||||
<separator text="@.general_options" left="true" horizontal="true" />
|
||||
<check text="@.interlaced" id="interlaced" />
|
||||
<check text="@.animation_loop" id="loop" />
|
||||
<check text="@.preserve_palette_order" id="preserve_palette_order" />
|
||||
|
||||
<separator horizontal="true" />
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2001-2018 by David Capello -->
|
||||
<!-- Copyright (c) 2020 Igara Studio S.A. -->
|
||||
<!-- Copyright (c) 2001-2018 David Capello -->
|
||||
<gui>
|
||||
<window id="new_sprite" text="@.title">
|
||||
<box vertical="true">
|
||||
@ -26,7 +27,7 @@
|
||||
<item text="@.black" icon="icon_black" />
|
||||
</buttonset>
|
||||
|
||||
<check id="advanced_check" text="@.advanced_options" />
|
||||
<check id="advanced_check" text="@general.advanced_options" />
|
||||
<vbox id="advanced">
|
||||
<label text="@.pixel_ratio" />
|
||||
<combobox id="pixel_ratio" cell_align="horizontal">
|
||||
|
@ -504,6 +504,10 @@
|
||||
<label text="@.non_active_layer_opacity" />
|
||||
<slider id="nonactive_layers_opacity" min="0" max="255" width="128" />
|
||||
</hbox>
|
||||
<hbox>
|
||||
<label text="@rgbmap_algorithm_selector.label" />
|
||||
<hbox id="rgbmap_algorithm_placeholder" />
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
</panel>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2015-2018 by David Capello -->
|
||||
<!-- Copyright (c) 2020 Igara Studio S.A. -->
|
||||
<!-- Copyright (c) 2015-2018 David Capello -->
|
||||
<gui>
|
||||
<window id="palette_from_sprite" text="@.title">
|
||||
<grid columns="2">
|
||||
@ -7,7 +8,15 @@
|
||||
<expr expansive="true" id="ncolors" magnet="true" />
|
||||
<radio id="current_palette" text="@.replace_palette" group="1" cell_hspan="2" />
|
||||
<radio id="current_range" text="@.replace_range" group="1" cell_hspan="2" />
|
||||
|
||||
<separator horizontal="true" cell_hspan="2" />
|
||||
|
||||
<check id="alpha_channel" text="@.alpha_channel" cell_hspan="2" />
|
||||
<check id="advanced_check" text="@general.advanced_options" cell_hspan="2" />
|
||||
<hbox id="advanced" cell_hspan="2">
|
||||
<label text="@rgbmap_algorithm_selector.label" />
|
||||
<hbox id="rgbmap_algorithm_placeholder" />
|
||||
</hbox>
|
||||
|
||||
<separator horizontal="true" cell_hspan="2" />
|
||||
|
||||
|
@ -85,10 +85,10 @@ We are using some C++11 features, mainly:
|
||||
* Use range-based for loops (`for (const auto& item : values) { ... }`)
|
||||
* Use template alias (`template<typename T> alias = orig<T>;`)
|
||||
* Use non-generic lambda functions
|
||||
* Use `std::shared_ptr` and `std::unique_ptr`
|
||||
* Use `std::shared_ptr`, `std::unique_ptr`, or `base::Ref`
|
||||
* Use `base::clamp` (no `std::clamp` yet)
|
||||
* Use `static constexpr T v = ...;`
|
||||
* You can use `<atomic>`, `<thread>`, `<mutex>`, and `<condition_variable>`
|
||||
* We can use `using T = ...;` instead of `typedef ... T`
|
||||
* Prefer `using T = ...;` instead of `typedef ... T`
|
||||
* We use gcc 9.2 or clang 9.0 on Linux, so check the features available in
|
||||
https://developer.mozilla.org/en-US/docs/Mozilla/Using_CXX_in_Mozilla_code
|
||||
|
2
laf
2
laf
@ -1 +1 @@
|
||||
Subproject commit e1fb70a069c6482be282bf6f6d9190e3a0def14a
|
||||
Subproject commit e1eec6912548498b87a17e01e88249cbc9328ad3
|
@ -227,6 +227,7 @@ if(ENABLE_UI)
|
||||
commands/cmd_fit_screen.cpp
|
||||
commands/cmd_frame_properties.cpp
|
||||
commands/cmd_frame_tag_properties.cpp
|
||||
commands/cmd_fullscreen_mode.cpp
|
||||
commands/cmd_fullscreen_preview.cpp
|
||||
commands/cmd_goto_frame.cpp
|
||||
commands/cmd_goto_layer.cpp
|
||||
@ -372,6 +373,7 @@ if(ENABLE_UI)
|
||||
ui/preview_editor.cpp
|
||||
ui/recent_listbox.cpp
|
||||
ui/resources_listbox.cpp
|
||||
ui/rgbmap_algorithm_selector.cpp
|
||||
ui/search_entry.cpp
|
||||
ui/select_accelerator.cpp
|
||||
ui/selection_mode_field.cpp
|
||||
|
@ -373,16 +373,13 @@ void App::run()
|
||||
ResourceFinder rf;
|
||||
rf.includeDataDir(fmt::format("icons/ase{0}.png", size).c_str());
|
||||
if (rf.findFirst()) {
|
||||
os::Surface* surf = os::instance()->loadRgbaSurface(rf.filename().c_str());
|
||||
os::SurfaceRef surf = os::instance()->loadRgbaSurface(rf.filename().c_str());
|
||||
if (surf)
|
||||
icons.push_back(surf);
|
||||
}
|
||||
}
|
||||
|
||||
display->setIcons(icons);
|
||||
|
||||
for (auto surf : icons)
|
||||
surf->dispose();
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
// Just ignore the exception, we couldn't change the app icon, no
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "app/util/filetoks.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/string.h"
|
||||
#include "fmt/format.h"
|
||||
@ -312,7 +311,7 @@ AppMenus* AppMenus::instance()
|
||||
static AppMenus* instance = NULL;
|
||||
if (!instance) {
|
||||
instance = new AppMenus;
|
||||
App::instance()->Exit.connect(base::Bind<void>(&destroy_instance, instance));
|
||||
App::instance()->Exit.connect([]{ destroy_instance(instance); });
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
@ -323,13 +322,7 @@ AppMenus::AppMenus()
|
||||
{
|
||||
m_recentFilesConn =
|
||||
App::instance()->recentFiles()->Changed.connect(
|
||||
base::Bind(&AppMenus::rebuildRecentList, this));
|
||||
}
|
||||
|
||||
AppMenus::~AppMenus()
|
||||
{
|
||||
if (m_osMenu)
|
||||
m_osMenu->dispose();
|
||||
[this]{ rebuildRecentList(); });
|
||||
}
|
||||
|
||||
void AppMenus::reload()
|
||||
@ -563,10 +556,10 @@ bool AppMenus::rebuildRecentList()
|
||||
// Sync native menus
|
||||
if (owner->native() &&
|
||||
owner->native()->menuItem) {
|
||||
os::Menus* menus = os::instance()->menus();
|
||||
os::Menu* osMenu = (menus ? menus->createMenu(): nullptr);
|
||||
auto menus = os::instance()->menus();
|
||||
os::MenuRef osMenu = (menus ? menus->makeMenu(): nullptr);
|
||||
if (osMenu) {
|
||||
createNativeSubmenus(osMenu, menu);
|
||||
createNativeSubmenus(osMenu.get(), menu);
|
||||
owner->native()->menuItem->setSubmenu(osMenu);
|
||||
}
|
||||
}
|
||||
@ -826,8 +819,9 @@ void AppMenus::createNativeMenus()
|
||||
if (!menus) // This platform doesn't support native menu items
|
||||
return;
|
||||
|
||||
os::Menu* oldOSMenu = m_osMenu;
|
||||
m_osMenu = menus->createMenu();
|
||||
// Save a reference to the old menu to avoid destroying it.
|
||||
os::MenuRef oldOSMenu = m_osMenu;
|
||||
m_osMenu = menus->makeMenu();
|
||||
|
||||
#ifdef __APPLE__ // Create default macOS app menus (App ... Window)
|
||||
{
|
||||
@ -863,24 +857,24 @@ void AppMenus::createNativeMenus()
|
||||
os::MenuItemInfo quit(fmt::format("Quit {}", get_app_name()), os::MenuItemInfo::Quit);
|
||||
quit.shortcut = os::Shortcut('q', os::kKeyCmdModifier);
|
||||
|
||||
os::Menu* appMenu = menus->createMenu();
|
||||
appMenu->addItem(menus->createMenuItem(about));
|
||||
appMenu->addItem(menus->createMenuItem(os::MenuItemInfo(os::MenuItemInfo::Separator)));
|
||||
appMenu->addItem(menus->createMenuItem(preferences));
|
||||
appMenu->addItem(menus->createMenuItem(os::MenuItemInfo(os::MenuItemInfo::Separator)));
|
||||
appMenu->addItem(menus->createMenuItem(hide));
|
||||
appMenu->addItem(menus->createMenuItem(os::MenuItemInfo("Hide Others", os::MenuItemInfo::HideOthers)));
|
||||
appMenu->addItem(menus->createMenuItem(os::MenuItemInfo("Show All", os::MenuItemInfo::ShowAll)));
|
||||
appMenu->addItem(menus->createMenuItem(os::MenuItemInfo(os::MenuItemInfo::Separator)));
|
||||
appMenu->addItem(menus->createMenuItem(quit));
|
||||
os::MenuRef appMenu = menus->makeMenu();
|
||||
appMenu->addItem(menus->makeMenuItem(about));
|
||||
appMenu->addItem(menus->makeMenuItem(os::MenuItemInfo(os::MenuItemInfo::Separator)));
|
||||
appMenu->addItem(menus->makeMenuItem(preferences));
|
||||
appMenu->addItem(menus->makeMenuItem(os::MenuItemInfo(os::MenuItemInfo::Separator)));
|
||||
appMenu->addItem(menus->makeMenuItem(hide));
|
||||
appMenu->addItem(menus->makeMenuItem(os::MenuItemInfo("Hide Others", os::MenuItemInfo::HideOthers)));
|
||||
appMenu->addItem(menus->makeMenuItem(os::MenuItemInfo("Show All", os::MenuItemInfo::ShowAll)));
|
||||
appMenu->addItem(menus->makeMenuItem(os::MenuItemInfo(os::MenuItemInfo::Separator)));
|
||||
appMenu->addItem(menus->makeMenuItem(quit));
|
||||
|
||||
os::MenuItem* appItem = menus->createMenuItem(os::MenuItemInfo("App"));
|
||||
os::MenuItemRef appItem = menus->makeMenuItem(os::MenuItemInfo("App"));
|
||||
appItem->setSubmenu(appMenu);
|
||||
m_osMenu->addItem(appItem);
|
||||
}
|
||||
#endif
|
||||
|
||||
createNativeSubmenus(m_osMenu, m_rootMenu.get());
|
||||
createNativeSubmenus(m_osMenu.get(), m_rootMenu.get());
|
||||
|
||||
#ifdef __APPLE__
|
||||
{
|
||||
@ -898,11 +892,11 @@ void AppMenus::createNativeMenus()
|
||||
os::MenuItemInfo minimize("Minimize", os::MenuItemInfo::Minimize);
|
||||
minimize.shortcut = os::Shortcut('m', os::kKeyCmdModifier);
|
||||
|
||||
os::Menu* windowMenu = menus->createMenu();
|
||||
windowMenu->addItem(menus->createMenuItem(minimize));
|
||||
windowMenu->addItem(menus->createMenuItem(os::MenuItemInfo("Zoom", os::MenuItemInfo::Zoom)));
|
||||
os::MenuRef windowMenu = menus->makeMenu();
|
||||
windowMenu->addItem(menus->makeMenuItem(minimize));
|
||||
windowMenu->addItem(menus->makeMenuItem(os::MenuItemInfo("Zoom", os::MenuItemInfo::Zoom)));
|
||||
|
||||
os::MenuItem* windowItem = menus->createMenuItem(os::MenuItemInfo("Window"));
|
||||
os::MenuItemRef windowItem = menus->makeMenuItem(os::MenuItemInfo("Window"));
|
||||
windowItem->setSubmenu(windowMenu);
|
||||
|
||||
// We use helpIndex+1 because the first index in m_osMenu is the
|
||||
@ -913,10 +907,11 @@ void AppMenus::createNativeMenus()
|
||||
|
||||
menus->setAppMenu(m_osMenu);
|
||||
if (oldOSMenu)
|
||||
oldOSMenu->dispose();
|
||||
oldOSMenu.reset();
|
||||
}
|
||||
|
||||
void AppMenus::createNativeSubmenus(os::Menu* osMenu, const ui::Menu* uiMenu)
|
||||
void AppMenus::createNativeSubmenus(os::Menu* osMenu,
|
||||
const ui::Menu* uiMenu)
|
||||
{
|
||||
os::Menus* menus = os::instance()->menus();
|
||||
|
||||
@ -960,7 +955,7 @@ void AppMenus::createNativeSubmenus(os::Menu* osMenu, const ui::Menu* uiMenu)
|
||||
continue;
|
||||
}
|
||||
|
||||
os::MenuItem* osItem = menus->createMenuItem(info);
|
||||
os::MenuItemRef osItem = menus->makeMenuItem(info);
|
||||
if (osItem) {
|
||||
osMenu->addItem(osItem);
|
||||
if (appMenuItem) {
|
||||
@ -970,8 +965,8 @@ void AppMenus::createNativeSubmenus(os::Menu* osMenu, const ui::Menu* uiMenu)
|
||||
|
||||
if (child->type() == ui::kMenuItemWidget &&
|
||||
((ui::MenuItem*)child)->hasSubmenu()) {
|
||||
os::Menu* osSubmenu = menus->createMenu();
|
||||
createNativeSubmenus(osSubmenu, ((ui::MenuItem*)child)->getSubmenu());
|
||||
os::MenuRef osSubmenu = menus->makeMenu();
|
||||
createNativeSubmenus(osSubmenu.get(), ((ui::MenuItem*)child)->getSubmenu());
|
||||
osItem->setSubmenu(osSubmenu);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "app/widget_type_mismatch.h"
|
||||
#include "base/disable_copying.h"
|
||||
#include "obs/connection.h"
|
||||
#include "os/menus.h"
|
||||
#include "ui/base.h"
|
||||
#include "ui/menu.h"
|
||||
|
||||
@ -22,11 +23,6 @@
|
||||
class TiXmlElement;
|
||||
class TiXmlHandle;
|
||||
|
||||
namespace os {
|
||||
class Menu;
|
||||
class Shortcut;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
class Command;
|
||||
class Params;
|
||||
@ -41,8 +37,6 @@ namespace app {
|
||||
public:
|
||||
static AppMenus* instance();
|
||||
|
||||
~AppMenus();
|
||||
|
||||
void reload();
|
||||
void initTheme();
|
||||
|
||||
@ -83,7 +77,8 @@ namespace app {
|
||||
void syncNativeMenuItemKeyShortcuts(Menu* menu);
|
||||
void updateMenusList();
|
||||
void createNativeMenus();
|
||||
void createNativeSubmenus(os::Menu* osMenu, const ui::Menu* uiMenu);
|
||||
void createNativeSubmenus(os::Menu* osMenu,
|
||||
const ui::Menu* uiMenu);
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
void loadScriptsSubmenu(ui::Menu* menu,
|
||||
@ -118,7 +113,7 @@ namespace app {
|
||||
std::map<std::string, GroupInfo> m_groups;
|
||||
// Native main menu bar (== nullptr if the platform doesn't
|
||||
// support native menus)
|
||||
os::Menu* m_osMenu;
|
||||
os::MenuRef m_osMenu;
|
||||
XmlTranslator m_xmlTranslator;
|
||||
};
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
#include "app/check_update_delegate.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/launcher.h"
|
||||
#include "base/replace_string.h"
|
||||
@ -127,7 +126,7 @@ void CheckUpdateThreadLauncher::launch()
|
||||
m_delegate->onCheckingUpdates();
|
||||
|
||||
m_bgJob.reset(new CheckUpdateBackgroundJob);
|
||||
m_thread.reset(new base::thread(base::Bind<void>(&CheckUpdateThreadLauncher::checkForUpdates, this)));
|
||||
m_thread.reset(new base::thread([this]{ checkForUpdates(); }));
|
||||
|
||||
// Start a timer to monitoring the progress of the background job
|
||||
// executed in "m_thread". The "onMonitoringTick" method will be
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -17,7 +17,7 @@
|
||||
namespace app {
|
||||
namespace cmd {
|
||||
|
||||
AssignColorProfile::AssignColorProfile(doc::Sprite* sprite, const gfx::ColorSpacePtr& cs)
|
||||
AssignColorProfile::AssignColorProfile(doc::Sprite* sprite, const gfx::ColorSpaceRef& cs)
|
||||
: WithSprite(sprite)
|
||||
, m_oldCS(sprite->colorSpace())
|
||||
, m_newCS(cs)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -18,7 +18,7 @@ namespace cmd {
|
||||
class AssignColorProfile : public Cmd,
|
||||
public WithSprite {
|
||||
public:
|
||||
AssignColorProfile(doc::Sprite* sprite, const gfx::ColorSpacePtr& cs);
|
||||
AssignColorProfile(doc::Sprite* sprite, const gfx::ColorSpaceRef& cs);
|
||||
|
||||
protected:
|
||||
void onExecute() override;
|
||||
@ -32,8 +32,8 @@ namespace cmd {
|
||||
}
|
||||
|
||||
private:
|
||||
gfx::ColorSpacePtr m_oldCS;
|
||||
gfx::ColorSpacePtr m_newCS;
|
||||
gfx::ColorSpaceRef m_oldCS;
|
||||
gfx::ColorSpaceRef m_newCS;
|
||||
};
|
||||
|
||||
} // namespace cmd
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -24,7 +24,7 @@ namespace app {
|
||||
namespace cmd {
|
||||
|
||||
static doc::ImageRef convert_image_color_space(const doc::Image* srcImage,
|
||||
const gfx::ColorSpacePtr& newCS,
|
||||
const gfx::ColorSpaceRef& newCS,
|
||||
os::ColorSpaceConversion* conversion)
|
||||
{
|
||||
ImageSpec spec = srcImage->spec();
|
||||
@ -71,14 +71,14 @@ static doc::ImageRef convert_image_color_space(const doc::Image* srcImage,
|
||||
}
|
||||
|
||||
void convert_color_profile(doc::Sprite* sprite,
|
||||
const gfx::ColorSpacePtr& newCS)
|
||||
const gfx::ColorSpaceRef& newCS)
|
||||
{
|
||||
ASSERT(sprite->colorSpace());
|
||||
ASSERT(newCS);
|
||||
|
||||
os::System* system = os::instance();
|
||||
auto srcOCS = system->createColorSpace(sprite->colorSpace());
|
||||
auto dstOCS = system->createColorSpace(newCS);
|
||||
auto srcOCS = system->makeColorSpace(sprite->colorSpace());
|
||||
auto dstOCS = system->makeColorSpace(newCS);
|
||||
ASSERT(srcOCS);
|
||||
ASSERT(dstOCS);
|
||||
|
||||
@ -123,15 +123,15 @@ void convert_color_profile(doc::Sprite* sprite,
|
||||
|
||||
void convert_color_profile(doc::Image* image,
|
||||
doc::Palette* palette,
|
||||
const gfx::ColorSpacePtr& oldCS,
|
||||
const gfx::ColorSpacePtr& newCS)
|
||||
const gfx::ColorSpaceRef& oldCS,
|
||||
const gfx::ColorSpaceRef& newCS)
|
||||
{
|
||||
ASSERT(oldCS);
|
||||
ASSERT(newCS);
|
||||
|
||||
os::System* system = os::instance();
|
||||
auto srcOCS = system->createColorSpace(oldCS);
|
||||
auto dstOCS = system->createColorSpace(newCS);
|
||||
auto srcOCS = system->makeColorSpace(oldCS);
|
||||
auto dstOCS = system->makeColorSpace(newCS);
|
||||
ASSERT(srcOCS);
|
||||
ASSERT(dstOCS);
|
||||
|
||||
@ -161,7 +161,7 @@ void convert_color_profile(doc::Image* image,
|
||||
}
|
||||
}
|
||||
|
||||
ConvertColorProfile::ConvertColorProfile(doc::Sprite* sprite, const gfx::ColorSpacePtr& newCS)
|
||||
ConvertColorProfile::ConvertColorProfile(doc::Sprite* sprite, const gfx::ColorSpaceRef& newCS)
|
||||
: WithSprite(sprite)
|
||||
{
|
||||
os::System* system = os::instance();
|
||||
@ -169,8 +169,8 @@ ConvertColorProfile::ConvertColorProfile(doc::Sprite* sprite, const gfx::ColorSp
|
||||
ASSERT(sprite->colorSpace());
|
||||
ASSERT(newCS);
|
||||
|
||||
auto srcOCS = system->createColorSpace(sprite->colorSpace());
|
||||
auto dstOCS = system->createColorSpace(newCS);
|
||||
auto srcOCS = system->makeColorSpace(sprite->colorSpace());
|
||||
auto dstOCS = system->makeColorSpace(newCS);
|
||||
|
||||
ASSERT(srcOCS);
|
||||
ASSERT(dstOCS);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -28,7 +28,7 @@ namespace cmd {
|
||||
class ConvertColorProfile : public Cmd,
|
||||
public WithSprite {
|
||||
public:
|
||||
ConvertColorProfile(doc::Sprite* sprite, const gfx::ColorSpacePtr& newCS);
|
||||
ConvertColorProfile(doc::Sprite* sprite, const gfx::ColorSpaceRef& newCS);
|
||||
|
||||
protected:
|
||||
void onExecute() override;
|
||||
@ -45,12 +45,12 @@ namespace cmd {
|
||||
// Converts the sprite to the new color profile without undo information.
|
||||
// TODO how to merge this function with cmd::ConvertColorProfile
|
||||
void convert_color_profile(doc::Sprite* sprite,
|
||||
const gfx::ColorSpacePtr& newCS);
|
||||
const gfx::ColorSpaceRef& newCS);
|
||||
|
||||
void convert_color_profile(doc::Image* image,
|
||||
doc::Palette* palette,
|
||||
const gfx::ColorSpacePtr& oldCS,
|
||||
const gfx::ColorSpacePtr& newCS);
|
||||
const gfx::ColorSpaceRef& oldCS,
|
||||
const gfx::ColorSpaceRef& newCS);
|
||||
|
||||
} // namespace cmd
|
||||
} // namespace app
|
||||
|
@ -70,6 +70,7 @@ private:
|
||||
SetPixelFormat::SetPixelFormat(Sprite* sprite,
|
||||
const PixelFormat newFormat,
|
||||
const render::Dithering& dithering,
|
||||
const doc::RgbMapAlgorithm mapAlgorithm,
|
||||
doc::rgba_to_graya_func toGray,
|
||||
render::TaskDelegate* delegate)
|
||||
: WithSprite(sprite)
|
||||
@ -102,6 +103,7 @@ SetPixelFormat::SetPixelFormat(Sprite* sprite,
|
||||
oldImage,
|
||||
cel->frame(),
|
||||
cel->layer()->isBackground(),
|
||||
mapAlgorithm,
|
||||
toGray,
|
||||
&superDel);
|
||||
|
||||
@ -118,6 +120,7 @@ SetPixelFormat::SetPixelFormat(Sprite* sprite,
|
||||
oldImage,
|
||||
0, // TODO select a frame or generate other tilesets?
|
||||
false, // TODO is background? it depends of the layer where this tileset is used
|
||||
mapAlgorithm,
|
||||
toGray,
|
||||
&superDel);
|
||||
}
|
||||
@ -191,6 +194,7 @@ void SetPixelFormat::convertImage(doc::Sprite* sprite,
|
||||
const doc::ImageRef& oldImage,
|
||||
const doc::frame_t frame,
|
||||
const bool isBackground,
|
||||
const doc::RgbMapAlgorithm mapAlgorithm,
|
||||
doc::rgba_to_graya_func toGray,
|
||||
render::TaskDelegate* delegate)
|
||||
{
|
||||
@ -201,7 +205,7 @@ void SetPixelFormat::convertImage(doc::Sprite* sprite,
|
||||
render::convert_pixel_format
|
||||
(oldImage.get(), nullptr, m_newFormat,
|
||||
dithering,
|
||||
sprite->rgbMap(frame),
|
||||
sprite->rgbMap(frame, sprite->rgbMapForSprite(), mapAlgorithm),
|
||||
sprite->palette(frame),
|
||||
isBackground,
|
||||
oldImage->maskColor(),
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "doc/frame.h"
|
||||
#include "doc/image_ref.h"
|
||||
#include "doc/pixel_format.h"
|
||||
#include "doc/rgbmap_algorithm.h"
|
||||
|
||||
namespace doc {
|
||||
class Sprite;
|
||||
@ -34,6 +35,7 @@ namespace cmd {
|
||||
SetPixelFormat(doc::Sprite* sprite,
|
||||
const doc::PixelFormat newFormat,
|
||||
const render::Dithering& dithering,
|
||||
const doc::RgbMapAlgorithm mapAlgorithm,
|
||||
doc::rgba_to_graya_func toGray,
|
||||
render::TaskDelegate* delegate);
|
||||
|
||||
@ -52,6 +54,7 @@ namespace cmd {
|
||||
const doc::ImageRef& oldImage,
|
||||
const doc::frame_t frame,
|
||||
const bool isBackground,
|
||||
const doc::RgbMapAlgorithm mapAlgorithm,
|
||||
doc::rgba_to_graya_func toGray,
|
||||
render::TaskDelegate* delegate);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -33,12 +33,12 @@ void initialize_color_spaces(Preferences& pref)
|
||||
});
|
||||
}
|
||||
|
||||
os::ColorSpacePtr get_screen_color_space()
|
||||
os::ColorSpaceRef get_screen_color_space()
|
||||
{
|
||||
return os::instance()->defaultDisplay()->colorSpace();
|
||||
}
|
||||
|
||||
os::ColorSpacePtr get_current_color_space()
|
||||
os::ColorSpaceRef get_current_color_space()
|
||||
{
|
||||
#ifdef ENABLE_UI
|
||||
if (current_editor)
|
||||
@ -48,14 +48,14 @@ os::ColorSpacePtr get_current_color_space()
|
||||
return get_screen_color_space();
|
||||
}
|
||||
|
||||
gfx::ColorSpacePtr get_working_rgb_space_from_preferences()
|
||||
gfx::ColorSpaceRef get_working_rgb_space_from_preferences()
|
||||
{
|
||||
if (Preferences::instance().color.manage()) {
|
||||
const std::string name = Preferences::instance().color.workingRgbSpace();
|
||||
if (name == "sRGB")
|
||||
return gfx::ColorSpace::MakeSRGB();
|
||||
|
||||
std::vector<os::ColorSpacePtr> colorSpaces;
|
||||
std::vector<os::ColorSpaceRef> colorSpaces;
|
||||
os::instance()->listColorSpaces(colorSpaces);
|
||||
for (auto& cs : colorSpaces) {
|
||||
if (cs->gfxColorSpace()->name() == name)
|
||||
@ -78,8 +78,8 @@ ConvertCS::ConvertCS()
|
||||
}
|
||||
}
|
||||
|
||||
ConvertCS::ConvertCS(const os::ColorSpacePtr& srcCS,
|
||||
const os::ColorSpacePtr& dstCS)
|
||||
ConvertCS::ConvertCS(const os::ColorSpaceRef& srcCS,
|
||||
const os::ColorSpaceRef& dstCS)
|
||||
{
|
||||
if (g_manage) {
|
||||
m_conversion = os::instance()->convertBetweenColorSpace(srcCS, dstCS);
|
||||
@ -108,10 +108,10 @@ ConvertCS convert_from_current_to_screen_color_space()
|
||||
return ConvertCS();
|
||||
}
|
||||
|
||||
ConvertCS convert_from_custom_to_srgb(const os::ColorSpacePtr& from)
|
||||
ConvertCS convert_from_custom_to_srgb(const os::ColorSpaceRef& from)
|
||||
{
|
||||
return ConvertCS(from,
|
||||
os::instance()->createColorSpace(gfx::ColorSpace::MakeSRGB()));
|
||||
os::instance()->makeColorSpace(gfx::ColorSpace::MakeSRGB()));
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (c) 2018-2020 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -12,8 +12,6 @@
|
||||
#include "gfx/color_space.h"
|
||||
#include "os/color_space.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace doc {
|
||||
class Sprite;
|
||||
}
|
||||
@ -23,27 +21,27 @@ namespace app {
|
||||
|
||||
void initialize_color_spaces(Preferences& pref);
|
||||
|
||||
os::ColorSpacePtr get_screen_color_space();
|
||||
os::ColorSpaceRef get_screen_color_space();
|
||||
|
||||
// Returns the color space of the current document.
|
||||
os::ColorSpacePtr get_current_color_space();
|
||||
os::ColorSpaceRef get_current_color_space();
|
||||
|
||||
gfx::ColorSpacePtr get_working_rgb_space_from_preferences();
|
||||
gfx::ColorSpaceRef get_working_rgb_space_from_preferences();
|
||||
|
||||
class ConvertCS {
|
||||
public:
|
||||
ConvertCS();
|
||||
ConvertCS(const os::ColorSpacePtr& srcCS,
|
||||
const os::ColorSpacePtr& dstCS);
|
||||
ConvertCS(const os::ColorSpaceRef& srcCS,
|
||||
const os::ColorSpaceRef& dstCS);
|
||||
ConvertCS(ConvertCS&&);
|
||||
ConvertCS& operator=(const ConvertCS&) = delete;
|
||||
gfx::Color operator()(const gfx::Color c);
|
||||
private:
|
||||
std::unique_ptr<os::ColorSpaceConversion> m_conversion;
|
||||
os::Ref<os::ColorSpaceConversion> m_conversion;
|
||||
};
|
||||
|
||||
ConvertCS convert_from_current_to_screen_color_space();
|
||||
ConvertCS convert_from_custom_to_srgb(const os::ColorSpacePtr& from);
|
||||
ConvertCS convert_from_custom_to_srgb(const os::ColorSpaceRef& from);
|
||||
|
||||
} // namespace app
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "app/commands/command.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "base/bind.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ver/info.h"
|
||||
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "app/ui/editor/select_box_state.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/clamp.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/mask.h"
|
||||
@ -75,13 +74,13 @@ public:
|
||||
setTop(0);
|
||||
setBottom(0);
|
||||
|
||||
width() ->Change.connect(base::Bind<void>(&CanvasSizeWindow::onSizeChange, this));
|
||||
height()->Change.connect(base::Bind<void>(&CanvasSizeWindow::onSizeChange, this));
|
||||
dir() ->ItemChange.connect(base::Bind<void>(&CanvasSizeWindow::onDirChange, this));;
|
||||
left() ->Change.connect(base::Bind<void>(&CanvasSizeWindow::onBorderChange, this));
|
||||
right() ->Change.connect(base::Bind<void>(&CanvasSizeWindow::onBorderChange, this));
|
||||
top() ->Change.connect(base::Bind<void>(&CanvasSizeWindow::onBorderChange, this));
|
||||
bottom()->Change.connect(base::Bind<void>(&CanvasSizeWindow::onBorderChange, this));
|
||||
width() ->Change.connect([this]{ onSizeChange(); });
|
||||
height()->Change.connect([this]{ onSizeChange(); });
|
||||
dir() ->ItemChange.connect([this]{ onDirChange(); });
|
||||
left() ->Change.connect([this]{ onBorderChange(); });
|
||||
right() ->Change.connect([this]{ onBorderChange(); });
|
||||
top() ->Change.connect([this]{ onBorderChange(); });
|
||||
bottom()->Change.connect([this]{ onBorderChange(); });
|
||||
|
||||
m_editor->setState(m_selectBoxState);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -21,7 +22,6 @@
|
||||
#include "app/ui/timeline/timeline.h"
|
||||
#include "app/ui/user_data_popup.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/mem_utils.h"
|
||||
#include "base/scoped_value.h"
|
||||
#include "doc/cel.h"
|
||||
@ -50,9 +50,9 @@ public:
|
||||
, m_cel(nullptr)
|
||||
, m_selfUpdate(false)
|
||||
, m_newUserData(false) {
|
||||
opacity()->Change.connect(base::Bind<void>(&CelPropertiesWindow::onStartTimer, this));
|
||||
userData()->Click.connect(base::Bind<void>(&CelPropertiesWindow::onPopupUserData, this));
|
||||
m_timer.Tick.connect(base::Bind<void>(&CelPropertiesWindow::onCommitChange, this));
|
||||
opacity()->Change.connect([this]{ onStartTimer(); });
|
||||
userData()->Click.connect([this]{ onPopupUserData(); });
|
||||
m_timer.Tick.connect([this]{ onCommitChange(); });
|
||||
|
||||
remapWindow();
|
||||
centerWindow();
|
||||
|
@ -26,8 +26,8 @@
|
||||
#include "app/ui/dithering_selector.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/editor/editor_render.h"
|
||||
#include "app/ui/rgbmap_algorithm_selector.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/thread.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/layer.h"
|
||||
@ -89,6 +89,7 @@ public:
|
||||
const doc::frame_t frame,
|
||||
const doc::PixelFormat pixelFormat,
|
||||
const render::Dithering& dithering,
|
||||
const doc::RgbMapAlgorithm rgbMapAlgorithm,
|
||||
const gen::ToGrayAlgorithm toGray,
|
||||
const gfx::Point& pos,
|
||||
const bool newBlend)
|
||||
@ -102,11 +103,13 @@ public:
|
||||
sprite, frame,
|
||||
pixelFormat,
|
||||
dithering,
|
||||
rgbMapAlgorithm,
|
||||
toGray,
|
||||
newBlend]() { // Copy the matrix
|
||||
run(sprite, frame,
|
||||
pixelFormat,
|
||||
dithering,
|
||||
rgbMapAlgorithm,
|
||||
toGray,
|
||||
newBlend);
|
||||
})
|
||||
@ -131,6 +134,7 @@ private:
|
||||
const doc::frame_t frame,
|
||||
const doc::PixelFormat pixelFormat,
|
||||
const render::Dithering& dithering,
|
||||
const doc::RgbMapAlgorithm rgbMapAlgorithm,
|
||||
const gen::ToGrayAlgorithm toGray,
|
||||
const bool newBlend) {
|
||||
doc::ImageRef tmp(
|
||||
@ -152,7 +156,9 @@ private:
|
||||
m_image.get(),
|
||||
pixelFormat,
|
||||
dithering,
|
||||
sprite->rgbMap(frame),
|
||||
sprite->rgbMap(frame,
|
||||
sprite->rgbMapForSprite(),
|
||||
rgbMapAlgorithm),
|
||||
sprite->palette(frame),
|
||||
(sprite->backgroundLayer() != nullptr),
|
||||
0,
|
||||
@ -189,9 +195,11 @@ public:
|
||||
, m_imageBuffer(new doc::ImageBuffer)
|
||||
, m_selectedItem(nullptr)
|
||||
, m_ditheringSelector(nullptr)
|
||||
, m_mapAlgorithmSelector(nullptr)
|
||||
, m_imageJustCreated(true)
|
||||
{
|
||||
doc::PixelFormat from = m_editor->sprite()->pixelFormat();
|
||||
const auto& pref = Preferences::instance();
|
||||
const doc::PixelFormat from = m_editor->sprite()->pixelFormat();
|
||||
|
||||
// Add the color mode in the window title
|
||||
switch (from) {
|
||||
@ -209,40 +217,63 @@ public:
|
||||
m_ditheringSelector = new DitheringSelector(DitheringSelector::SelectBoth);
|
||||
m_ditheringSelector->setExpansive(true);
|
||||
|
||||
m_mapAlgorithmSelector = new RgbMapAlgorithmSelector;
|
||||
m_mapAlgorithmSelector->setExpansive(true);
|
||||
|
||||
// Select default dithering method
|
||||
{
|
||||
int index = m_ditheringSelector->findItemIndex(
|
||||
Preferences::instance().quantization.ditheringAlgorithm());
|
||||
pref.quantization.ditheringAlgorithm());
|
||||
if (index >= 0)
|
||||
m_ditheringSelector->setSelectedItemIndex(index);
|
||||
}
|
||||
|
||||
m_ditheringSelector->Change.connect(
|
||||
base::Bind<void>(&ColorModeWindow::onDithering, this));
|
||||
ditheringPlaceholder()->addChild(m_ditheringSelector);
|
||||
// Select default RgbMap algorithm
|
||||
m_mapAlgorithmSelector->algorithm(pref.experimental.rgbmapAlgorithm());
|
||||
|
||||
factor()->Change.connect(base::Bind<void>(&ColorModeWindow::onDithering, this));
|
||||
ditheringPlaceholder()->addChild(m_ditheringSelector);
|
||||
rgbmapAlgorithmPlaceholder()->addChild(m_mapAlgorithmSelector);
|
||||
|
||||
const bool adv = pref.quantization.advanced();
|
||||
advancedCheck()->setSelected(adv);
|
||||
advanced()->setVisible(adv);
|
||||
|
||||
// Signals
|
||||
m_ditheringSelector->Change.connect([this]{ onIndexParamChange(); });
|
||||
m_mapAlgorithmSelector->Change.connect([this]{ onIndexParamChange(); });
|
||||
factor()->Change.connect([this]{ onIndexParamChange(); });
|
||||
|
||||
advancedCheck()->Click.connect(
|
||||
[this](ui::Event&){
|
||||
advanced()->setVisible(advancedCheck()->isSelected());
|
||||
|
||||
const gfx::Rect origBounds = bounds();
|
||||
setBounds(gfx::Rect(bounds().origin(), sizeHint()));
|
||||
manager()->invalidateRect(origBounds);
|
||||
});
|
||||
}
|
||||
else {
|
||||
amount()->setVisible(false);
|
||||
advancedCheck()->setVisible(false);
|
||||
advanced()->setVisible(false);
|
||||
}
|
||||
if (from != IMAGE_GRAYSCALE) {
|
||||
colorMode()->addChild(new ConversionItem(IMAGE_GRAYSCALE));
|
||||
|
||||
toGrayCombobox()->Change.connect(base::Bind<void>(&ColorModeWindow::onToGrayChange, this));
|
||||
toGrayCombobox()->Change.connect([this]{ onToGrayChange(); });
|
||||
}
|
||||
|
||||
colorModeView()->setMinSize(
|
||||
colorModeView()->sizeHint() +
|
||||
colorMode()->sizeHint());
|
||||
|
||||
colorMode()->Change.connect(base::Bind<void>(&ColorModeWindow::onChangeColorMode, this));
|
||||
m_timer.Tick.connect(base::Bind<void>(&ColorModeWindow::onMonitorProgress, this));
|
||||
colorMode()->Change.connect([this]{ onChangeColorMode(); });
|
||||
m_timer.Tick.connect([this]{ onMonitorProgress(); });
|
||||
|
||||
progress()->setReadOnly(true);
|
||||
|
||||
// Default dithering factor
|
||||
factor()->setValue(Preferences::instance().quantization.ditheringFactor());
|
||||
factor()->setValue(pref.quantization.ditheringFactor());
|
||||
|
||||
// Select first option
|
||||
colorMode()->selectIndex(0);
|
||||
@ -267,6 +298,13 @@ public:
|
||||
return d;
|
||||
}
|
||||
|
||||
doc::RgbMapAlgorithm rgbMapAlgorithm() const {
|
||||
if (m_mapAlgorithmSelector)
|
||||
return m_mapAlgorithmSelector->algorithm();
|
||||
else
|
||||
return doc::RgbMapAlgorithm::DEFAULT;
|
||||
}
|
||||
|
||||
gen::ToGrayAlgorithm toGray() const {
|
||||
static_assert(
|
||||
int(gen::ToGrayAlgorithm::LUMA) == 0 &&
|
||||
@ -280,20 +318,25 @@ public:
|
||||
return flatten()->isSelected();
|
||||
}
|
||||
|
||||
// Save the dithering method used for the future
|
||||
void saveDitheringOptions() {
|
||||
void saveOptions() {
|
||||
auto& pref = Preferences::instance();
|
||||
|
||||
// Save the dithering method used for the future
|
||||
if (m_ditheringSelector) {
|
||||
if (auto item = m_ditheringSelector->getSelectedItem()) {
|
||||
Preferences::instance().quantization.ditheringAlgorithm(
|
||||
pref.quantization.ditheringAlgorithm(
|
||||
item->text());
|
||||
|
||||
if (m_ditheringSelector->ditheringAlgorithm() ==
|
||||
render::DitheringAlgorithm::ErrorDiffusion) {
|
||||
Preferences::instance().quantization.ditheringFactor(
|
||||
pref.quantization.ditheringFactor(
|
||||
factor()->getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_mapAlgorithmSelector)
|
||||
pref.quantization.advanced(advancedCheck()->isSelected());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -368,6 +411,7 @@ private:
|
||||
m_editor->frame(),
|
||||
dstPixelFormat,
|
||||
dithering(),
|
||||
rgbMapAlgorithm(),
|
||||
toGray(),
|
||||
visibleBounds.origin(),
|
||||
Preferences::instance().experimental.newBlend()));
|
||||
@ -375,7 +419,7 @@ private:
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
void onDithering() {
|
||||
void onIndexParamChange() {
|
||||
stop();
|
||||
m_selectedItem = nullptr;
|
||||
onChangeColorMode();
|
||||
@ -421,6 +465,7 @@ private:
|
||||
std::unique_ptr<ConvertThread> m_bgThread;
|
||||
ConversionItem* m_selectedItem;
|
||||
DitheringSelector* m_ditheringSelector;
|
||||
RgbMapAlgorithmSelector* m_mapAlgorithmSelector;
|
||||
bool m_imageJustCreated;
|
||||
};
|
||||
|
||||
@ -441,6 +486,7 @@ private:
|
||||
bool m_useUI;
|
||||
doc::PixelFormat m_format;
|
||||
render::Dithering m_dithering;
|
||||
doc::RgbMapAlgorithm m_rgbmap;
|
||||
gen::ToGrayAlgorithm m_toGray;
|
||||
};
|
||||
|
||||
@ -450,6 +496,7 @@ ChangePixelFormatCommand::ChangePixelFormatCommand()
|
||||
m_useUI = true;
|
||||
m_format = IMAGE_RGB;
|
||||
m_dithering = render::Dithering();
|
||||
m_rgbmap = doc::RgbMapAlgorithm::DEFAULT;
|
||||
m_toGray = gen::ToGrayAlgorithm::DEFAULT;
|
||||
}
|
||||
|
||||
@ -497,6 +544,15 @@ void ChangePixelFormatCommand::onLoadParams(const Params& params)
|
||||
m_dithering.matrix(render::BayerMatrix(8));
|
||||
}
|
||||
|
||||
// TODO change this with NewParams as in ColorQuantizationParams
|
||||
std::string rgbmap = params.get("rgbmap");
|
||||
if (rgbmap == "octree")
|
||||
m_rgbmap = doc::RgbMapAlgorithm::OCTREE;
|
||||
else if (rgbmap == "rgb5a3")
|
||||
m_rgbmap = doc::RgbMapAlgorithm::RGB5A3;
|
||||
else
|
||||
m_rgbmap = doc::RgbMapAlgorithm::DEFAULT;
|
||||
|
||||
std::string toGray = params.get("toGray");
|
||||
if (toGray == "luma")
|
||||
m_toGray = gen::ToGrayAlgorithm::LUMA;
|
||||
@ -570,10 +626,11 @@ void ChangePixelFormatCommand::onExecute(Context* context)
|
||||
|
||||
m_format = window.pixelFormat();
|
||||
m_dithering = window.dithering();
|
||||
m_rgbmap = window.rgbMapAlgorithm();
|
||||
m_toGray = window.toGray();
|
||||
flatten = window.flattenEnabled();
|
||||
|
||||
window.saveDitheringOptions();
|
||||
window.saveOptions();
|
||||
}
|
||||
#endif // ENABLE_UI
|
||||
|
||||
@ -607,6 +664,7 @@ void ChangePixelFormatCommand::onExecute(Context* context)
|
||||
new cmd::SetPixelFormat(
|
||||
sprite, m_format,
|
||||
m_dithering,
|
||||
m_rgbmap,
|
||||
get_gray_func(m_toGray),
|
||||
&job)); // SpriteJob is a render::TaskDelegate
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -20,10 +20,12 @@
|
||||
#include "app/sprite_job.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/color_bar.h"
|
||||
#include "app/ui/rgbmap_algorithm_selector.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "doc/palette.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "render/quantization.h"
|
||||
#include "ui/manager.h"
|
||||
|
||||
#include "palette_from_sprite.xml.h"
|
||||
|
||||
@ -36,8 +38,53 @@ struct ColorQuantizationParams : public NewParams {
|
||||
Param<bool> withAlpha { this, true, "withAlpha" };
|
||||
Param<int> maxColors { this, 256, "maxColors" };
|
||||
Param<bool> useRange { this, false, "useRange" };
|
||||
Param<RgbMapAlgorithm> algorithm { this, RgbMapAlgorithm::DEFAULT, "algorithm" };
|
||||
};
|
||||
|
||||
#if ENABLE_UI
|
||||
|
||||
class PaletteFromSpriteWindow : public app::gen::PaletteFromSprite {
|
||||
public:
|
||||
PaletteFromSpriteWindow() {
|
||||
rgbmapAlgorithmPlaceholder()->addChild(&m_algoSelector);
|
||||
|
||||
advancedCheck()->Click.connect(
|
||||
[this](ui::Event&){
|
||||
advanced()->setVisible(advancedCheck()->isSelected());
|
||||
|
||||
const gfx::Rect origBounds = bounds();
|
||||
setBounds(gfx::Rect(bounds().origin(), sizeHint()));
|
||||
manager()->invalidateRect(origBounds);
|
||||
});
|
||||
|
||||
m_algoSelector.Change.connect(
|
||||
[this](){
|
||||
switch (algorithm()) {
|
||||
case RgbMapAlgorithm::RGB5A3:
|
||||
alphaChannel()->setEnabled(true);
|
||||
break;
|
||||
case RgbMapAlgorithm::OCTREE:
|
||||
alphaChannel()->setSelected(false);
|
||||
alphaChannel()->setEnabled(false);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
doc::RgbMapAlgorithm algorithm() {
|
||||
return m_algoSelector.algorithm();
|
||||
}
|
||||
|
||||
void algorithm(const doc::RgbMapAlgorithm mapAlgo) {
|
||||
m_algoSelector.algorithm(mapAlgo);
|
||||
}
|
||||
|
||||
private:
|
||||
RgbMapAlgorithmSelector m_algoSelector;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class ColorQuantizationCommand : public CommandWithNewParams<ColorQuantizationParams> {
|
||||
public:
|
||||
ColorQuantizationCommand();
|
||||
@ -65,8 +112,10 @@ void ColorQuantizationCommand::onExecute(Context* ctx)
|
||||
const bool ui = (params().ui() && ctx->isUIAvailable());
|
||||
#endif
|
||||
|
||||
auto& pref = Preferences::instance();
|
||||
bool withAlpha = params().withAlpha();
|
||||
int maxColors = params().maxColors();
|
||||
RgbMapAlgorithm algorithm = params().algorithm();
|
||||
bool createPal;
|
||||
|
||||
Site site = ctx->activeSite();
|
||||
@ -74,16 +123,22 @@ void ColorQuantizationCommand::onExecute(Context* ctx)
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
if (ui) {
|
||||
app::gen::PaletteFromSprite window;
|
||||
PaletteFromSpriteWindow window;
|
||||
{
|
||||
ContextReader reader(ctx);
|
||||
const Palette* curPalette = site.sprite()->palette(site.frame());
|
||||
|
||||
if (!params().algorithm.isSet())
|
||||
algorithm = pref.experimental.rgbmapAlgorithm();
|
||||
if (!params().withAlpha.isSet())
|
||||
withAlpha = App::instance()->preferences().quantization.withAlpha();
|
||||
withAlpha = pref.quantization.withAlpha();
|
||||
|
||||
const bool advanced = pref.quantization.advanced();
|
||||
window.advancedCheck()->setSelected(advanced);
|
||||
window.advanced()->setVisible(advanced);
|
||||
|
||||
window.algorithm(algorithm);
|
||||
window.newPalette()->setSelected(true);
|
||||
window.alphaChannel()->setSelected(withAlpha);
|
||||
window.ncolors()->setTextf("%d", maxColors);
|
||||
|
||||
if (entries.picks() > 1) {
|
||||
@ -107,7 +162,10 @@ void ColorQuantizationCommand::onExecute(Context* ctx)
|
||||
|
||||
maxColors = window.ncolors()->textInt();
|
||||
withAlpha = window.alphaChannel()->isSelected();
|
||||
App::instance()->preferences().quantization.withAlpha(withAlpha);
|
||||
algorithm = window.algorithm();
|
||||
|
||||
pref.quantization.withAlpha(withAlpha);
|
||||
pref.quantization.advanced(window.advancedCheck()->isSelected());
|
||||
|
||||
if (window.newPalette()->isSelected()) {
|
||||
createPal = true;
|
||||
@ -139,14 +197,15 @@ void ColorQuantizationCommand::onExecute(Context* ctx)
|
||||
Palette tmpPalette(frame, entries.picks());
|
||||
|
||||
SpriteJob job(reader, "Color Quantization");
|
||||
const bool newBlend = Preferences::instance().experimental.newBlend();
|
||||
const bool newBlend = pref.experimental.newBlend();
|
||||
job.startJobWithCallback(
|
||||
[sprite, withAlpha, &tmpPalette, &job, newBlend]{
|
||||
[sprite, withAlpha, &tmpPalette, &job, newBlend, algorithm]{
|
||||
render::create_palette_from_sprite(
|
||||
sprite, 0, sprite->lastFrame(),
|
||||
withAlpha, &tmpPalette,
|
||||
&job,
|
||||
newBlend); // SpriteJob is a render::TaskDelegate
|
||||
&job, // SpriteJob is a render::TaskDelegate
|
||||
newBlend,
|
||||
algorithm);
|
||||
});
|
||||
job.waitJob();
|
||||
if (job.isCanceled())
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -32,7 +32,6 @@
|
||||
#include "app/ui/optional_alert.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/timeline/timeline.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/clamp.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/fs.h"
|
||||
@ -318,11 +317,11 @@ public:
|
||||
, m_executionID(0)
|
||||
, m_filenameFormat(params.filenameFormat())
|
||||
{
|
||||
sectionTabs()->ItemChange.connect(base::Bind<void>(&ExportSpriteSheetWindow::onChangeSection, this));
|
||||
expandSections()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onExpandSections, this));
|
||||
closeSpriteSection()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onCloseSection, this, kSectionSprite));
|
||||
closeBordersSection()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onCloseSection, this, kSectionBorders));
|
||||
closeOutputSection()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onCloseSection, this, kSectionOutput));
|
||||
sectionTabs()->ItemChange.connect([this]{ onChangeSection(); });
|
||||
expandSections()->Click.connect([this]{ onExpandSections(); });
|
||||
closeSpriteSection()->Click.connect([this]{ onCloseSection(kSectionSprite); });
|
||||
closeBordersSection()->Click.connect([this]{ onCloseSection(kSectionBorders); });
|
||||
closeOutputSection()->Click.connect([this]{ onCloseSection(kSectionOutput); });
|
||||
|
||||
static_assert(
|
||||
(int)app::SpriteSheetType::None == 0 &&
|
||||
@ -430,32 +429,32 @@ public:
|
||||
m_dataFilename == kSpecifiedFilename)
|
||||
m_dataFilename = base + ".json";
|
||||
|
||||
exportButton()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onExport, this));
|
||||
sheetType()->Change.connect(&ExportSpriteSheetWindow::onSheetTypeChange, this);
|
||||
constraintType()->Change.connect(&ExportSpriteSheetWindow::onConstraintTypeChange, this);
|
||||
widthConstraint()->Change.connect(&ExportSpriteSheetWindow::generatePreview, this);
|
||||
heightConstraint()->Change.connect(&ExportSpriteSheetWindow::generatePreview, this);
|
||||
borderPadding()->Change.connect(base::Bind<void>(&ExportSpriteSheetWindow::generatePreview, this));
|
||||
shapePadding()->Change.connect(base::Bind<void>(&ExportSpriteSheetWindow::generatePreview, this));
|
||||
innerPadding()->Change.connect(base::Bind<void>(&ExportSpriteSheetWindow::generatePreview, this));
|
||||
extrudeEnabled()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::generatePreview, this));
|
||||
mergeDups()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::generatePreview, this));
|
||||
ignoreEmpty()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::generatePreview, this));
|
||||
imageEnabled()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onImageEnabledChange, this));
|
||||
imageFilename()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onImageFilename, this));
|
||||
dataEnabled()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onDataEnabledChange, this));
|
||||
dataFilename()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onDataFilename, this));
|
||||
trimSpriteEnabled()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onTrimEnabledChange, this));
|
||||
trimEnabled()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onTrimEnabledChange, this));
|
||||
gridTrimEnabled()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::generatePreview, this));
|
||||
layers()->Change.connect(base::Bind<void>(&ExportSpriteSheetWindow::generatePreview, this));
|
||||
splitLayers()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onSplitLayersOrFrames, this));
|
||||
splitTags()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onSplitLayersOrFrames, this));
|
||||
frames()->Change.connect(base::Bind<void>(&ExportSpriteSheetWindow::generatePreview, this));
|
||||
dataFilenameFormat()->Change.connect(base::Bind<void>(&ExportSpriteSheetWindow::onDataFilenameFormatChange, this));
|
||||
openGenerated()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::onOpenGeneratedChange, this));
|
||||
preview()->Click.connect(base::Bind<void>(&ExportSpriteSheetWindow::generatePreview, this));
|
||||
m_genTimer.Tick.connect(base::Bind<void>(&ExportSpriteSheetWindow::onGenTimerTick, this));
|
||||
exportButton()->Click.connect([this]{ onExport(); });
|
||||
sheetType()->Change.connect([this]{ onSheetTypeChange(); });
|
||||
constraintType()->Change.connect([this]{ onConstraintTypeChange(); });
|
||||
widthConstraint()->Change.connect([this]{ generatePreview(); });
|
||||
heightConstraint()->Change.connect([this]{ generatePreview(); });
|
||||
borderPadding()->Change.connect([this]{ generatePreview(); });
|
||||
shapePadding()->Change.connect([this]{ generatePreview(); });
|
||||
innerPadding()->Change.connect([this]{ generatePreview(); });
|
||||
extrudeEnabled()->Click.connect([this]{ generatePreview(); });
|
||||
mergeDups()->Click.connect([this]{ generatePreview(); });
|
||||
ignoreEmpty()->Click.connect([this]{ generatePreview(); });
|
||||
imageEnabled()->Click.connect([this]{ onImageEnabledChange(); });
|
||||
imageFilename()->Click.connect([this]{ onImageFilename(); });
|
||||
dataEnabled()->Click.connect([this]{ onDataEnabledChange(); });
|
||||
dataFilename()->Click.connect([this]{ onDataFilename(); });
|
||||
trimSpriteEnabled()->Click.connect([this]{ onTrimEnabledChange(); });
|
||||
trimEnabled()->Click.connect([this]{ onTrimEnabledChange(); });
|
||||
gridTrimEnabled()->Click.connect([this]{ generatePreview(); });
|
||||
layers()->Change.connect([this]{ generatePreview(); });
|
||||
splitLayers()->Click.connect([this]{ onSplitLayersOrFrames(); });
|
||||
splitTags()->Click.connect([this]{ onSplitLayersOrFrames(); });
|
||||
frames()->Change.connect([this]{ generatePreview(); });
|
||||
dataFilenameFormat()->Change.connect([this]{ onDataFilenameFormatChange(); });
|
||||
openGenerated()->Click.connect([this]{ onOpenGeneratedChange(); });
|
||||
preview()->Click.connect([this]{ generatePreview(); });
|
||||
m_genTimer.Tick.connect([this]{ onGenTimerTick(); });
|
||||
|
||||
// Select tabs
|
||||
{
|
||||
|
60
src/app/commands/cmd_fullscreen_mode.cpp
Normal file
60
src/app/commands/cmd_fullscreen_mode.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/context.h"
|
||||
#include "os/display.h"
|
||||
#include "os/system.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
class FullscreenModeCommand : public Command {
|
||||
public:
|
||||
FullscreenModeCommand();
|
||||
|
||||
protected:
|
||||
void onExecute(Context* context) override;
|
||||
};
|
||||
|
||||
FullscreenModeCommand::FullscreenModeCommand()
|
||||
: Command(CommandId::FullscreenMode(), CmdUIOnlyFlag)
|
||||
{
|
||||
}
|
||||
|
||||
// Shows the sprite using the complete screen.
|
||||
void FullscreenModeCommand::onExecute(Context* ctx)
|
||||
{
|
||||
if (!ctx->isUIAvailable())
|
||||
return;
|
||||
|
||||
ui::Manager* manager = ui::Manager::getDefault();
|
||||
ASSERT(manager);
|
||||
if (!manager)
|
||||
return;
|
||||
|
||||
os::Display* display = manager->getDisplay();
|
||||
ASSERT(display);
|
||||
if (!display)
|
||||
return;
|
||||
|
||||
display->setFullscreen(
|
||||
!display->isFullscreen());
|
||||
}
|
||||
|
||||
Command* CommandFactory::createFullscreenModeCommand()
|
||||
{
|
||||
return new FullscreenModeCommand;
|
||||
}
|
||||
|
||||
} // namespace app
|
@ -26,7 +26,6 @@
|
||||
#include "doc/palette.h"
|
||||
#include "doc/primitives.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "os/scoped_handle.h"
|
||||
#include "os/surface.h"
|
||||
#include "os/system.h"
|
||||
|
||||
@ -53,7 +52,7 @@ public:
|
||||
, m_proj(editor->projection())
|
||||
, m_index_bg_color(-1)
|
||||
, m_doublebuf(Image::create(IMAGE_RGB, ui::display_w(), ui::display_h()))
|
||||
, m_doublesur(os::instance()->createRgbaSurface(ui::display_w(), ui::display_h())) {
|
||||
, m_doublesur(os::instance()->makeRgbaSurface(ui::display_w(), ui::display_h())) {
|
||||
// Do not use DocWriter (do not lock the document) because we
|
||||
// will call other sub-commands (e.g. previous frame, next frame,
|
||||
// etc.).
|
||||
@ -232,8 +231,8 @@ protected:
|
||||
}
|
||||
|
||||
convert_image_to_surface(m_doublebuf.get(), m_pal,
|
||||
m_doublesur, 0, 0, 0, 0, m_doublebuf->width(), m_doublebuf->height());
|
||||
g->blit(m_doublesur, 0, 0, 0, 0, m_doublesur->width(), m_doublesur->height());
|
||||
m_doublesur.get(), 0, 0, 0, 0, m_doublebuf->width(), m_doublebuf->height());
|
||||
g->blit(m_doublesur.get(), 0, 0, 0, 0, m_doublesur->width(), m_doublesur->height());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -249,7 +248,7 @@ private:
|
||||
int m_index_bg_color;
|
||||
std::unique_ptr<Image> m_render;
|
||||
std::unique_ptr<Image> m_doublebuf;
|
||||
os::ScopedHandle<os::Surface> m_doublesur;
|
||||
os::SurfaceRef m_doublesur;
|
||||
filters::TiledMode m_tiled;
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -29,7 +29,6 @@
|
||||
#include "app/ui/editor/select_box_state.h"
|
||||
#include "app/ui/editor/standby_state.h"
|
||||
#include "app/ui/workspace.h"
|
||||
#include "base/bind.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/layer.h"
|
||||
@ -69,16 +68,16 @@ public:
|
||||
sheetType()->addItem("By Columns");
|
||||
sheetType()->setSelectedItemIndex((int)app::SpriteSheetType::Rows-1);
|
||||
|
||||
sheetType()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onSheetTypeChange, this));
|
||||
x()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
|
||||
y()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
|
||||
width()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
|
||||
height()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
|
||||
paddingEnabled()->Click.connect(base::Bind<void>(&ImportSpriteSheetWindow::onPaddingEnabledChange, this));
|
||||
horizontalPadding()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
|
||||
verticalPadding()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
|
||||
partialTiles()->Click.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
|
||||
selectFile()->Click.connect(base::Bind<void>(&ImportSpriteSheetWindow::onSelectFile, this));
|
||||
sheetType()->Change.connect([this]{ onSheetTypeChange(); });
|
||||
x()->Change.connect([this]{ onEntriesChange(); });
|
||||
y()->Change.connect([this]{ onEntriesChange(); });
|
||||
width()->Change.connect([this]{ onEntriesChange(); });
|
||||
height()->Change.connect([this]{ onEntriesChange(); });
|
||||
paddingEnabled()->Click.connect([this]{ onPaddingEnabledChange(); });
|
||||
horizontalPadding()->Change.connect([this]{ onEntriesChange(); });
|
||||
verticalPadding()->Change.connect([this]{ onEntriesChange(); });
|
||||
partialTiles()->Click.connect([this]{ onEntriesChange(); });
|
||||
selectFile()->Click.connect([this]{ onSelectFile(); });
|
||||
|
||||
remapWindow();
|
||||
centerWindow();
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "app/ui/select_accelerator.h"
|
||||
#include "app/ui/separator_in_view.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/scoped_value.h"
|
||||
#include "base/split_string.h"
|
||||
@ -376,13 +375,13 @@ private:
|
||||
|
||||
m_changeConn = obs::connection();
|
||||
m_changeButton.reset(new Button(""));
|
||||
m_changeConn = m_changeButton->Click.connect(base::Bind<void>(&KeyItem::onChangeAccel, this, i));
|
||||
m_changeConn = m_changeButton->Click.connect([this, i]{ onChangeAccel(i); });
|
||||
m_changeButton->setStyle(SkinTheme::instance()->styles.miniButton());
|
||||
addChild(m_changeButton.get());
|
||||
|
||||
m_deleteConn = obs::connection();
|
||||
m_deleteButton.reset(new Button(""));
|
||||
m_deleteConn = m_deleteButton->Click.connect(base::Bind<void>(&KeyItem::onDeleteAccel, this, i));
|
||||
m_deleteConn = m_deleteButton->Click.connect([this, i]{ onDeleteAccel(i); });
|
||||
m_deleteButton->setStyle(SkinTheme::instance()->styles.miniButton());
|
||||
addChild(m_deleteButton.get());
|
||||
|
||||
@ -409,7 +408,7 @@ private:
|
||||
(!m_menuitem || m_menuitem->getCommand())) {
|
||||
m_addConn = obs::connection();
|
||||
m_addButton.reset(new Button(""));
|
||||
m_addConn = m_addButton->Click.connect(base::Bind<void>(&KeyItem::onAddAccel, this));
|
||||
m_addConn = m_addButton->Click.connect([this]{ onAddAccel(); });
|
||||
m_addButton->setStyle(SkinTheme::instance()->styles.miniButton());
|
||||
addChild(m_addButton.get());
|
||||
|
||||
@ -511,14 +510,14 @@ public:
|
||||
|
||||
onWheelBehaviorChange();
|
||||
|
||||
wheelBehavior()->ItemChange.connect(base::Bind<void>(&KeyboardShortcutsWindow::onWheelBehaviorChange, this));
|
||||
wheelZoom()->Click.connect(base::Bind<void>(&KeyboardShortcutsWindow::onWheelZoomChange, this));
|
||||
wheelBehavior()->ItemChange.connect([this]{ onWheelBehaviorChange(); });
|
||||
wheelZoom()->Click.connect([this]{ onWheelZoomChange(); });
|
||||
|
||||
search()->Change.connect(base::Bind<void>(&KeyboardShortcutsWindow::onSearchChange, this));
|
||||
section()->Change.connect(base::Bind<void>(&KeyboardShortcutsWindow::onSectionChange, this));
|
||||
importButton()->Click.connect(base::Bind<void>(&KeyboardShortcutsWindow::onImport, this));
|
||||
exportButton()->Click.connect(base::Bind<void>(&KeyboardShortcutsWindow::onExport, this));
|
||||
resetButton()->Click.connect(base::Bind<void>(&KeyboardShortcutsWindow::onReset, this));
|
||||
search()->Change.connect([this]{ onSearchChange(); });
|
||||
section()->Change.connect([this]{ onSectionChange(); });
|
||||
importButton()->Click.connect([this]{ onImport(); });
|
||||
exportButton()->Click.connect([this]{ onExport(); });
|
||||
resetButton()->Click.connect([this]{ onReset(); });
|
||||
|
||||
fillAllLists();
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -24,7 +25,6 @@
|
||||
#include "app/ui/timeline/timeline.h"
|
||||
#include "app/ui/user_data_popup.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/scoped_value.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/layer.h"
|
||||
@ -99,11 +99,11 @@ public:
|
||||
mode()->addItem(new BlendModeItem("Color", doc::BlendMode::HSL_COLOR));
|
||||
mode()->addItem(new BlendModeItem("Luminosity", doc::BlendMode::HSL_LUMINOSITY));
|
||||
|
||||
name()->Change.connect(base::Bind<void>(&LayerPropertiesWindow::onStartTimer, this));
|
||||
mode()->Change.connect(base::Bind<void>(&LayerPropertiesWindow::onStartTimer, this));
|
||||
opacity()->Change.connect(base::Bind<void>(&LayerPropertiesWindow::onStartTimer, this));
|
||||
m_timer.Tick.connect(base::Bind<void>(&LayerPropertiesWindow::onCommitChange, this));
|
||||
userData()->Click.connect(base::Bind<void>(&LayerPropertiesWindow::onPopupUserData, this));
|
||||
name()->Change.connect([this]{ onStartTimer(); });
|
||||
mode()->Change.connect([this]{ onStartTimer(); });
|
||||
opacity()->Change.connect([this]{ onStartTimer(); });
|
||||
m_timer.Tick.connect([this]{ onCommitChange(); });
|
||||
userData()->Click.connect([this]{ onPopupUserData(); });
|
||||
|
||||
remapWindow();
|
||||
centerWindow();
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "app/ui/color_bar.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/selection_mode_field.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/chrono.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/scoped_value.h"
|
||||
@ -136,13 +135,13 @@ void MaskByColorCommand::onExecute(Context* context)
|
||||
if (get_config_bool("MaskColor", "Preview", true))
|
||||
m_checkPreview->setSelected(true);
|
||||
|
||||
button_ok->Click.connect(base::Bind<void>(&Window::closeWindow, m_window, button_ok));
|
||||
button_cancel->Click.connect(base::Bind<void>(&Window::closeWindow, m_window, button_cancel));
|
||||
button_ok->Click.connect([this, button_ok]{ m_window->closeWindow(button_ok); });
|
||||
button_cancel->Click.connect([this, button_cancel]{ m_window->closeWindow(button_cancel); });
|
||||
|
||||
m_buttonColor->Change.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader)));
|
||||
m_sliderTolerance->Change.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader)));
|
||||
m_checkPreview->Click.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader)));
|
||||
m_selMode->ModeChange.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader)));
|
||||
m_buttonColor->Change.connect([&]{ maskPreview(reader); });
|
||||
m_sliderTolerance->Change.connect([&]{ maskPreview(reader); });
|
||||
m_checkPreview->Click.connect([&]{ maskPreview(reader); });
|
||||
m_selMode->ModeChange.connect([&]{ maskPreview(reader); });
|
||||
|
||||
button_ok->setFocusMagnet(true);
|
||||
m_buttonColor->setExpansive(true);
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "app/util/clipboard.h"
|
||||
#include "app/util/clipboard.h"
|
||||
#include "app/util/pixel_ratio.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/clamp.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/image.h"
|
||||
@ -155,16 +154,15 @@ void NewFileCommand::onExecute(Context* ctx)
|
||||
bool advanced = pref.newFile.advanced();
|
||||
window.advancedCheck()->setSelected(advanced);
|
||||
window.advancedCheck()->Click.connect(
|
||||
base::Bind<void>(
|
||||
[&]{
|
||||
gfx::Rect bounds = window.bounds();
|
||||
window.advanced()->setVisible(window.advancedCheck()->isSelected());
|
||||
window.setBounds(gfx::Rect(window.bounds().origin(),
|
||||
window.sizeHint()));
|
||||
window.layout();
|
||||
[&]{
|
||||
gfx::Rect bounds = window.bounds();
|
||||
window.advanced()->setVisible(window.advancedCheck()->isSelected());
|
||||
window.setBounds(gfx::Rect(window.bounds().origin(),
|
||||
window.sizeHint()));
|
||||
window.layout();
|
||||
|
||||
window.manager()->invalidateRect(bounds);
|
||||
}));
|
||||
window.manager()->invalidateRect(bounds);
|
||||
});
|
||||
window.advanced()->setVisible(advanced);
|
||||
if (advanced)
|
||||
window.pixelRatio()->setValue(pref.newFile.pixelRatio());
|
||||
@ -275,7 +273,8 @@ void NewFileCommand::onExecute(Context* ctx)
|
||||
if (clipboardPalette.isBlack()) {
|
||||
render::create_palette_from_sprite(
|
||||
sprite.get(), 0, sprite->lastFrame(), true,
|
||||
&clipboardPalette, nullptr, true);
|
||||
&clipboardPalette, nullptr, true,
|
||||
Preferences::instance().experimental.rgbmapAlgorithm());
|
||||
}
|
||||
sprite->setPalette(&clipboardPalette, false);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -25,7 +25,6 @@
|
||||
#include "app/recent_files.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/thread.h"
|
||||
#include "doc/sprite.h"
|
||||
|
@ -28,9 +28,9 @@
|
||||
#include "app/tx.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/pref_widget.h"
|
||||
#include "app/ui/rgbmap_algorithm_selector.h"
|
||||
#include "app/ui/separator_in_view.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/clamp.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/fs.h"
|
||||
@ -99,13 +99,13 @@ class OptionsWindow : public app::gen::Options {
|
||||
|
||||
class ColorSpaceItem : public ListItem {
|
||||
public:
|
||||
ColorSpaceItem(const os::ColorSpacePtr& cs)
|
||||
ColorSpaceItem(const os::ColorSpaceRef& cs)
|
||||
: ListItem(cs->gfxColorSpace()->name()),
|
||||
m_cs(cs) {
|
||||
}
|
||||
os::ColorSpacePtr cs() const { return m_cs; }
|
||||
os::ColorSpaceRef cs() const { return m_cs; }
|
||||
private:
|
||||
os::ColorSpacePtr m_cs;
|
||||
os::ColorSpaceRef m_cs;
|
||||
};
|
||||
|
||||
class ThemeItem : public ListItem {
|
||||
@ -202,7 +202,7 @@ public:
|
||||
, m_restoreScreenScaling(m_pref.general.screenScale())
|
||||
, m_restoreUIScaling(m_pref.general.uiScale())
|
||||
{
|
||||
sectionListbox()->Change.connect(base::Bind<void>(&OptionsWindow::onChangeSection, this));
|
||||
sectionListbox()->Change.connect([this]{ onChangeSection(); });
|
||||
|
||||
// Default extension to save files
|
||||
fillExtensionsCombobox(defaultExtension(), m_pref.saveFile.defaultExtension());
|
||||
@ -212,15 +212,15 @@ public:
|
||||
|
||||
// Number of recent items
|
||||
recentFiles()->setValue(m_pref.general.recentItems());
|
||||
clearRecentFiles()->Click.connect(base::Bind<void>(&OptionsWindow::onClearRecentFiles, this));
|
||||
clearRecentFiles()->Click.connect([this]{ onClearRecentFiles(); });
|
||||
|
||||
// Template item for active display color profiles
|
||||
m_templateTextForDisplayCS = windowCs()->getItem(2)->text();
|
||||
windowCs()->deleteItem(2);
|
||||
|
||||
// Color profiles
|
||||
resetColorManagement()->Click.connect(base::Bind<void>(&OptionsWindow::onResetColorManagement, this));
|
||||
colorManagement()->Click.connect(base::Bind<void>(&OptionsWindow::onColorManagement, this));
|
||||
resetColorManagement()->Click.connect([this]{ onResetColorManagement(); });
|
||||
colorManagement()->Click.connect([this]{ onColorManagement(); });
|
||||
{
|
||||
os::instance()->listColorSpaces(m_colorSpaces);
|
||||
for (auto& cs : m_colorSpaces) {
|
||||
@ -236,7 +236,7 @@ public:
|
||||
}
|
||||
|
||||
// Alerts
|
||||
resetAlerts()->Click.connect(base::Bind<void>(&OptionsWindow::onResetAlerts, this));
|
||||
resetAlerts()->Click.connect([this]{ onResetAlerts(); });
|
||||
|
||||
// Cursor
|
||||
paintingCursorType()->setSelectedItemIndex(int(m_pref.cursor.paintingCursorType()));
|
||||
@ -250,7 +250,7 @@ public:
|
||||
cursorColorType()->setSelectedItemIndex(1);
|
||||
cursorColor()->setVisible(true);
|
||||
}
|
||||
cursorColorType()->Change.connect(base::Bind<void>(&OptionsWindow::onCursorColorType, this));
|
||||
cursorColorType()->Change.connect([this]{ onCursorColorType(); });
|
||||
|
||||
// Brush preview
|
||||
brushPreview()->setSelectedItemIndex(
|
||||
@ -334,7 +334,7 @@ public:
|
||||
int(os::Capabilities::CustomNativeMouseCursor)) != 0) {
|
||||
if (m_pref.cursor.useNativeCursor())
|
||||
nativeCursor()->setSelected(true);
|
||||
nativeCursor()->Click.connect(base::Bind<void>(&OptionsWindow::onNativeCursorChange, this));
|
||||
nativeCursor()->Click.connect([this]{ onNativeCursorChange(); });
|
||||
|
||||
cursorScale()->setSelectedItemIndex(
|
||||
cursorScale()->findItemIndexByValue(
|
||||
@ -400,6 +400,10 @@ public:
|
||||
|
||||
nonactiveLayersOpacity()->setValue(m_pref.experimental.nonactiveLayersOpacity());
|
||||
|
||||
rgbmapAlgorithmPlaceholder()->addChild(&m_rgbmapAlgorithmSelector);
|
||||
m_rgbmapAlgorithmSelector.setExpansive(true);
|
||||
m_rgbmapAlgorithmSelector.algorithm(m_pref.experimental.rgbmapAlgorithm());
|
||||
|
||||
if (m_pref.editor.showScrollbars())
|
||||
showScrollbars()->setSelected(true);
|
||||
|
||||
@ -418,11 +422,11 @@ public:
|
||||
if (context->activeDocument()) {
|
||||
bgScope()->addItem("Background for the Active Document");
|
||||
bgScope()->setSelectedItemIndex(1);
|
||||
bgScope()->Change.connect(base::Bind<void>(&OptionsWindow::onChangeBgScope, this));
|
||||
bgScope()->Change.connect([this]{ onChangeBgScope(); });
|
||||
|
||||
gridScope()->addItem("Grid for the Active Document");
|
||||
gridScope()->setSelectedItemIndex(1);
|
||||
gridScope()->Change.connect(base::Bind<void>(&OptionsWindow::onChangeGridScope, this));
|
||||
gridScope()->Change.connect([this]{ onChangeGridScope(); });
|
||||
}
|
||||
|
||||
selectScalingItems();
|
||||
@ -477,21 +481,21 @@ public:
|
||||
checkedBgSize()->addItem("2x2");
|
||||
checkedBgSize()->addItem("1x1");
|
||||
checkedBgSize()->addItem("Custom");
|
||||
checkedBgSize()->Change.connect(base::Bind<void>(&OptionsWindow::onCheckedBgSizeChange, this));
|
||||
checkedBgSize()->Change.connect([this]{ onCheckedBgSizeChange(); });
|
||||
|
||||
// Reset buttons
|
||||
resetBg()->Click.connect(base::Bind<void>(&OptionsWindow::onResetBg, this));
|
||||
resetGrid()->Click.connect(base::Bind<void>(&OptionsWindow::onResetGrid, this));
|
||||
resetBg()->Click.connect([this]{ onResetBg(); });
|
||||
resetGrid()->Click.connect([this]{ onResetGrid(); });
|
||||
|
||||
// Links
|
||||
locateFile()->Click.connect(base::Bind<void>(&OptionsWindow::onLocateConfigFile, this));
|
||||
locateFile()->Click.connect([this]{ onLocateConfigFile(); });
|
||||
if (!App::instance()->memoryDumpFilename().empty())
|
||||
locateCrashFolder()->Click.connect(base::Bind<void>(&OptionsWindow::onLocateCrashFolder, this));
|
||||
locateCrashFolder()->Click.connect([this]{ onLocateCrashFolder(); });
|
||||
else
|
||||
locateCrashFolder()->setVisible(false);
|
||||
|
||||
// Undo preferences
|
||||
limitUndo()->Click.connect(base::Bind<void>(&OptionsWindow::onLimitUndoCheck, this));
|
||||
limitUndo()->Click.connect([this]{ onLimitUndoCheck(); });
|
||||
limitUndo()->setSelected(m_pref.undo.sizeLimit() != 0);
|
||||
onLimitUndoCheck();
|
||||
|
||||
@ -499,20 +503,20 @@ public:
|
||||
undoAllowNonlinearHistory()->setSelected(m_pref.undo.allowNonlinearHistory());
|
||||
|
||||
// Theme buttons
|
||||
themeList()->Change.connect(base::Bind<void>(&OptionsWindow::onThemeChange, this));
|
||||
themeList()->DoubleClickItem.connect(base::Bind<void>(&OptionsWindow::onSelectTheme, this));
|
||||
selectTheme()->Click.connect(base::Bind<void>(&OptionsWindow::onSelectTheme, this));
|
||||
openThemeFolder()->Click.connect(base::Bind<void>(&OptionsWindow::onOpenThemeFolder, this));
|
||||
themeList()->Change.connect([this]{ onThemeChange(); });
|
||||
themeList()->DoubleClickItem.connect([this]{ onSelectTheme(); });
|
||||
selectTheme()->Click.connect([this]{ onSelectTheme(); });
|
||||
openThemeFolder()->Click.connect([this]{ onOpenThemeFolder(); });
|
||||
|
||||
// Extensions buttons
|
||||
extensionsList()->Change.connect(base::Bind<void>(&OptionsWindow::onExtensionChange, this));
|
||||
addExtension()->Click.connect(base::Bind<void>(&OptionsWindow::onAddExtension, this));
|
||||
disableExtension()->Click.connect(base::Bind<void>(&OptionsWindow::onDisableExtension, this));
|
||||
uninstallExtension()->Click.connect(base::Bind<void>(&OptionsWindow::onUninstallExtension, this));
|
||||
openExtensionFolder()->Click.connect(base::Bind<void>(&OptionsWindow::onOpenExtensionFolder, this));
|
||||
extensionsList()->Change.connect([this]{ onExtensionChange(); });
|
||||
addExtension()->Click.connect([this]{ onAddExtension(); });
|
||||
disableExtension()->Click.connect([this]{ onDisableExtension(); });
|
||||
uninstallExtension()->Click.connect([this]{ onUninstallExtension(); });
|
||||
openExtensionFolder()->Click.connect([this]{ onOpenExtensionFolder(); });
|
||||
|
||||
// Apply button
|
||||
buttonApply()->Click.connect(base::Bind<void>(&OptionsWindow::onApply, this));
|
||||
buttonApply()->Click.connect([this]{ onApply(); });
|
||||
|
||||
onChangeBgScope();
|
||||
onChangeGridScope();
|
||||
@ -521,12 +525,12 @@ public:
|
||||
// Refill languages combobox when extensions are enabled/disabled
|
||||
m_extLanguagesChanges =
|
||||
App::instance()->extensions().LanguagesChange.connect(
|
||||
base::Bind<void>(&OptionsWindow::refillLanguages, this));
|
||||
[this]{ refillLanguages(); });
|
||||
|
||||
// Reload themes when extensions are enabled/disabled
|
||||
m_extThemesChanges =
|
||||
App::instance()->extensions().ThemesChange.connect(
|
||||
base::Bind<void>(&OptionsWindow::reloadThemes, this));
|
||||
[this]{ reloadThemes(); });
|
||||
}
|
||||
|
||||
bool ok() {
|
||||
@ -695,6 +699,7 @@ public:
|
||||
m_pref.experimental.useNativeFileDialog(nativeFileDialog()->isSelected());
|
||||
m_pref.experimental.flashLayer(flashLayer()->isSelected());
|
||||
m_pref.experimental.nonactiveLayersOpacity(nonactiveLayersOpacity()->getValue());
|
||||
m_pref.experimental.rgbmapAlgorithm(m_rgbmapAlgorithmSelector.algorithm());
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
@ -1604,8 +1609,9 @@ private:
|
||||
std::string m_restoreThisTheme;
|
||||
int m_restoreScreenScaling;
|
||||
int m_restoreUIScaling;
|
||||
std::vector<os::ColorSpacePtr> m_colorSpaces;
|
||||
std::vector<os::ColorSpaceRef> m_colorSpaces;
|
||||
std::string m_templateTextForDisplayCS;
|
||||
RgbMapAlgorithmSelector m_rgbmapAlgorithmSelector;
|
||||
};
|
||||
|
||||
class OptionsCommand : public Command {
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "app/ui/font_popup.h"
|
||||
#include "app/ui/timeline/timeline.h"
|
||||
#include "app/util/freetype_utils.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/clamp.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/string.h"
|
||||
@ -69,8 +68,8 @@ public:
|
||||
updateFontFaceButton();
|
||||
|
||||
fontSize()->setTextf("%d", size);
|
||||
fontFace()->Click.connect(base::Bind<void>(&PasteTextWindow::onSelectFontFile, this));
|
||||
fontFace()->DropDownClick.connect(base::Bind<void>(&PasteTextWindow::onSelectSystemFont, this));
|
||||
fontFace()->Click.connect([this]{ onSelectFontFile(); });
|
||||
fontFace()->DropDownClick.connect([this]{ onSelectSystemFont(); });
|
||||
fontColor()->setColor(color);
|
||||
this->antialias()->setSelected(antialias);
|
||||
}
|
||||
@ -116,7 +115,7 @@ private:
|
||||
try {
|
||||
m_fontPopup.reset(new FontPopup());
|
||||
m_fontPopup->Load.connect(&PasteTextWindow::setFontFace, this);
|
||||
m_fontPopup->Close.connect(base::Bind<void>(&PasteTextWindow::onCloseFontPopup, this));
|
||||
m_fontPopup->Close.connect([this]{ onCloseFontPopup(); });
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
Console::showException(ex);
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include "app/ui/layer_frame_comboboxes.h"
|
||||
#include "app/ui/optional_alert.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/scoped_value.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -22,7 +22,6 @@
|
||||
#include "app/tx.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/util/pixel_ratio.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/mem_utils.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/palette.h"
|
||||
@ -64,7 +63,7 @@ void SpritePropertiesCommand::onExecute(Context* context)
|
||||
ColorButton* color_button = nullptr;
|
||||
|
||||
// List of available color profiles
|
||||
std::vector<os::ColorSpacePtr> colorSpaces;
|
||||
std::vector<os::ColorSpaceRef> colorSpaces;
|
||||
os::instance()->listColorSpaces(colorSpaces);
|
||||
|
||||
// Load the window widget
|
||||
@ -153,7 +152,7 @@ void SpritePropertiesCommand::onExecute(Context* context)
|
||||
++i;
|
||||
}
|
||||
if (selectedColorProfile < 0) {
|
||||
colorSpaces.push_back(os::instance()->createColorSpace(sprite->colorSpace()));
|
||||
colorSpaces.push_back(os::instance()->makeColorSpace(sprite->colorSpace()));
|
||||
selectedColorProfile = colorSpaces.size()-1;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "app/modules/palettes.h"
|
||||
#include "app/sprite_job.h"
|
||||
#include "app/util/resize_image.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/clamp.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "doc/algorithm/resize_image.h"
|
||||
@ -184,11 +183,11 @@ protected:
|
||||
class SpriteSizeWindow : public app::gen::SpriteSize {
|
||||
public:
|
||||
SpriteSizeWindow(Context* ctx, const SpriteSizeParams& params) : m_ctx(ctx) {
|
||||
lockRatio()->Click.connect(base::Bind<void>(&SpriteSizeWindow::onLockRatioClick, this));
|
||||
widthPx()->Change.connect(base::Bind<void>(&SpriteSizeWindow::onWidthPxChange, this));
|
||||
heightPx()->Change.connect(base::Bind<void>(&SpriteSizeWindow::onHeightPxChange, this));
|
||||
widthPerc()->Change.connect(base::Bind<void>(&SpriteSizeWindow::onWidthPercChange, this));
|
||||
heightPerc()->Change.connect(base::Bind<void>(&SpriteSizeWindow::onHeightPercChange, this));
|
||||
lockRatio()->Click.connect([this]{ onLockRatioClick(); });
|
||||
widthPx()->Change.connect([this]{ onWidthPxChange(); });
|
||||
heightPx()->Change.connect([this]{ onHeightPxChange(); });
|
||||
widthPerc()->Change.connect([this]{ onWidthPercChange(); });
|
||||
heightPerc()->Change.connect([this]{ onHeightPercChange(); });
|
||||
|
||||
widthPx()->setTextf("%d", params.width());
|
||||
heightPx()->setTextf("%d", params.height());
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2015-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -21,7 +22,6 @@
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/modules/palettes.h"
|
||||
#include "app/site.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/mem_utils.h"
|
||||
#include "ui/listitem.h"
|
||||
#include "ui/message.h"
|
||||
|
@ -72,6 +72,7 @@ FOR_EACH_COMMAND(Fill)
|
||||
FOR_EACH_COMMAND(FitScreen)
|
||||
FOR_EACH_COMMAND(FrameProperties)
|
||||
FOR_EACH_COMMAND(FrameTagProperties)
|
||||
FOR_EACH_COMMAND(FullscreenMode)
|
||||
FOR_EACH_COMMAND(FullscreenPreview)
|
||||
FOR_EACH_COMMAND(GotoFirstFrame)
|
||||
FOR_EACH_COMMAND(GotoFirstFrameInTag)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -21,7 +21,6 @@
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/color_sliders.h"
|
||||
#include "app/ui/slider2.h"
|
||||
#include "base/bind.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
@ -59,8 +58,8 @@ public:
|
||||
getContainer()->addChild(&m_brightness);
|
||||
getContainer()->addChild(new ui::Label("Contrast:"));
|
||||
getContainer()->addChild(&m_contrast);
|
||||
m_brightness.Change.connect(base::Bind<void>(&BrightnessContrastWindow::onChange, this));
|
||||
m_contrast.Change.connect(base::Bind<void>(&BrightnessContrastWindow::onChange, this));
|
||||
m_brightness.Change.connect([this]{ onChange(); });
|
||||
m_contrast.Change.connect([this]{ onChange(); });
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -23,7 +23,6 @@
|
||||
#include "app/ini_file.h"
|
||||
#include "app/load_widget.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "base/bind.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "filters/convolution_matrix.h"
|
||||
@ -58,7 +57,9 @@ static const char* ConfigSection = "ConvolutionMatrix";
|
||||
|
||||
class ConvolutionMatrixWindow : public FilterWindow {
|
||||
public:
|
||||
ConvolutionMatrixWindow(ConvolutionMatrixFilter& filter, FilterManagerImpl& filterMgr, ConvolutionMatrixStock& stock)
|
||||
ConvolutionMatrixWindow(ConvolutionMatrixFilter& filter,
|
||||
FilterManagerImpl& filterMgr,
|
||||
ConvolutionMatrixStock& stock)
|
||||
: FilterWindow("Convolution Matrix", ConfigSection, &filterMgr,
|
||||
WithChannelsSelector,
|
||||
WithTiledCheckBox,
|
||||
@ -72,14 +73,14 @@ public:
|
||||
{
|
||||
getContainer()->addChild(m_controlsWidget.get());
|
||||
|
||||
m_reloadButton->Click.connect(&ConvolutionMatrixWindow::onReloadStock, this);
|
||||
m_stockListBox->Change.connect(base::Bind<void>(&ConvolutionMatrixWindow::onMatrixChange, this));
|
||||
m_reloadButton->Click.connect([this]{ onReloadStock(); });
|
||||
m_stockListBox->Change.connect([this]{ onMatrixChange(); });
|
||||
|
||||
fillStockListBox();
|
||||
}
|
||||
|
||||
private:
|
||||
void onReloadStock(Event& ev) {
|
||||
void onReloadStock() {
|
||||
m_stock.reloadStock();
|
||||
fillStockListBox();
|
||||
}
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "app/ui/button_set.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/color_sliders.h"
|
||||
#include "base/bind.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
@ -75,11 +74,11 @@ public:
|
||||
m_colorType.addItem("HSV+")->setFocusStop(false);
|
||||
m_colorType.addItem("HSL+")->setFocusStop(false);
|
||||
m_colorType.setSelectedItem(int(mode));
|
||||
m_colorType.ItemChange.connect(base::Bind<void>(&HueSaturationWindow::onChangeMode, this));
|
||||
m_colorType.ItemChange.connect([this]{ onChangeMode(); });
|
||||
|
||||
m_sliders.setColorType(app::Color::HslType);
|
||||
m_sliders.setMode(ColorSliders::Mode::Relative);
|
||||
m_sliders.ColorChange.connect(base::Bind<void>(&HueSaturationWindow::onChangeControls, this));
|
||||
m_sliders.ColorChange.connect([this]{ onChangeControls(); });
|
||||
|
||||
onChangeMode();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -19,7 +19,6 @@
|
||||
#include "app/ini_file.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "base/bind.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -22,7 +22,6 @@
|
||||
#include "app/ui/color_bar.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "base/bind.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -30,7 +30,6 @@
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/bind.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -15,7 +15,6 @@
|
||||
#include "app/modules/gfx.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "base/bind.h"
|
||||
#include "doc/image.h"
|
||||
#include "ui/box.h"
|
||||
#include "ui/button.h"
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -17,7 +18,6 @@
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "base/bind.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
@ -73,7 +73,7 @@ FilterWindow::FilterWindow(const char* title, const char* cfgSection,
|
||||
|
||||
if (m_tiledCheck) {
|
||||
m_tiledCheck->setSelected(tiledMode != TiledMode::NONE);
|
||||
m_tiledCheck->Click.connect(base::Bind<void>(&FilterWindow::onTiledChange, this));
|
||||
m_tiledCheck->Click.connect([this]{ onTiledChange(); });
|
||||
|
||||
m_vbox.addChild(m_tiledCheck);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "base/string.h"
|
||||
#include "doc/algorithm/resize_image.h"
|
||||
#include "doc/color_mode.h"
|
||||
#include "doc/rgbmap_algorithm.h"
|
||||
#include "filters/color_curve.h"
|
||||
#include "filters/hue_saturation_filter.h"
|
||||
#include "filters/outline_filter.h"
|
||||
@ -192,6 +193,17 @@ void Param<tools::InkType>::fromString(const std::string& value)
|
||||
setValue(tools::string_id_to_ink_type(value));
|
||||
}
|
||||
|
||||
template<>
|
||||
void Param<doc::RgbMapAlgorithm>::fromString(const std::string& value)
|
||||
{
|
||||
if (base::utf8_icmp(value, "octree") == 0)
|
||||
setValue(doc::RgbMapAlgorithm::OCTREE);
|
||||
else if (base::utf8_icmp(value, "rgb5a3") == 0)
|
||||
setValue(doc::RgbMapAlgorithm::RGB5A3);
|
||||
else
|
||||
setValue(doc::RgbMapAlgorithm::DEFAULT);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Convert values from Lua
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -326,6 +338,15 @@ void Param<tools::InkType>::fromLua(lua_State* L, int index)
|
||||
script::get_value_from_lua<tools::InkType>(L, index);
|
||||
}
|
||||
|
||||
template<>
|
||||
void Param<doc::RgbMapAlgorithm>::fromLua(lua_State* L, int index)
|
||||
{
|
||||
if (lua_type(L, index) == LUA_TSTRING)
|
||||
fromString(lua_tostring(L, index));
|
||||
else
|
||||
setValue((doc::RgbMapAlgorithm)lua_tointeger(L, index));
|
||||
}
|
||||
|
||||
void CommandWithNewParamsBase::loadParamsFromLuaTable(lua_State* L, int index)
|
||||
{
|
||||
onResetValues();
|
||||
|
@ -70,7 +70,7 @@ void ScreenshotCommand::onExecute(Context* ctx)
|
||||
rf.includeDesktopDir("");
|
||||
|
||||
os::Display* display = ui::Manager::getDefault()->getDisplay();
|
||||
os::Surface* surface = display->getSurface();
|
||||
os::Surface* surface = display->surface();
|
||||
std::string fn;
|
||||
|
||||
if (params().save()) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -13,7 +13,6 @@
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/memory.h"
|
||||
#include "base/string.h"
|
||||
#include "ui/ui.h"
|
||||
@ -34,14 +33,13 @@ public:
|
||||
ConsoleWindow() : Window(Window::WithTitleBar, "Console"),
|
||||
m_textbox("", WORDWRAP),
|
||||
m_button("Cancel") {
|
||||
m_button.Click.connect(base::Bind<void>(&ConsoleWindow::closeWindow, this, &m_button));
|
||||
m_button.Click.connect([this]{ closeWindow(&m_button); });
|
||||
|
||||
// When the window is closed, we clear the text
|
||||
Close.connect(
|
||||
base::Bind<void>(
|
||||
[this] {
|
||||
m_textbox.setText(std::string());
|
||||
}));
|
||||
[this]{
|
||||
m_textbox.setText(std::string());
|
||||
});
|
||||
|
||||
m_view.attachToView(&m_textbox);
|
||||
m_button.setMinSize(gfx::Size(60*ui::guiscale(), 0));
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "app/doc_access.h"
|
||||
#include "app/doc_diff.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/chrono.h"
|
||||
#include "base/remove_from_container.h"
|
||||
#include "ui/system.h"
|
||||
@ -63,7 +62,7 @@ BackupObserver::BackupObserver(RecoveryConfig* config,
|
||||
, m_session(session)
|
||||
, m_ctx(ctx)
|
||||
, m_done(false)
|
||||
, m_thread(base::Bind<void>(&BackupObserver::backgroundThread, this))
|
||||
, m_thread([this]{ backgroundThread(); })
|
||||
{
|
||||
m_ctx->add_observer(this);
|
||||
m_ctx->documents().add_observer(this);
|
||||
|
@ -368,7 +368,7 @@ private:
|
||||
|
||||
// Read color space
|
||||
if (!s.eof()) {
|
||||
gfx::ColorSpacePtr colorSpace = readColorSpace(s);
|
||||
gfx::ColorSpaceRef colorSpace = readColorSpace(s);
|
||||
if (colorSpace)
|
||||
spr->setColorSpace(colorSpace);
|
||||
}
|
||||
@ -383,7 +383,7 @@ private:
|
||||
return spr.release();
|
||||
}
|
||||
|
||||
gfx::ColorSpacePtr readColorSpace(std::ifstream& s) {
|
||||
gfx::ColorSpaceRef readColorSpace(std::ifstream& s) {
|
||||
const gfx::ColorSpace::Type type = (gfx::ColorSpace::Type)read16(s);
|
||||
const gfx::ColorSpace::Flag flags = (gfx::ColorSpace::Flag)read16(s);
|
||||
const double gamma = fixmath::fixtof(read32(s));
|
||||
@ -399,7 +399,7 @@ private:
|
||||
s.read((char*)&buf[0], n);
|
||||
std::string name = read_string(s);
|
||||
|
||||
auto colorSpace = std::make_shared<gfx::ColorSpace>(
|
||||
auto colorSpace = base::make_ref<gfx::ColorSpace>(
|
||||
type, flags, gamma, std::move(buf));
|
||||
colorSpace->setName(name);
|
||||
return colorSpace;
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "app/doc_access.h"
|
||||
#include "app/file/file.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/fstream_path.h"
|
||||
|
@ -205,7 +205,7 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool writeColorSpace(std::ofstream& s, const gfx::ColorSpacePtr& colorSpace) {
|
||||
bool writeColorSpace(std::ofstream& s, const gfx::ColorSpaceRef& colorSpace) {
|
||||
write16(s, colorSpace->type());
|
||||
write16(s, colorSpace->flags());
|
||||
write32(s, fixmath::ftofix(colorSpace->gamma()));
|
||||
|
@ -602,7 +602,7 @@ void Doc::updateOSColorSpace(bool appWideSignal)
|
||||
{
|
||||
auto system = os::instance();
|
||||
if (system) {
|
||||
m_osColorSpace = system->createColorSpace(sprite()->colorSpace());
|
||||
m_osColorSpace = system->makeColorSpace(sprite()->colorSpace());
|
||||
if (!m_osColorSpace && system->defaultDisplay())
|
||||
m_osColorSpace = system->defaultDisplay()->colorSpace();
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ namespace app {
|
||||
color_t bgColor() const;
|
||||
color_t bgColor(Layer* layer) const;
|
||||
|
||||
os::ColorSpacePtr osColorSpace() const { return m_osColorSpace; }
|
||||
os::ColorSpaceRef osColorSpace() const { return m_osColorSpace; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Notifications
|
||||
@ -261,7 +261,7 @@ namespace app {
|
||||
gfx::Point m_lastDrawingPoint;
|
||||
|
||||
// Last used color space to render a sprite.
|
||||
os::ColorSpacePtr m_osColorSpace;
|
||||
os::ColorSpaceRef m_osColorSpace;
|
||||
|
||||
DISABLE_COPYING(Doc);
|
||||
};
|
||||
|
@ -1094,7 +1094,7 @@ Doc* DocExporter::createEmptyTexture(const Samples& samples,
|
||||
ColorMode colorMode = ColorMode::INDEXED;
|
||||
Palette* palette = nullptr;
|
||||
int maxColors = 256;
|
||||
gfx::ColorSpacePtr colorSpace;
|
||||
gfx::ColorSpaceRef colorSpace;
|
||||
color_t transparentColor = 0;
|
||||
|
||||
for (const auto& sample : samples) {
|
||||
@ -1184,6 +1184,7 @@ void DocExporter::renderTexture(Context* ctx,
|
||||
sample.sprite(),
|
||||
textureImage->pixelFormat(),
|
||||
render::Dithering(),
|
||||
Sprite::DefaultRgbMapAlgorithm(), // TODO add rgbmap algorithm preference
|
||||
nullptr, // toGray is not needed because the texture is Indexed or RGB
|
||||
nullptr) // TODO add a delegate to show progress
|
||||
.execute(ctx);
|
||||
|
@ -995,7 +995,7 @@ static void ase_file_write_color_profile(FILE* f,
|
||||
dio::AsepriteFrameHeader* frame_header,
|
||||
const doc::Sprite* sprite)
|
||||
{
|
||||
const gfx::ColorSpacePtr& cs = sprite->colorSpace();
|
||||
const gfx::ColorSpaceRef& cs = sprite->colorSpace();
|
||||
if (!cs) // No color
|
||||
return;
|
||||
|
||||
|
@ -906,7 +906,8 @@ void FileOp::postLoad()
|
||||
std::shared_ptr<Palette> palette(
|
||||
render::create_palette_from_sprite(
|
||||
sprite, frame_t(0), sprite->lastFrame(), true,
|
||||
nullptr, nullptr, m_config.newBlend));
|
||||
nullptr, nullptr, m_config.newBlend,
|
||||
m_config.rgbMapAlgorithm));
|
||||
|
||||
sprite->resetPalettes();
|
||||
sprite->setPalette(palette.get(), false);
|
||||
@ -914,7 +915,7 @@ void FileOp::postLoad()
|
||||
}
|
||||
|
||||
// What to do with the sprite color profile?
|
||||
gfx::ColorSpacePtr spriteCS = sprite->colorSpace();
|
||||
gfx::ColorSpaceRef spriteCS = sprite->colorSpace();
|
||||
app::gen::ColorProfileBehavior behavior =
|
||||
app::gen::ColorProfileBehavior::DISABLE;
|
||||
|
||||
|
@ -22,6 +22,7 @@ void FileOpConfig::fillFromPreferences()
|
||||
newBlend = Preferences::instance().experimental.newBlend();
|
||||
defaultSliceColor = Preferences::instance().slices.defaultColor();
|
||||
workingCS = get_working_rgb_space_from_preferences();
|
||||
rgbMapAlgorithm = Preferences::instance().experimental.rgbmapAlgorithm();
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
#include "app/color.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "doc/rgbmap_algorithm.h"
|
||||
#include "gfx/color_space.h"
|
||||
|
||||
namespace app {
|
||||
@ -24,7 +25,7 @@ namespace app {
|
||||
// profile or without a color profile.
|
||||
app::gen::ColorProfileBehavior filesWithProfile = app::gen::ColorProfileBehavior::EMBEDDED;
|
||||
app::gen::ColorProfileBehavior missingProfile = app::gen::ColorProfileBehavior::ASSIGN;
|
||||
gfx::ColorSpacePtr workingCS = gfx::ColorSpace::MakeSRGB();
|
||||
gfx::ColorSpaceRef workingCS = gfx::ColorSpace::MakeSRGB();
|
||||
|
||||
// True if we should render each frame to save it with the new
|
||||
// blend mode.h
|
||||
@ -32,6 +33,9 @@ namespace app {
|
||||
|
||||
app::Color defaultSliceColor = app::Color::fromRgb(0, 0, 255);
|
||||
|
||||
// Algorithm used to create a palette from RGB files.
|
||||
doc::RgbMapAlgorithm rgbMapAlgorithm = doc::RgbMapAlgorithm::DEFAULT;
|
||||
|
||||
void fillFromPreferences();
|
||||
};
|
||||
|
||||
|
@ -356,7 +356,9 @@ private:
|
||||
if (!frameBounds.isEmpty())
|
||||
frameImage.reset(readFrameIndexedImage(frameBounds));
|
||||
|
||||
GIF_TRACE("GIF: Frame[%d] transparent index = %d\n", (int)m_frameNum, m_localTransparentIndex);
|
||||
GIF_TRACE("GIF: Frame[%d] transparentIndex=%d localMap=%d\n",
|
||||
(int)m_frameNum, m_localTransparentIndex,
|
||||
m_gifFile->Image.ColorMap ? m_gifFile->Image.ColorMap->ColorCount: 0);
|
||||
|
||||
if (m_frameNum == 0) {
|
||||
if (m_localTransparentIndex >= 0)
|
||||
@ -456,9 +458,14 @@ private:
|
||||
}
|
||||
else if (!m_hasLocalColormaps) {
|
||||
if (!global) {
|
||||
if (!m_firstLocalColormap)
|
||||
m_firstLocalColormap = GifMakeMapObject(colormap->ColorCount,
|
||||
colormap->Colors);
|
||||
if (!m_firstLocalColormap) {
|
||||
m_firstLocalColormap = GifMakeMapObject(256, nullptr);
|
||||
for (int i=0; i<colormap->ColorCount; ++i) {
|
||||
m_firstLocalColormap->Colors[i].Red = colormap->Colors[i].Red;
|
||||
m_firstLocalColormap->Colors[i].Green = colormap->Colors[i].Green;
|
||||
m_firstLocalColormap->Colors[i].Blue = colormap->Colors[i].Blue;
|
||||
}
|
||||
}
|
||||
global = m_firstLocalColormap;
|
||||
}
|
||||
|
||||
@ -502,13 +509,13 @@ private:
|
||||
// With this we avoid discarding the transparent index when a
|
||||
// frame indicates that it uses a specific index as transparent
|
||||
// but the image is completely opaque anyway.
|
||||
if (m_localTransparentIndex >= 0 &&
|
||||
if (!m_opaque && m_frameNum == 0 && m_localTransparentIndex >= 0 &&
|
||||
m_localTransparentIndex < ncolors) {
|
||||
usedEntries[m_localTransparentIndex] = true;
|
||||
}
|
||||
|
||||
for (const auto& i : LockImageBits<IndexedTraits>(frameImage)) {
|
||||
if (i >= 0 && i < ncolors)
|
||||
if (i >= 0 && i < ncolors && i != m_localTransparentIndex)
|
||||
usedEntries[i] = true;
|
||||
}
|
||||
}
|
||||
@ -523,11 +530,16 @@ private:
|
||||
// Check if we need an extra color equal to the bg color in a
|
||||
// transparent frameImage.
|
||||
bool needsExtraBgColor = false;
|
||||
bool needCheckLocalTransparent = m_bgIndex != m_localTransparentIndex ||
|
||||
(ncolors > m_localTransparentIndex
|
||||
&& m_localTransparentIndex >= 0
|
||||
&& usedEntries[m_localTransparentIndex]);
|
||||
|
||||
if (m_sprite->pixelFormat() == IMAGE_INDEXED &&
|
||||
!m_opaque && m_bgIndex != m_localTransparentIndex) {
|
||||
!m_opaque &&
|
||||
needCheckLocalTransparent) {
|
||||
for (const auto& i : LockImageBits<IndexedTraits>(frameImage)) {
|
||||
if (i == m_bgIndex &&
|
||||
i != m_localTransparentIndex) {
|
||||
if (i == m_bgIndex) {
|
||||
needsExtraBgColor = true;
|
||||
break;
|
||||
}
|
||||
@ -617,6 +629,20 @@ private:
|
||||
int i = m_bgIndex;
|
||||
int j = base++;
|
||||
palette->setEntry(j, colormap2rgba(colormap, i));
|
||||
// m_firstLocalColorMap, is used only if we have no global color map in the gif source,
|
||||
// and we want to preserve original color indexes, as much we can.
|
||||
// If the palette size is > 256, m_firstLocalColormal is no more useful, because
|
||||
// the sprite pixel format will be converted in RGBA image, and the colors will
|
||||
// be picked from the sprite palette, instead of m_firstLocalColorMap.
|
||||
if (m_firstLocalColormap && m_firstLocalColormap->ColorCount > j) {
|
||||
// We need add this extra color to m_firstLocalColormap, because
|
||||
// it might has not been considered in the first getFrameColormap execution.
|
||||
// (this happen when: in the first execution of getFrameColormap function
|
||||
// an extra color was not needed)
|
||||
m_firstLocalColormap->Colors[j].Red = rgba_getr(palette->getEntry(j));
|
||||
m_firstLocalColormap->Colors[j].Green = rgba_getg(palette->getEntry(j));
|
||||
m_firstLocalColormap->Colors[j].Blue = rgba_getb(palette->getEntry(j));
|
||||
}
|
||||
m_remap.map(i, j);
|
||||
}
|
||||
|
||||
@ -892,6 +918,34 @@ bool GifFormat::onLoad(FileOp* fop)
|
||||
|
||||
#ifdef ENABLE_SAVE
|
||||
|
||||
// Our stragegy to encode GIF files depends of the sprite color mode:
|
||||
//
|
||||
// 1) If the sprite is indexed, we have two paths:
|
||||
// * For opaque an opaque sprite we can save it as it is (with the
|
||||
// same indexes/pixels and same color palette). This brings us
|
||||
// the best possible to compress the GIF file (using the best
|
||||
// disposal method to update only the differences between each
|
||||
// frame).
|
||||
// * For transparent sprites we offer to the user the option to
|
||||
// preserve the original palette or not
|
||||
// (m_preservePaletteOrders). If the palette must be preserve,
|
||||
// some level of compression will be sacrificed.
|
||||
//
|
||||
// 2) For RGB sprites the palette is created on each frame depending
|
||||
// on the updated rectangle between frames, i.e. each to new frame
|
||||
// incorporates a minimal rectangular region with changes from the
|
||||
// previous frame, we can calculate the palette required for this
|
||||
// rectangle and use it as a local colormap for the frame (if each
|
||||
// frame uses previous color in the palette there is no need to
|
||||
// introduce a new palette).
|
||||
//
|
||||
// Note: In the following algorithm you will find the "pixel clearing"
|
||||
// term, this happens when we need to clear an opaque color with the
|
||||
// gif transparent bg color. This is the worst possible case, because
|
||||
// on transparent gif files, the only way to get the transparent color
|
||||
// (bg color) is using the RESTORE_BGCOLOR disposal method (so we lost
|
||||
// the chance to use DO_NOT_DISPOSE in these cases).
|
||||
//
|
||||
class GifEncoder {
|
||||
public:
|
||||
typedef int gifframe_t;
|
||||
@ -902,10 +956,22 @@ public:
|
||||
, m_document(fop->document())
|
||||
, m_sprite(fop->document()->sprite())
|
||||
, m_spriteBounds(m_sprite->bounds())
|
||||
, m_hasBackground(m_sprite->backgroundLayer() ? true: false)
|
||||
, m_hasBackground(m_sprite->isOpaque())
|
||||
, m_bitsPerPixel(1)
|
||||
, m_globalColormap(nullptr)
|
||||
, m_quantizeColormaps(false) {
|
||||
, m_globalColormapPalette(*m_sprite->palette(0))
|
||||
, m_preservePaletteOrder(false) {
|
||||
|
||||
const auto gifOptions = std::static_pointer_cast<GifOptions>(fop->formatOptions());
|
||||
|
||||
LOG("GIF: Saving with options: interlaced=%d loop=%d\n",
|
||||
gifOptions->interlaced(), gifOptions->loop());
|
||||
|
||||
m_interlaced = gifOptions->interlaced();
|
||||
m_loop = (gifOptions->loop() ? 0: -1);
|
||||
m_lastFrameBounds = m_spriteBounds;
|
||||
m_lastDisposal = DisposalMethod::NONE;
|
||||
|
||||
if (m_sprite->pixelFormat() == IMAGE_INDEXED) {
|
||||
for (Palette* palette : m_sprite->getPalettes()) {
|
||||
int bpp = GifBitSizeLimited(palette->size());
|
||||
@ -920,46 +986,107 @@ public:
|
||||
m_sprite->getPalettes().size() == 1) {
|
||||
// If some layer has opacity < 255 or a different blend mode, we
|
||||
// need to create color palettes.
|
||||
bool quantizeColormaps = false;
|
||||
for (const Layer* layer : m_sprite->allVisibleLayers()) {
|
||||
if (layer->isVisible() && layer->isImage()) {
|
||||
const LayerImage* imageLayer = static_cast<const LayerImage*>(layer);
|
||||
if (imageLayer->opacity() < 255 ||
|
||||
imageLayer->blendMode() != BlendMode::NORMAL) {
|
||||
m_quantizeColormaps = true;
|
||||
quantizeColormaps = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_quantizeColormaps) {
|
||||
m_globalColormap = createColorMap(m_sprite->palette(0));
|
||||
if (!quantizeColormaps) {
|
||||
m_globalColormap = createColorMap(&m_globalColormapPalette);
|
||||
m_bgIndex = m_sprite->transparentColor();
|
||||
// For indexed and opaque sprite, we can preserve the exact
|
||||
// palette order without lossing compression rate.
|
||||
if (m_hasBackground)
|
||||
m_preservePaletteOrder = true;
|
||||
// Only for transparent indexed images the user can choose to
|
||||
// preserve or not the palette order.
|
||||
else
|
||||
m_preservePaletteOrder = gifOptions->preservePaletteOrder();
|
||||
}
|
||||
else
|
||||
m_bgIndex = 0;
|
||||
}
|
||||
else {
|
||||
m_bgIndex = 0;
|
||||
m_quantizeColormaps = true;
|
||||
}
|
||||
|
||||
// This is the transparent index to use as "local transparent"
|
||||
// index for each gif frame. In case that we use a global colormap
|
||||
// (and we don't need to preserve the original palette), we can
|
||||
// try to find a place for a global transparent index.
|
||||
m_transparentIndex = (m_hasBackground ? -1: m_bgIndex);
|
||||
if (m_globalColormap) {
|
||||
// The variable m_globalColormap is != nullptr only on indexed images
|
||||
ASSERT(m_sprite->pixelFormat() == IMAGE_INDEXED);
|
||||
|
||||
if (m_hasBackground)
|
||||
m_clearColor = m_sprite->palette(0)->getEntry(m_bgIndex);
|
||||
else
|
||||
m_clearColor = rgba(0, 0, 0, 0);
|
||||
const Palette* pal = m_sprite->palette(0);
|
||||
bool maskColorFounded = false;
|
||||
for (int i=0; i<pal->size(); i++) {
|
||||
if (doc::rgba_geta(pal->getEntry(i)) == 0) {
|
||||
maskColorFounded = true;
|
||||
m_transparentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const auto gifOptions = std::static_pointer_cast<GifOptions>(fop->formatOptions());
|
||||
#if 0
|
||||
// If the palette contains room for one extra color for the
|
||||
// mask, we can use that index.
|
||||
if (!maskColorFounded && pal->size() < 256) {
|
||||
maskColorFounded = true;
|
||||
|
||||
LOG("GIF: Saving with options: interlaced=%d loop=%d\n",
|
||||
gifOptions->interlaced(), gifOptions->loop());
|
||||
Palette newPalette(*pal);
|
||||
newPalette.addEntry(0);
|
||||
ASSERT(newPalette.size() <= 256);
|
||||
|
||||
m_interlaced = gifOptions->interlaced();
|
||||
m_loop = (gifOptions->loop() ? 0: -1);
|
||||
m_transparentIndex = newPalette.size() - 1;
|
||||
m_globalColormapPalette = newPalette;
|
||||
m_globalColormap = createColorMap(&m_globalColormapPalette);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (// If all colors are opaque/used in the sprite
|
||||
!maskColorFounded &&
|
||||
// We aren't obligated to preserve the original palette
|
||||
!m_preservePaletteOrder &&
|
||||
// And the sprite is transparent
|
||||
!m_hasBackground) {
|
||||
// We create a new palette with 255 colors + one extra entry
|
||||
// for the transparent color
|
||||
Palette newPalette(0, 255);
|
||||
render::create_palette_from_sprite(
|
||||
m_sprite,
|
||||
0,
|
||||
totalFrames()-1,
|
||||
false,
|
||||
&newPalette,
|
||||
nullptr,
|
||||
m_fop->newBlend(),
|
||||
RgbMapAlgorithm::DEFAULT, // TODO configurable?
|
||||
false); // Do not add the transparent color yet
|
||||
|
||||
// We will use the last palette entry (e.g. index=255) as the
|
||||
// transparent index
|
||||
newPalette.addEntry(0);
|
||||
ASSERT(newPalette.size() <= 256);
|
||||
|
||||
m_transparentIndex = newPalette.size() - 1;
|
||||
m_globalColormapPalette = newPalette;
|
||||
m_globalColormap = createColorMap(&m_globalColormapPalette);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the 3 temporary images (previous/current/next) to
|
||||
// compare pixels between them.
|
||||
for (int i=0; i<3; ++i)
|
||||
m_images[i].reset(Image::create(IMAGE_RGB,
|
||||
m_images[i].reset(Image::create((m_preservePaletteOrder)? IMAGE_INDEXED : IMAGE_RGB,
|
||||
m_spriteBounds.w,
|
||||
m_spriteBounds.h));
|
||||
}
|
||||
@ -1005,25 +1132,22 @@ public:
|
||||
if (gifFrame+1 < nframes)
|
||||
renderFrame(*frame_it, m_nextImage);
|
||||
|
||||
gfx::Rect frameBounds;
|
||||
DisposalMethod disposal;
|
||||
calculateBestDisposalMethod(gifFrame, frameBounds, disposal);
|
||||
gfx::Rect frameBounds = m_spriteBounds;
|
||||
DisposalMethod disposal = DisposalMethod::DO_NOT_DISPOSE;
|
||||
|
||||
// TODO We could join both frames in a longer one (with more duration)
|
||||
if (frameBounds.isEmpty())
|
||||
frameBounds = gfx::Rect(0, 0, 1, 1);
|
||||
// Creation of the deltaImage (difference image result respect
|
||||
// to current VS previous frame image). At the same time we
|
||||
// must scan the next image, to check if some pixel turns to
|
||||
// transparent (0), if the case, we need to force disposal
|
||||
// method of the current image to RESTORE_BG. Further, at the
|
||||
// same time, we must check if we can go without color zero (0).
|
||||
|
||||
calculateDeltaImageFrameBoundsDisposal(gifFrame, frameBounds, disposal);
|
||||
|
||||
writeImage(gifFrame, frame, frameBounds, disposal,
|
||||
// Only the last frame in the animation needs the fix
|
||||
(fix_last_frame_duration && gifFrame == nframes-1));
|
||||
|
||||
// Dispose/clear frame content
|
||||
process_disposal_method(m_previousImage,
|
||||
m_currentImage,
|
||||
disposal,
|
||||
frameBounds,
|
||||
m_clearColor);
|
||||
|
||||
m_fop->setProgress(double(gifFrame+1) / double(nframes));
|
||||
}
|
||||
return true;
|
||||
@ -1031,6 +1155,126 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void calculateDeltaImageFrameBoundsDisposal(gifframe_t gifFrame,
|
||||
gfx::Rect& frameBounds,
|
||||
DisposalMethod& disposal) {
|
||||
if (gifFrame == 0) {
|
||||
m_deltaImage.reset(Image::createCopy(m_currentImage));
|
||||
frameBounds = m_spriteBounds;
|
||||
|
||||
// The first frame (frame 0) is good to force to disposal = DO_NOT_DISPOSE,
|
||||
// but when the next frame (frame 1) has a "pixel clearing",
|
||||
// we must change disposal to RESTORE_BGCOLOR.
|
||||
|
||||
// "Pixel clearing" detection:
|
||||
if (!m_hasBackground && !m_preservePaletteOrder) {
|
||||
const LockImageBits<RgbTraits> bits2(m_currentImage);
|
||||
const LockImageBits<RgbTraits> bits3(m_nextImage);
|
||||
typename LockImageBits<RgbTraits>::const_iterator it2, it3, end2, end3;
|
||||
for (it2 = bits2.begin(), end2 = bits2.end(),
|
||||
it3 = bits3.begin(), end3 = bits3.end();
|
||||
it2 != end2 && it3 != end3; ++it2, ++it3) {
|
||||
if (*it2 != 0 && *it3 == 0) {
|
||||
disposal = DisposalMethod::RESTORE_BGCOLOR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_preservePaletteOrder)
|
||||
disposal = DisposalMethod::RESTORE_BGCOLOR;
|
||||
}
|
||||
else {
|
||||
int x1 = 0;
|
||||
int y1 = 0;
|
||||
int x2 = 0;
|
||||
int y2 = 0;
|
||||
|
||||
if (!m_preservePaletteOrder) {
|
||||
// When m_lastDisposal was RESTORE_BGBOLOR it implies
|
||||
// we will have to cover with colors the entire previous frameBounds plus
|
||||
// the current frameBounds due to color changes, so we must start with
|
||||
// a frameBounds equal to the previous frame iteration (saved in m_lastFrameBounds).
|
||||
// Then we must cover all the resultant frameBounds with full color
|
||||
// in m_currentImage, the output image will be saved in deltaImage.
|
||||
if (m_lastDisposal == DisposalMethod::RESTORE_BGCOLOR) {
|
||||
x1 = m_lastFrameBounds.x;
|
||||
y1 = m_lastFrameBounds.y;
|
||||
x2 = m_lastFrameBounds.x + m_lastFrameBounds.w - 1;
|
||||
y2 = m_lastFrameBounds.y + m_lastFrameBounds.h - 1;
|
||||
}
|
||||
else {
|
||||
x1 = m_spriteBounds.w - 1;
|
||||
y1 = m_spriteBounds.h - 1;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
int x, y;
|
||||
const LockImageBits<RgbTraits> bits1(m_previousImage);
|
||||
const LockImageBits<RgbTraits> bits2(m_currentImage);
|
||||
const LockImageBits<RgbTraits> bits3(m_nextImage);
|
||||
m_deltaImage.reset(Image::create(PixelFormat::IMAGE_RGB, m_spriteBounds.w, m_spriteBounds.h));
|
||||
clear_image(m_deltaImage.get(), 0);
|
||||
LockImageBits<RgbTraits> deltaBits(m_deltaImage.get());
|
||||
typename LockImageBits<RgbTraits>::iterator deltaIt;
|
||||
typename LockImageBits<RgbTraits>::const_iterator it1, it2, it3, end1, end2, end3, deltaEnd;
|
||||
|
||||
bool previousImageMatchsCurrent = true;
|
||||
for (it1 = bits1.begin(), end1 = bits1.end(),
|
||||
it2 = bits2.begin(), end2 = bits2.end(),
|
||||
it3 = bits3.begin(), end2 = bits3.end(),
|
||||
deltaIt = deltaBits.begin();
|
||||
it1 != end1 && it2 != end2; ++it1, ++it2, ++it3, ++deltaIt, ++i) {
|
||||
x = i % m_spriteBounds.w;
|
||||
y = i / m_spriteBounds.w;
|
||||
// While we are checking color differences,
|
||||
// we enlarge the frameBounds where the color differences take place
|
||||
if (*it1 != *it2 || *it3 == 0) {
|
||||
previousImageMatchsCurrent = false;
|
||||
*deltaIt = *it2;
|
||||
if (x < x1) x1 = x;
|
||||
if (x > x2) x2 = x;
|
||||
if (y < y1) y1 = y;
|
||||
if (y > y2) y2 = y;
|
||||
}
|
||||
|
||||
// We need to change disposal mode DO_NOT_DISPOSE to RESTORE_BGCOLOR only
|
||||
// if we found a "pixel clearing" in the next Image. RESTORE_BGCOLOR is
|
||||
// our way to clear pixels.
|
||||
if (*it2 != 0 && *it3 == 0) {
|
||||
disposal = DisposalMethod::RESTORE_BGCOLOR;
|
||||
}
|
||||
}
|
||||
if (previousImageMatchsCurrent)
|
||||
frameBounds = gfx::Rect(m_lastFrameBounds);
|
||||
else
|
||||
frameBounds = gfx::Rect(x1, y1, x2-x1+1, y2-y1+1);
|
||||
}
|
||||
else
|
||||
disposal = DisposalMethod::RESTORE_BGCOLOR;
|
||||
|
||||
// We need to conditionate the deltaImage to the next step: 'writeImage()'
|
||||
// To do it, we need to crop deltaImage in frameBounds.
|
||||
// If disposal method changed to RESTORE_BGCOLOR deltaImage we need to reproduce ALL the colors of m_currentImage
|
||||
// contained in frameBounds (so, we will overwrite delta image with a cropped current image).
|
||||
// In the other hand, if disposal is still DO_NOT_DISPOSAL, delta image will be a cropped image
|
||||
// from itself in frameBounds.
|
||||
if (disposal == DisposalMethod::RESTORE_BGCOLOR || m_lastDisposal == DisposalMethod::RESTORE_BGCOLOR) {
|
||||
m_deltaImage.reset(crop_image(m_currentImage, frameBounds, 0));
|
||||
}
|
||||
else {
|
||||
m_deltaImage.reset(crop_image(m_deltaImage.get(), frameBounds, 0));
|
||||
disposal = DisposalMethod::DO_NOT_DISPOSE;
|
||||
}
|
||||
m_lastFrameBounds = frameBounds;
|
||||
}
|
||||
|
||||
// TODO We could join both frames in a longer one (with more duration)
|
||||
if (frameBounds.isEmpty())
|
||||
frameBounds = gfx::Rect(0, 0, 1, 1);
|
||||
|
||||
m_lastDisposal = disposal;
|
||||
}
|
||||
|
||||
doc::frame_t totalFrames() const {
|
||||
return m_fop->roi().frames();
|
||||
}
|
||||
@ -1123,99 +1367,38 @@ private:
|
||||
return frameBounds;
|
||||
}
|
||||
|
||||
void calculateBestDisposalMethod(gifframe_t gifFrame, gfx::Rect& frameBounds,
|
||||
DisposalMethod& disposal) {
|
||||
if (m_hasBackground) {
|
||||
disposal = DisposalMethod::DO_NOT_DISPOSE;
|
||||
}
|
||||
else {
|
||||
disposal = DisposalMethod::RESTORE_BGCOLOR;
|
||||
}
|
||||
|
||||
if (gifFrame == 0) {
|
||||
frameBounds = m_spriteBounds;
|
||||
}
|
||||
else {
|
||||
gfx::Rect prev, next;
|
||||
|
||||
if (gifFrame-1 >= 0)
|
||||
prev = calculateFrameBounds(m_currentImage, m_previousImage);
|
||||
|
||||
if (!m_hasBackground &&
|
||||
gifFrame+1 < totalFrames())
|
||||
next = calculateFrameBounds(m_currentImage, m_nextImage);
|
||||
|
||||
frameBounds = prev.createUnion(next);
|
||||
|
||||
// Special case were it's better to restore the previous frame
|
||||
// when we dispose the current one than clearing with the bg
|
||||
// color.
|
||||
if (m_hasBackground && !prev.isEmpty()) {
|
||||
gfx::Rect prevNext = calculateFrameBounds(m_previousImage, m_nextImage);
|
||||
if (!prevNext.isEmpty() &&
|
||||
frameBounds.contains(prevNext) &&
|
||||
prevNext.w*prevNext.h < frameBounds.w*frameBounds.h) {
|
||||
disposal = DisposalMethod::RESTORE_PREVIOUS;
|
||||
}
|
||||
}
|
||||
|
||||
GIF_TRACE("GIF: frameBounds=%d %d %d %d prev=%d %d %d %d next=%d %d %d %d\n",
|
||||
frameBounds.x, frameBounds.y, frameBounds.w, frameBounds.h,
|
||||
prev.x, prev.y, prev.w, prev.h,
|
||||
next.x, next.y, next.w, next.h);
|
||||
}
|
||||
}
|
||||
|
||||
void writeImage(const gifframe_t gifFrame,
|
||||
const frame_t frame,
|
||||
const gfx::Rect& frameBounds,
|
||||
const DisposalMethod disposal,
|
||||
const bool fixDuration) {
|
||||
std::unique_ptr<Palette> framePaletteRef;
|
||||
std::unique_ptr<RgbMap> rgbmapRef;
|
||||
Palette* framePalette = m_sprite->palette(frame);
|
||||
RgbMap* rgbmap = m_sprite->rgbMap(frame);
|
||||
Palette framePalette;
|
||||
if (m_globalColormap)
|
||||
framePalette = m_globalColormapPalette;
|
||||
else
|
||||
framePalette = calculatePalette(frameBounds, disposal);
|
||||
|
||||
// Create optimized palette for RGB/Grayscale images
|
||||
if (m_quantizeColormaps) {
|
||||
framePaletteRef.reset(createOptimizedPalette(frameBounds));
|
||||
framePalette = framePaletteRef.get();
|
||||
|
||||
rgbmapRef.reset(new RgbMap);
|
||||
rgbmap = rgbmapRef.get();
|
||||
rgbmap->regenerate(framePalette, m_transparentIndex);
|
||||
}
|
||||
|
||||
// We will store the frameBounds pixels in frameImage, with the
|
||||
// indexes that must be stored in the GIF file for this specific
|
||||
// frame.
|
||||
if (!m_frameImageBuf)
|
||||
m_frameImageBuf.reset(new ImageBuffer);
|
||||
RgbMapRGB5A3 rgbmap; // TODO RgbMapRGB5A3 configurable?
|
||||
rgbmap.regenerateMap(&framePalette, m_transparentIndex);
|
||||
|
||||
ImageRef frameImage(Image::create(IMAGE_INDEXED,
|
||||
frameBounds.w,
|
||||
frameBounds.h,
|
||||
m_frameImageBuf));
|
||||
|
||||
// Convert the frameBounds area of m_currentImage (RGB) to frameImage (Indexed)
|
||||
// bool needsTransparent = false;
|
||||
PalettePicks usedColors(framePalette->size());
|
||||
// Every frame might use a small portion of the global palette,
|
||||
// to optimize the gif file size, we will analize which colors
|
||||
// will be used in each processed frame.
|
||||
PalettePicks usedColors(framePalette.size());
|
||||
|
||||
// If the sprite needs a transparent color we mark it as used so
|
||||
// the palette includes a spot for it. It doesn't matter if the
|
||||
// image doesn't use the transparent index, if the sprite isn't
|
||||
// opaque we need the transparent index anyway.
|
||||
if (m_transparentIndex >= 0) {
|
||||
int i = m_transparentIndex;
|
||||
if (i >= usedColors.size())
|
||||
usedColors.resize(i+1);
|
||||
usedColors[i] = true;
|
||||
}
|
||||
int localTransparent = m_transparentIndex;
|
||||
ColorMapObject* colormap = m_globalColormap;
|
||||
Remap remap(256);
|
||||
|
||||
{
|
||||
const LockImageBits<RgbTraits> srcBits(m_currentImage, frameBounds);
|
||||
LockImageBits<IndexedTraits> dstBits(
|
||||
frameImage.get(), gfx::Rect(0, 0, frameBounds.w, frameBounds.h));
|
||||
if (!m_preservePaletteOrder) {
|
||||
const LockImageBits<RgbTraits> srcBits(m_deltaImage.get());
|
||||
LockImageBits<IndexedTraits> dstBits(frameImage.get());
|
||||
|
||||
auto srcIt = srcBits.begin();
|
||||
auto dstIt = dstBits.begin();
|
||||
@ -1229,20 +1412,16 @@ private:
|
||||
int i;
|
||||
|
||||
if (rgba_geta(color) >= 128) {
|
||||
i = framePalette->findExactMatch(
|
||||
i = framePalette.findExactMatch(
|
||||
rgba_getr(color),
|
||||
rgba_getg(color),
|
||||
rgba_getb(color),
|
||||
255,
|
||||
m_transparentIndex);
|
||||
if (i < 0)
|
||||
i = rgbmap->mapColor(rgba_getr(color),
|
||||
rgba_getg(color),
|
||||
rgba_getb(color),
|
||||
255);
|
||||
i = rgbmap.mapColor(color | rgba_a_mask); // alpha=255
|
||||
}
|
||||
else {
|
||||
ASSERT(m_transparentIndex >= 0);
|
||||
if (m_transparentIndex >= 0)
|
||||
i = m_transparentIndex;
|
||||
else
|
||||
@ -1261,34 +1440,36 @@ private:
|
||||
*dstIt = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int usedNColors = usedColors.picks();
|
||||
int usedNColors = usedColors.picks();
|
||||
|
||||
Remap remap(256);
|
||||
for (int i=0; i<remap.size(); ++i)
|
||||
remap.map(i, i);
|
||||
for (int i=0; i<remap.size(); ++i)
|
||||
remap.map(i, i);
|
||||
|
||||
int localTransparent = m_transparentIndex;
|
||||
ColorMapObject* colormap = m_globalColormap;
|
||||
if (!colormap) {
|
||||
Palette reducedPalette(0, usedNColors);
|
||||
if (!colormap) {
|
||||
Palette reducedPalette(0, usedNColors);
|
||||
|
||||
for (int i=0, j=0; i<framePalette->size(); ++i) {
|
||||
if (usedColors[i]) {
|
||||
reducedPalette.setEntry(j, framePalette->getEntry(i));
|
||||
remap.map(i, j);
|
||||
++j;
|
||||
for (int i=0, j=0; i<framePalette.size(); ++i) {
|
||||
if (usedColors[i]) {
|
||||
reducedPalette.setEntry(j, framePalette.getEntry(i));
|
||||
remap.map(i, j);
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
colormap = createColorMap(&reducedPalette);
|
||||
if (localTransparent >= 0)
|
||||
localTransparent = remap[localTransparent];
|
||||
}
|
||||
|
||||
colormap = createColorMap(&reducedPalette);
|
||||
if (localTransparent >= 0)
|
||||
localTransparent = remap[localTransparent];
|
||||
if (localTransparent >= 0 && m_transparentIndex != localTransparent)
|
||||
remap.map(m_transparentIndex, localTransparent);
|
||||
}
|
||||
else {
|
||||
frameImage.reset(Image::createCopy(m_deltaImage.get()));
|
||||
for (int i=0; i<colormap->ColorCount; ++i)
|
||||
remap.map(i, i);
|
||||
}
|
||||
|
||||
if (localTransparent >= 0 && m_transparentIndex != localTransparent)
|
||||
remap.map(m_transparentIndex, localTransparent);
|
||||
|
||||
// Write extension record.
|
||||
writeExtension(gifFrame, frame, localTransparent,
|
||||
@ -1338,20 +1519,173 @@ private:
|
||||
GifFreeMapObject(colormap);
|
||||
}
|
||||
|
||||
Palette* createOptimizedPalette(const gfx::Rect& frameBounds) {
|
||||
Palette calculatePalette(const gfx::Rect& frameBounds,
|
||||
const DisposalMethod disposal) {
|
||||
// First, we must check the palette color count in m_deltaImage (our best shot
|
||||
// to find the smaller palette color count)
|
||||
Palette pal(createOptimizedPalette(m_deltaImage.get(), m_deltaImage->bounds(), 256));
|
||||
if (pal.size() == 256) {
|
||||
// Here the palette has 256 colors, there is no place to include
|
||||
// the 0 color (createOptimizedPalette() doesn't create an entry
|
||||
// for it).
|
||||
//
|
||||
// We have two paths:
|
||||
// 1- Giving a try to palette generation on m_currentImage in frameBouns limits.
|
||||
// 2- If the previous step is not possible (color count > 256), we will to start
|
||||
// to approximate colors from m_deltaImage with some criterion. Final target:
|
||||
// to approximate the palette to 255 colors + clear color (0)).
|
||||
|
||||
// 1- Giving a try to palette generation on m_currentImage in frameBouns limits.
|
||||
// if disposal == RESTORE_BGCOLOR m_deltaImage already is a cropped copy of m_currentImage.
|
||||
Palette auxPalette;
|
||||
if (disposal == DisposalMethod::DO_NOT_DISPOSE)
|
||||
auxPalette = createOptimizedPalette(m_currentImage, frameBounds, 257);
|
||||
else
|
||||
auxPalette = pal;
|
||||
|
||||
if (auxPalette.size() <= 256) {
|
||||
// We are fine with color count in m_currentImage contained in
|
||||
// frameBounds (we got 256 or less colors):
|
||||
m_transparentIndex = -1;
|
||||
pal = auxPalette;
|
||||
if (disposal == DisposalMethod::DO_NOT_DISPOSE) {
|
||||
ASSERT(frameBounds.w >= 1);
|
||||
m_deltaImage.reset(crop_image(m_currentImage, frameBounds, 0));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 2- If the previous step fails, we will to start to approximate colors from m_deltaImage
|
||||
// with some criterion:
|
||||
|
||||
// Final target: to approximate the palette to 255 colors + clear color (0)).
|
||||
// CRITERION:
|
||||
// Find a palette of 220 or less colors (in high precision) into the square border
|
||||
// contained in m_deltaImage, then into the center square quantize the remaining colors
|
||||
// to complete a palette of 255 colors, finally add the transparent color (0).
|
||||
//
|
||||
// m_currentImage__ __ m_deltaImage (same rectangle size as `frameBounds` variable)
|
||||
// | |
|
||||
// --------------*----|-----------
|
||||
// | | |
|
||||
// | --------------*- |
|
||||
// | | | |
|
||||
// | | ________ | |
|
||||
// | | | | *--------------- square border (we will collect
|
||||
// | | | | | | high precision colors from this area, less than 220)
|
||||
// | | | | | |
|
||||
// | | | *--------------------- center rectangle (we will to quantize
|
||||
// | | | | | | colors contained in this area)
|
||||
// | | |________| | |
|
||||
// | | | |
|
||||
// | |________________| |
|
||||
// | |
|
||||
// |_______________________________|
|
||||
//
|
||||
|
||||
const gfx::Size deltaSize = m_deltaImage->size();
|
||||
int thicknessTop = deltaSize.h / 4;
|
||||
int thicknessLeft = deltaSize.w / 4;
|
||||
int repeatCounter = 0;
|
||||
while (repeatCounter < 10 && thicknessTop > 0 && thicknessLeft > 0) {
|
||||
|
||||
// ----------------
|
||||
// |________________|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | |________| |
|
||||
// |________________|
|
||||
render::PaletteOptimizer optimizer;
|
||||
gfx::Rect auxRect(0, 0, deltaSize.w, thicknessTop);
|
||||
optimizer.feedWithImage(m_deltaImage.get(), auxRect, false);
|
||||
|
||||
// ----------------
|
||||
// | ________ |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |___|________|___|
|
||||
// |________________|
|
||||
auxRect = gfx::Rect(0, deltaSize.h - thicknessTop - 1, deltaSize.w, thicknessTop);
|
||||
optimizer.feedWithImage(m_deltaImage.get(), auxRect, false);
|
||||
|
||||
// ----------------
|
||||
// |____________ |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |___|________| |
|
||||
// |________________|
|
||||
auxRect = gfx::Rect(0, thicknessTop, thicknessLeft, deltaSize.h - 2 * thicknessTop);
|
||||
optimizer.feedWithImage(m_deltaImage.get(), auxRect, false);
|
||||
|
||||
// ----------------
|
||||
// | _____________|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | |________|___|
|
||||
// |________________|
|
||||
auxRect = gfx::Rect(deltaSize.w - thicknessLeft - 1, thicknessTop, thicknessLeft, deltaSize.h - 2 * thicknessTop);
|
||||
optimizer.feedWithImage(m_deltaImage.get(), auxRect, false);
|
||||
|
||||
int maxBorderColorCount = 220;
|
||||
if (optimizer.isHighPrecision() && (optimizer.highPrecisionSize() < maxBorderColorCount)) {
|
||||
pal.resize(optimizer.highPrecisionSize());
|
||||
optimizer.calculate(&pal, -1);
|
||||
break;
|
||||
}
|
||||
else if (thicknessTop <= 1 || thicknessLeft <= 1) {
|
||||
pal.resize(0);
|
||||
thicknessTop = 0;
|
||||
thicknessLeft = 0;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
thicknessTop -= thicknessTop / 2;
|
||||
thicknessLeft -= thicknessLeft / 2;
|
||||
}
|
||||
|
||||
repeatCounter++;
|
||||
}
|
||||
// Quantize the colors contained into center rectangle and add these in `pal`:
|
||||
if (pal.size() < 255) {
|
||||
gfx::Rect centerRect(thicknessLeft,
|
||||
thicknessTop,
|
||||
deltaSize.w - 2 * thicknessLeft,
|
||||
deltaSize.h - 2 * thicknessTop);
|
||||
Palette centerPalette(0, 255 - pal.size());
|
||||
centerPalette = createOptimizedPalette(m_deltaImage.get(),
|
||||
centerRect, 255 - pal.size());
|
||||
for (int i=0; i < centerPalette.size(); i++)
|
||||
pal.addEntry(centerPalette.getEntry(i));
|
||||
}
|
||||
// Finally add transparent color:
|
||||
ASSERT(pal.size() <= 255);
|
||||
pal.addEntry(0);
|
||||
m_transparentIndex = pal.size() - 1;
|
||||
}
|
||||
}
|
||||
// We are fine, we got 255 or less, there is room for the transparent color
|
||||
else if (pal.size() <= 255) {
|
||||
pal.addEntry(0);
|
||||
m_transparentIndex = pal.size() - 1;
|
||||
}
|
||||
return pal;
|
||||
}
|
||||
|
||||
static Palette createOptimizedPalette(const Image* image,
|
||||
const gfx::Rect& bounds,
|
||||
const int ncolors) {
|
||||
render::PaletteOptimizer optimizer;
|
||||
|
||||
// Feed the palette optimizer with pixels inside frameBounds
|
||||
for (const auto& color : LockImageBits<RgbTraits>(m_currentImage, frameBounds)) {
|
||||
if (rgba_geta(color) >= 128)
|
||||
// Feed the palette optimizer with pixels inside the given bounds
|
||||
for (const auto& color : LockImageBits<RgbTraits>(image, bounds)) {
|
||||
if (rgba_geta(color) >= 128) // Note: the mask color won't be part of the final palette
|
||||
optimizer.feedWithRgbaColor(
|
||||
rgba(rgba_getr(color),
|
||||
rgba_getg(color),
|
||||
rgba_getb(color), 255));
|
||||
}
|
||||
|
||||
Palette* palette = new Palette(0, 256);
|
||||
optimizer.calculate(palette, m_transparentIndex);
|
||||
Palette palette(0, ncolors);
|
||||
optimizer.calculate(&palette, -1);
|
||||
return palette;
|
||||
}
|
||||
|
||||
@ -1360,7 +1694,10 @@ private:
|
||||
render.setNewBlend(m_fop->newBlend());
|
||||
|
||||
render.setBgType(render::BgType::NONE);
|
||||
clear_image(dst, m_clearColor);
|
||||
if (m_preservePaletteOrder)
|
||||
clear_image(dst, m_bgIndex);
|
||||
else
|
||||
clear_image(dst, 0);
|
||||
render.renderSprite(dst, m_sprite, frame);
|
||||
}
|
||||
|
||||
@ -1398,18 +1735,23 @@ private:
|
||||
gfx::Rect m_spriteBounds;
|
||||
bool m_hasBackground;
|
||||
int m_bgIndex;
|
||||
color_t m_clearColor;
|
||||
int m_transparentIndex;
|
||||
int m_bitsPerPixel;
|
||||
// Global palette to use on all frames, or nullptr in case that we
|
||||
// have to quantize the palette on each frame.
|
||||
ColorMapObject* m_globalColormap;
|
||||
bool m_quantizeColormaps;
|
||||
Palette m_globalColormapPalette;
|
||||
bool m_interlaced;
|
||||
int m_loop;
|
||||
bool m_preservePaletteOrder;
|
||||
gfx::Rect m_lastFrameBounds;
|
||||
DisposalMethod m_lastDisposal;
|
||||
ImageBufferPtr m_frameImageBuf;
|
||||
ImageRef m_images[3];
|
||||
Image* m_previousImage;
|
||||
Image* m_currentImage;
|
||||
Image* m_nextImage;
|
||||
std::unique_ptr<Image> m_deltaImage;
|
||||
};
|
||||
|
||||
bool GifFormat::onSave(FileOp* fop)
|
||||
@ -1448,21 +1790,37 @@ FormatOptionsPtr GifFormat::onAskUserForFormatOptions(FileOp* fop)
|
||||
opts->setInterlaced(pref.gif.interlaced());
|
||||
if (pref.isSet(pref.gif.loop))
|
||||
opts->setLoop(pref.gif.loop());
|
||||
if (pref.isSet(pref.gif.preservePaletteOrder))
|
||||
opts->setPreservePaletteOrder(pref.gif.preservePaletteOrder());
|
||||
|
||||
if (pref.gif.showAlert()) {
|
||||
app::gen::GifOptions win;
|
||||
win.interlaced()->setSelected(opts->interlaced());
|
||||
win.loop()->setSelected(opts->loop());
|
||||
win.preservePaletteOrder()->setSelected(opts->preservePaletteOrder());
|
||||
|
||||
if (fop->document()->sprite()->pixelFormat() == PixelFormat::IMAGE_INDEXED &&
|
||||
!fop->document()->sprite()->isOpaque())
|
||||
win.preservePaletteOrder()->setEnabled(true);
|
||||
else {
|
||||
win.preservePaletteOrder()->setEnabled(false);
|
||||
if (fop->document()->sprite()->pixelFormat() == PixelFormat::IMAGE_INDEXED && fop->document()->sprite()->isOpaque())
|
||||
win.preservePaletteOrder()->setSelected(true);
|
||||
else
|
||||
win.preservePaletteOrder()->setSelected(false);
|
||||
}
|
||||
|
||||
win.openWindowInForeground();
|
||||
|
||||
if (win.closer() == win.ok()) {
|
||||
pref.gif.interlaced(win.interlaced()->isSelected());
|
||||
pref.gif.loop(win.loop()->isSelected());
|
||||
pref.gif.preservePaletteOrder(win.preservePaletteOrder()->isSelected());
|
||||
pref.gif.showAlert(!win.dontShow()->isSelected());
|
||||
|
||||
opts->setInterlaced(pref.gif.interlaced());
|
||||
opts->setLoop(pref.gif.loop());
|
||||
opts->setPreservePaletteOrder(pref.gif.preservePaletteOrder());
|
||||
}
|
||||
else {
|
||||
opts.reset();
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -18,20 +19,25 @@ namespace app {
|
||||
public:
|
||||
GifOptions(
|
||||
bool interlaced = false,
|
||||
bool loop = true)
|
||||
bool loop = true,
|
||||
bool preservePaletteOrder = true)
|
||||
: m_interlaced(interlaced)
|
||||
, m_loop(loop) {
|
||||
, m_loop(loop)
|
||||
, m_preservePaletteOrder(preservePaletteOrder) {
|
||||
}
|
||||
|
||||
bool interlaced() const { return m_interlaced; }
|
||||
bool loop() const { return m_loop; }
|
||||
bool preservePaletteOrder() const { return m_preservePaletteOrder; }
|
||||
|
||||
void setInterlaced(bool interlaced) { m_interlaced = interlaced; }
|
||||
void setLoop(bool loop) { m_loop = loop; }
|
||||
void setPreservePaletteOrder(bool preservePaletteOrder) {m_preservePaletteOrder = preservePaletteOrder; }
|
||||
|
||||
private:
|
||||
bool m_interlaced;
|
||||
bool m_loop;
|
||||
bool m_preservePaletteOrder;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -69,7 +69,7 @@ class JpegFormat : public FileFormat {
|
||||
}
|
||||
|
||||
bool onLoad(FileOp* fop) override;
|
||||
gfx::ColorSpacePtr loadColorSpace(FileOp* fop, jpeg_decompress_struct* dinfo);
|
||||
gfx::ColorSpaceRef loadColorSpace(FileOp* fop, jpeg_decompress_struct* dinfo);
|
||||
#ifdef ENABLE_SAVE
|
||||
bool onSave(FileOp* fop) override;
|
||||
void saveColorSpace(FileOp* fop, jpeg_compress_struct* cinfo,
|
||||
@ -256,7 +256,7 @@ bool JpegFormat::onLoad(FileOp* fop)
|
||||
}
|
||||
|
||||
// Read color space
|
||||
gfx::ColorSpacePtr colorSpace = loadColorSpace(fop, &dinfo);
|
||||
gfx::ColorSpaceRef colorSpace = loadColorSpace(fop, &dinfo);
|
||||
if (colorSpace)
|
||||
fop->setEmbeddedColorProfile();
|
||||
else { // sRGB is the default JPG color space.
|
||||
@ -282,7 +282,7 @@ bool JpegFormat::onLoad(FileOp* fop)
|
||||
// in two steps:
|
||||
// (1) Discover all ICC profile markers and verify that they are numbered properly.
|
||||
// (2) Copy the data from each marker into a contiguous ICC profile.
|
||||
gfx::ColorSpacePtr JpegFormat::loadColorSpace(FileOp* fop, jpeg_decompress_struct* dinfo)
|
||||
gfx::ColorSpaceRef JpegFormat::loadColorSpace(FileOp* fop, jpeg_decompress_struct* dinfo)
|
||||
{
|
||||
// Note that 256 will be enough storage space since each markerIndex is stored in 8-bits.
|
||||
jpeg_marker_struct* markerSequence[256];
|
||||
|
@ -59,7 +59,7 @@ class PngFormat : public FileFormat {
|
||||
}
|
||||
|
||||
bool onLoad(FileOp* fop) override;
|
||||
gfx::ColorSpacePtr loadColorSpace(png_structp png, png_infop info);
|
||||
gfx::ColorSpaceRef loadColorSpace(png_structp png, png_infop info);
|
||||
#ifdef ENABLE_SAVE
|
||||
bool onSave(FileOp* fop) override;
|
||||
void saveColorSpace(png_structp png, png_infop info, const gfx::ColorSpace* colorSpace);
|
||||
@ -457,7 +457,7 @@ bool PngFormat::onLoad(FileOp* fop)
|
||||
//
|
||||
// Code to read color spaces from png files from Skia (SkPngCodec.cpp)
|
||||
// by Google Inc.
|
||||
gfx::ColorSpacePtr PngFormat::loadColorSpace(png_structp png_ptr, png_infop info_ptr)
|
||||
gfx::ColorSpaceRef PngFormat::loadColorSpace(png_structp png_ptr, png_infop info_ptr)
|
||||
{
|
||||
// First check for an ICC profile
|
||||
png_bytep profile;
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "app/file/webp_options.h"
|
||||
#include "app/ini_file.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/clamp.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/file_handle.h"
|
||||
@ -421,7 +420,7 @@ FormatOptionsPtr WebPFormat::onAskUserForFormatOptions(FileOp* fop)
|
||||
win.imagePreset()->setSelectedItemIndex(opts->imagePreset());
|
||||
|
||||
updatePanels();
|
||||
win.type()->Change.connect(base::Bind<void>(updatePanels));
|
||||
win.type()->Change.connect(updatePanels);
|
||||
|
||||
win.openWindowInForeground();
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -31,8 +32,8 @@ bool show_file_selector(
|
||||
|
||||
if (Preferences::instance().experimental.useNativeFileDialog() &&
|
||||
os::instance()->nativeDialogs()) {
|
||||
os::FileDialog* dlg =
|
||||
os::instance()->nativeDialogs()->createFileDialog();
|
||||
os::FileDialogRef dlg =
|
||||
os::instance()->nativeDialogs()->makeFileDialog();
|
||||
|
||||
if (dlg) {
|
||||
dlg->setTitle(title);
|
||||
@ -65,7 +66,6 @@ bool show_file_selector(
|
||||
else
|
||||
output.push_back(dlg->fileName());
|
||||
}
|
||||
dlg->dispose();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ namespace app {
|
||||
namespace {
|
||||
|
||||
class FileItem;
|
||||
typedef std::map<std::string, FileItem*> FileItemMap;
|
||||
using FileItemMap = std::map<std::string, FileItem*>;
|
||||
|
||||
// the root of the file-system
|
||||
FileItem* rootitem = nullptr;
|
||||
@ -121,8 +121,8 @@ public:
|
||||
m_thumbnailProgress = progress;
|
||||
}
|
||||
|
||||
os::Surface* getThumbnail() override;
|
||||
void setThumbnail(os::Surface* thumbnail) override;
|
||||
os::SurfaceRef getThumbnail() override;
|
||||
void setThumbnail(const os::SurfaceRef& thumbnail) override;
|
||||
|
||||
// Calls "delete this"
|
||||
void deleteItem() {
|
||||
@ -586,16 +586,21 @@ bool FileItem::hasExtension(const base::paths& extensions)
|
||||
return base::has_file_extension(m_filename, extensions);
|
||||
}
|
||||
|
||||
os::Surface* FileItem::getThumbnail()
|
||||
os::SurfaceRef FileItem::getThumbnail()
|
||||
{
|
||||
return m_thumbnail;
|
||||
os::SurfaceRef ref(m_thumbnail.load());
|
||||
if (ref)
|
||||
ref->ref(); // base::Ref(T*) doesn't add an extra reference
|
||||
return ref;
|
||||
}
|
||||
|
||||
void FileItem::setThumbnail(os::Surface* thumbnail)
|
||||
void FileItem::setThumbnail(const os::SurfaceRef& newThumbnail)
|
||||
{
|
||||
auto old = m_thumbnail.exchange(thumbnail);
|
||||
if (newThumbnail)
|
||||
newThumbnail->ref();
|
||||
auto old = m_thumbnail.exchange(newThumbnail.get());
|
||||
if (old)
|
||||
old->dispose();
|
||||
old->unref();
|
||||
}
|
||||
|
||||
FileItem::FileItem(FileItem* parent)
|
||||
@ -621,8 +626,7 @@ FileItem::~FileItem()
|
||||
{
|
||||
FS_TRACE("FS: Destroying FileItem() with parent %p\n", m_parent);
|
||||
|
||||
if (auto ptr = m_thumbnail.load())
|
||||
ptr->dispose();
|
||||
m_thumbnail.exchange(nullptr);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (m_fullpidl && m_fullpidl != m_pidl) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -12,19 +12,15 @@
|
||||
#include "base/mutex.h"
|
||||
#include "base/paths.h"
|
||||
#include "obs/signal.h"
|
||||
#include "os/surface.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace os {
|
||||
class Surface;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
|
||||
class IFileItem;
|
||||
|
||||
typedef std::vector<IFileItem*> FileItemList;
|
||||
using FileItemList = std::vector<IFileItem*>;
|
||||
|
||||
class FileSystemModule {
|
||||
static FileSystemModule* m_instance;
|
||||
@ -91,8 +87,8 @@ namespace app {
|
||||
virtual double getThumbnailProgress() = 0;
|
||||
virtual void setThumbnailProgress(double progress) = 0;
|
||||
|
||||
virtual os::Surface* getThumbnail() = 0;
|
||||
virtual void setThumbnail(os::Surface* thumbnail) = 0;
|
||||
virtual os::SurfaceRef getThumbnail() = 0;
|
||||
virtual void setThumbnail(const os::SurfaceRef& thumbnail) = 0;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -96,9 +96,9 @@ protected:
|
||||
void saveLayout(Widget* widget, const std::string& str) override;
|
||||
};
|
||||
|
||||
static os::Display* main_display = NULL;
|
||||
static CustomizedGuiManager* manager = NULL;
|
||||
static Theme* gui_theme = NULL;
|
||||
static os::DisplayRef main_display = nullptr;
|
||||
static CustomizedGuiManager* manager = nullptr;
|
||||
static Theme* gui_theme = nullptr;
|
||||
|
||||
static ui::Timer* defered_invalid_timer = nullptr;
|
||||
static gfx::Region defered_invalid_region;
|
||||
@ -124,7 +124,7 @@ static bool create_main_display(bool gpuAccel,
|
||||
|
||||
try {
|
||||
if (w > 0 && h > 0) {
|
||||
main_display = os::instance()->createDisplay(
|
||||
main_display = os::instance()->makeDisplay(
|
||||
w, h, (scale == 0 ? 2: base::clamp(scale, 1, 4)));
|
||||
}
|
||||
}
|
||||
@ -136,7 +136,7 @@ static bool create_main_display(bool gpuAccel,
|
||||
for (int c=0; try_resolutions[c].width; ++c) {
|
||||
try {
|
||||
main_display =
|
||||
os::instance()->createDisplay(
|
||||
os::instance()->makeDisplay(
|
||||
try_resolutions[c].width,
|
||||
try_resolutions[c].height,
|
||||
(scale == 0 ? try_resolutions[c].scale: scale));
|
||||
@ -193,7 +193,7 @@ int init_module_gui()
|
||||
|
||||
// Create the default-manager
|
||||
manager = new CustomizedGuiManager();
|
||||
manager->setDisplay(main_display);
|
||||
manager->setDisplay(main_display.get());
|
||||
|
||||
// Setup the GUI theme for all widgets
|
||||
gui_theme = new SkinTheme;
|
||||
@ -221,7 +221,8 @@ void exit_module_gui()
|
||||
ui::set_theme(nullptr, ui::guiscale());
|
||||
delete gui_theme;
|
||||
|
||||
main_display->dispose();
|
||||
// This should be the last unref() of the display to delete it.
|
||||
main_display.reset();
|
||||
}
|
||||
|
||||
void update_displays_color_profile_from_preferences()
|
||||
@ -240,13 +241,13 @@ void update_displays_color_profile_from_preferences()
|
||||
break;
|
||||
case gen::WindowColorProfile::SRGB:
|
||||
system->setDisplaysColorSpace(
|
||||
system->createColorSpace(gfx::ColorSpace::MakeSRGB()));
|
||||
system->makeColorSpace(gfx::ColorSpace::MakeSRGB()));
|
||||
break;
|
||||
case gen::WindowColorProfile::SPECIFIC: {
|
||||
std::string name =
|
||||
Preferences::instance().color.windowProfileName();
|
||||
|
||||
std::vector<os::ColorSpacePtr> colorSpaces;
|
||||
std::vector<os::ColorSpaceRef> colorSpaces;
|
||||
system->listColorSpaces(colorSpaces);
|
||||
|
||||
for (auto& cs : colorSpaces) {
|
||||
|
@ -54,6 +54,14 @@ Preferences::Preferences()
|
||||
|
||||
load();
|
||||
|
||||
// Create a connection with the default RgbMapAlgorithm preferences
|
||||
// to change the default algorithm in the "doc" layer.
|
||||
experimental.rgbmapAlgorithm.AfterChange.connect(
|
||||
[](const doc::RgbMapAlgorithm& newValue){
|
||||
doc::Sprite::SetDefaultRgbMapAlgorithm(newValue);
|
||||
});
|
||||
doc::Sprite::SetDefaultRgbMapAlgorithm(experimental.rgbmapAlgorithm());
|
||||
|
||||
// Create a connection with the default document preferences grid
|
||||
// bounds to sync the default grid bounds for new sprites in the
|
||||
// "doc" layer.
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "doc/color_mode.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/layer_list.h"
|
||||
#include "doc/rgbmap_algorithm.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "filters/hue_saturation_filter.h"
|
||||
#include "filters/tiled_mode.h"
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include "app/res/http_loader.h"
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/fstream_path.h"
|
||||
#include "base/replace_string.h"
|
||||
@ -29,7 +28,7 @@ HttpLoader::HttpLoader(const std::string& url)
|
||||
: m_url(url)
|
||||
, m_done(false)
|
||||
, m_request(nullptr)
|
||||
, m_thread(base::Bind<void>(&HttpLoader::threadHttpRequest, this))
|
||||
, m_thread([this]{ threadHttpRequest(); })
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -17,7 +17,6 @@
|
||||
#include "app/file_system.h"
|
||||
#include "app/res/palette_resource.h"
|
||||
#include "app/resource_finder.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/scoped_value.h"
|
||||
#include "doc/palette.h"
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -14,7 +15,6 @@
|
||||
#include "app/res/resource.h"
|
||||
#include "app/res/resources_loader_delegate.h"
|
||||
#include "app/resource_finder.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/scoped_value.h"
|
||||
|
||||
@ -24,9 +24,7 @@ ResourcesLoader::ResourcesLoader(ResourcesLoaderDelegate* delegate)
|
||||
: m_delegate(delegate)
|
||||
, m_done(false)
|
||||
, m_cancel(false)
|
||||
, m_thread(
|
||||
new base::thread(
|
||||
base::Bind<void>(&ResourcesLoader::threadLoadResources, this)))
|
||||
, m_thread(new base::thread([this]{ threadLoadResources(); }))
|
||||
{
|
||||
}
|
||||
|
||||
@ -87,8 +85,7 @@ void ResourcesLoader::threadLoadResources()
|
||||
|
||||
base::thread* ResourcesLoader::createThread()
|
||||
{
|
||||
return new base::thread(
|
||||
base::Bind<void>(&ResourcesLoader::threadLoadResources, this));
|
||||
return new base::thread([this]{ threadLoadResources(); });
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "app/ui/color_shades.h"
|
||||
#include "app/ui/expr_entry.h"
|
||||
#include "app/ui/filename_field.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/paths.h"
|
||||
#include "ui/box.h"
|
||||
#include "ui/button.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (c) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -115,7 +115,7 @@ int ImageSpec_set_colorSpace(lua_State* L)
|
||||
{
|
||||
auto spec = get_obj<doc::ImageSpec>(L, 1);
|
||||
auto cs = get_obj<gfx::ColorSpace>(L, 2);
|
||||
spec->setColorSpace(std::make_shared<gfx::ColorSpace>(*cs));
|
||||
spec->setColorSpace(base::make_ref<gfx::ColorSpace>(*cs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2015-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -294,7 +294,7 @@ int Sprite_assignColorSpace(lua_State* L)
|
||||
auto cs = get_obj<gfx::ColorSpace>(L, 2);
|
||||
Tx tx;
|
||||
tx(new cmd::AssignColorProfile(
|
||||
sprite, std::make_shared<gfx::ColorSpace>(*cs)));
|
||||
sprite, base::make_ref<gfx::ColorSpace>(*cs)));
|
||||
tx.commit();
|
||||
return 1;
|
||||
}
|
||||
@ -305,7 +305,7 @@ int Sprite_convertColorSpace(lua_State* L)
|
||||
auto cs = get_obj<gfx::ColorSpace>(L, 2);
|
||||
Tx tx;
|
||||
tx(new cmd::ConvertColorProfile(
|
||||
sprite, std::make_shared<gfx::ColorSpace>(*cs)));
|
||||
sprite, base::make_ref<gfx::ColorSpace>(*cs)));
|
||||
tx.commit();
|
||||
return 1;
|
||||
}
|
||||
|
@ -184,6 +184,7 @@ FOR_ENUM(app::tools::RotationAlgorithm)
|
||||
FOR_ENUM(doc::AniDir)
|
||||
FOR_ENUM(doc::BrushPattern)
|
||||
FOR_ENUM(doc::ColorMode)
|
||||
FOR_ENUM(doc::RgbMapAlgorithm)
|
||||
FOR_ENUM(filters::HueSaturationFilter::Mode)
|
||||
FOR_ENUM(filters::TiledMode)
|
||||
FOR_ENUM(render::OnionskinPosition)
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "app/i18n/strings.h"
|
||||
#include "app/resource_finder.h"
|
||||
#include "app/task.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/launcher.h"
|
||||
#include "fmt/format.h"
|
||||
@ -139,7 +138,7 @@ void SendCrash::notificationClick()
|
||||
if (isDev) {
|
||||
dlg.official()->setVisible(false);
|
||||
dlg.devFilename()->setText(m_dumpFilename);
|
||||
dlg.devFilename()->Click.connect(base::Bind(&SendCrash::onClickDevFilename, this));
|
||||
dlg.devFilename()->Click.connect([this]{ onClickDevFilename(); });
|
||||
}
|
||||
else
|
||||
#endif // On other platforms the crash file might be useful even in
|
||||
@ -148,7 +147,7 @@ void SendCrash::notificationClick()
|
||||
{
|
||||
dlg.dev()->setVisible(false);
|
||||
dlg.filename()->setText(m_dumpFilename);
|
||||
dlg.filename()->Click.connect(base::Bind(&SendCrash::onClickFilename, this));
|
||||
dlg.filename()->Click.connect([this]{ onClickFilename(); });
|
||||
}
|
||||
|
||||
dlg.openWindowInForeground();
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "app/file/file.h"
|
||||
#include "app/file_system.h"
|
||||
#include "app/util/conversion_to_surface.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/clamp.h"
|
||||
#include "base/scoped_lock.h"
|
||||
#include "base/thread.h"
|
||||
@ -46,7 +45,7 @@ public:
|
||||
: m_queue(queue)
|
||||
, m_fop(nullptr)
|
||||
, m_isDone(false)
|
||||
, m_thread(base::Bind<void>(&Worker::loadBgThread, this)) {
|
||||
, m_thread([this]{ loadBgThread(); }) {
|
||||
}
|
||||
|
||||
~Worker() {
|
||||
@ -159,13 +158,13 @@ private:
|
||||
|
||||
// Set the thumbnail of the file-item.
|
||||
if (thumbnailImage) {
|
||||
os::Surface* thumbnail =
|
||||
os::instance()->createRgbaSurface(
|
||||
os::SurfaceRef thumbnail =
|
||||
os::instance()->makeRgbaSurface(
|
||||
thumbnailImage->width(),
|
||||
thumbnailImage->height());
|
||||
|
||||
convert_image_to_surface(
|
||||
thumbnailImage.get(), palette.get(), thumbnail,
|
||||
thumbnailImage.get(), palette.get(), thumbnail.get(),
|
||||
0, 0, 0, 0, thumbnailImage->width(), thumbnailImage->height());
|
||||
|
||||
{
|
||||
@ -226,7 +225,7 @@ ThumbnailGenerator* ThumbnailGenerator::instance()
|
||||
static ThumbnailGenerator* singleton = nullptr;
|
||||
if (singleton == NULL) {
|
||||
singleton = new ThumbnailGenerator();
|
||||
App::instance()->Exit.connect(base::Bind<void>(&delete_singleton, singleton));
|
||||
App::instance()->Exit.connect([&]{ delete_singleton(singleton); });
|
||||
}
|
||||
return singleton;
|
||||
}
|
||||
|
@ -22,8 +22,8 @@
|
||||
namespace app {
|
||||
namespace thumb {
|
||||
|
||||
os::Surface* get_cel_thumbnail(const doc::Cel* cel,
|
||||
const gfx::Size& fitInSize)
|
||||
os::SurfaceRef get_cel_thumbnail(const doc::Cel* cel,
|
||||
const gfx::Size& fitInSize)
|
||||
{
|
||||
gfx::Size newSize;
|
||||
|
||||
@ -57,11 +57,11 @@ os::Surface* get_cel_thumbnail(const doc::Cel* cel,
|
||||
gfx::Clip(gfx::Rect(gfx::Point(0, 0), newSize)),
|
||||
255, doc::BlendMode::NORMAL);
|
||||
|
||||
if (os::Surface* thumbnail = os::instance()->createRgbaSurface(
|
||||
if (os::SurfaceRef thumbnail = os::instance()->makeRgbaSurface(
|
||||
thumbnailImage->width(),
|
||||
thumbnailImage->height())) {
|
||||
convert_image_to_surface(
|
||||
thumbnailImage.get(), palette, thumbnail,
|
||||
thumbnailImage.get(), palette, thumbnail.get(),
|
||||
0, 0, 0, 0, thumbnailImage->width(), thumbnailImage->height());
|
||||
return thumbnail;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2016 Carlo Caputo
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -10,6 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "gfx/size.h"
|
||||
#include "os/surface.h"
|
||||
|
||||
namespace doc {
|
||||
class Cel;
|
||||
@ -22,8 +23,8 @@ namespace os {
|
||||
namespace app {
|
||||
namespace thumb {
|
||||
|
||||
os::Surface* get_cel_thumbnail(const doc::Cel* cel,
|
||||
const gfx::Size& fitInSize);
|
||||
os::SurfaceRef get_cel_thumbnail(const doc::Cel* cel,
|
||||
const gfx::Size& fitInSize);
|
||||
|
||||
} // thumb
|
||||
} // app
|
||||
|
@ -292,10 +292,7 @@ public:
|
||||
c = m_palette->getEntry(c);
|
||||
|
||||
c = rgba_blender_normal(c, m_color, m_opacity);
|
||||
*m_dstAddress = m_rgbmap->mapColor(rgba_getr(c),
|
||||
rgba_getg(c),
|
||||
rgba_getb(c),
|
||||
rgba_geta(c));
|
||||
*m_dstAddress = m_rgbmap->mapColor(c);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -365,10 +362,7 @@ public:
|
||||
c = m_palette->getEntry(c);
|
||||
|
||||
c = rgba_blender_merge(c, m_color, m_opacity);
|
||||
*m_dstAddress = m_rgbmap->mapColor(rgba_getr(c),
|
||||
rgba_getg(c),
|
||||
rgba_getb(c),
|
||||
rgba_geta(c));
|
||||
*m_dstAddress = m_rgbmap->mapColor(c);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -520,8 +514,7 @@ public:
|
||||
doc::rgba(m_area.r, m_area.g, m_area.b, m_area.a),
|
||||
m_opacity);
|
||||
|
||||
*m_dstAddress = m_rgbmap->mapColor(
|
||||
rgba_getr(c), rgba_getg(c), rgba_getb(c), rgba_geta(c));
|
||||
*m_dstAddress = m_rgbmap->mapColor(c);
|
||||
}
|
||||
else {
|
||||
*m_dstAddress = *m_srcAddress;
|
||||
@ -633,8 +626,7 @@ public:
|
||||
color_t c = rgba_blender_normal(
|
||||
m_palette->getEntry(*m_srcAddress), m_color2, m_opacity);
|
||||
|
||||
*m_dstAddress = m_rgbmap->mapColor(
|
||||
rgba_getr(c), rgba_getg(c), rgba_getb(c), rgba_geta(c));
|
||||
*m_dstAddress = m_rgbmap->mapColor(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -721,10 +713,7 @@ void JumbleInkProcessing<IndexedTraits>::processPixel(int x, int y)
|
||||
tc, m_opacity);
|
||||
|
||||
if (rgba_geta(c) >= 128)
|
||||
*m_dstAddress = m_rgbmap->mapColor(rgba_getr(c),
|
||||
rgba_getg(c),
|
||||
rgba_getb(c),
|
||||
rgba_geta(c));
|
||||
*m_dstAddress = m_rgbmap->mapColor(c);
|
||||
else
|
||||
*m_dstAddress = 0;
|
||||
}
|
||||
@ -1060,10 +1049,7 @@ void GradientInkProcessing<IndexedTraits>::processPixel(int x, int y)
|
||||
c0 = m_palette->getEntry(c0);
|
||||
c = rgba_blender_normal(c0, c, m_opacity);
|
||||
|
||||
*m_dstAddress = m_rgbmap->mapColor(rgba_getr(c),
|
||||
rgba_getg(c),
|
||||
rgba_getb(c),
|
||||
rgba_geta(c));
|
||||
*m_dstAddress = m_rgbmap->mapColor(c);
|
||||
|
||||
++m_tmpAddress;
|
||||
}
|
||||
@ -1108,10 +1094,7 @@ public:
|
||||
|
||||
void processPixel(int x, int y) {
|
||||
color_t c = rgba_blender_neg_bw(m_palette->getEntry(*m_srcAddress), m_color, 255);
|
||||
*m_dstAddress = m_rgbmap->mapColor(rgba_getr(c),
|
||||
rgba_getg(c),
|
||||
rgba_getb(c),
|
||||
rgba_geta(c));
|
||||
*m_dstAddress = m_rgbmap->mapColor(c);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "app/tools/stroke.h"
|
||||
#include "app/tools/tool_group.h"
|
||||
#include "app/tools/tool_loop.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/exception.h"
|
||||
#include "doc/algo.h"
|
||||
#include "doc/algorithm/floodfill.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -25,8 +25,7 @@
|
||||
#include "ui/widget.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace app {
|
||||
|
||||
@ -47,18 +46,6 @@ AppMenuItem::AppMenuItem(const std::string& text,
|
||||
{
|
||||
}
|
||||
|
||||
AppMenuItem::~AppMenuItem()
|
||||
{
|
||||
if (m_native) {
|
||||
// Do not call disposeNative(), the native handle will be disposed
|
||||
// when the main menu (app menu) is disposed.
|
||||
|
||||
// TODO improve handling of these kind of pointer from laf-os library
|
||||
|
||||
delete m_native;
|
||||
}
|
||||
}
|
||||
|
||||
void AppMenuItem::setKey(const KeyPtr& key)
|
||||
{
|
||||
m_key = key;
|
||||
@ -68,23 +55,14 @@ void AppMenuItem::setKey(const KeyPtr& key)
|
||||
void AppMenuItem::setNative(const Native& native)
|
||||
{
|
||||
if (!m_native)
|
||||
m_native = new Native(native);
|
||||
else {
|
||||
// Do not call disposeNative(), the native handle will be disposed
|
||||
// when the main menu (app menu) is disposed.
|
||||
|
||||
m_native.reset(new Native(native));
|
||||
else
|
||||
*m_native = native;
|
||||
}
|
||||
}
|
||||
|
||||
void AppMenuItem::disposeNative()
|
||||
{
|
||||
#if 0 // TODO fix this and the whole handling of native menu items from laf-os
|
||||
if (m_native->menuItem) {
|
||||
m_native->menuItem->dispose();
|
||||
m_native->menuItem = nullptr;
|
||||
}
|
||||
#endif
|
||||
m_native.reset();
|
||||
}
|
||||
|
||||
void AppMenuItem::syncNativeMenuItemKeyShortcut()
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -10,12 +11,11 @@
|
||||
|
||||
#include "app/commands/params.h"
|
||||
#include "app/ui/key.h"
|
||||
#include "os/menus.h"
|
||||
#include "os/shortcut.h"
|
||||
#include "ui/menu.h"
|
||||
|
||||
namespace os {
|
||||
class MenuItem;
|
||||
}
|
||||
#include <memory>
|
||||
|
||||
namespace app {
|
||||
class Command;
|
||||
@ -28,7 +28,7 @@ namespace app {
|
||||
class AppMenuItem : public ui::MenuItem {
|
||||
public:
|
||||
struct Native {
|
||||
os::MenuItem* menuItem = nullptr;
|
||||
os::MenuItemRef menuItem = nullptr;
|
||||
os::Shortcut shortcut;
|
||||
app::KeyContext keyContext = app::KeyContext::Any;
|
||||
};
|
||||
@ -36,7 +36,6 @@ namespace app {
|
||||
AppMenuItem(const std::string& text,
|
||||
Command* command = nullptr,
|
||||
const Params& params = Params());
|
||||
~AppMenuItem();
|
||||
|
||||
KeyPtr key() { return m_key; }
|
||||
void setKey(const KeyPtr& key);
|
||||
@ -47,7 +46,7 @@ namespace app {
|
||||
Command* getCommand() { return m_command; }
|
||||
const Params& getParams() const { return m_params; }
|
||||
|
||||
Native* native() { return m_native; }
|
||||
Native* native() const { return m_native.get(); }
|
||||
void setNative(const Native& native);
|
||||
void disposeNative();
|
||||
void syncNativeMenuItemKeyShortcut();
|
||||
@ -65,7 +64,7 @@ namespace app {
|
||||
Command* m_command;
|
||||
Params m_params;
|
||||
bool m_isRecentFileItem;
|
||||
Native* m_native;
|
||||
std::unique_ptr<Native> m_native;
|
||||
|
||||
static Params s_contextParams;
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -11,7 +12,6 @@
|
||||
#include "app/ui/backup_indicator.h"
|
||||
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "base/bind.h"
|
||||
#include "ui/manager.h"
|
||||
|
||||
namespace app {
|
||||
@ -21,7 +21,7 @@ BackupIndicator::BackupIndicator()
|
||||
, m_small(false)
|
||||
, m_running(false)
|
||||
{
|
||||
m_timer.Tick.connect(base::Bind<void>(&BackupIndicator::onTick, this));
|
||||
m_timer.Tick.connect([this]{ onTick(); });
|
||||
}
|
||||
|
||||
BackupIndicator::~BackupIndicator()
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "app/util/conversion_to_surface.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "doc/brush.h"
|
||||
#include "doc/image.h"
|
||||
@ -444,7 +443,7 @@ void BrushPopup::onBrushChanges()
|
||||
}
|
||||
|
||||
// static
|
||||
os::Surface* BrushPopup::createSurfaceForBrush(const BrushRef& origBrush)
|
||||
os::SurfaceRef BrushPopup::createSurfaceForBrush(const BrushRef& origBrush)
|
||||
{
|
||||
Image* image = nullptr;
|
||||
BrushRef brush = origBrush;
|
||||
@ -456,7 +455,7 @@ os::Surface* BrushPopup::createSurfaceForBrush(const BrushRef& origBrush)
|
||||
image = brush->image();
|
||||
}
|
||||
|
||||
os::Surface* surface = os::instance()->createRgbaSurface(
|
||||
os::SurfaceRef surface = os::instance()->makeRgbaSurface(
|
||||
std::min(10, image ? image->width(): 4),
|
||||
std::min(10, image ? image->height(): 4));
|
||||
|
||||
@ -469,7 +468,7 @@ os::Surface* BrushPopup::createSurfaceForBrush(const BrushRef& origBrush)
|
||||
}
|
||||
|
||||
convert_image_to_surface(
|
||||
image, palette, surface,
|
||||
image, palette, surface.get(),
|
||||
0, 0, 0, 0, image->width(), image->height());
|
||||
|
||||
if (image->pixelFormat() == IMAGE_BITMAP)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -23,7 +23,7 @@ namespace app {
|
||||
void setBrush(doc::Brush* brush);
|
||||
void regenerate(const gfx::Rect& box);
|
||||
|
||||
static os::Surface* createSurfaceForBrush(const doc::BrushRef& brush);
|
||||
static os::SurfaceRef createSurfaceForBrush(const doc::BrushRef& brush);
|
||||
|
||||
private:
|
||||
void onStandardBrush();
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "base/bind.h"
|
||||
#include "gfx/color.h"
|
||||
#include "os/surface.h"
|
||||
#include "ui/box.h"
|
||||
@ -160,7 +159,7 @@ void ButtonSet::Item::onPaint(ui::PaintEvent& ev)
|
||||
}
|
||||
|
||||
if (hasText()) {
|
||||
g->setFont(font());
|
||||
g->setFont(AddRef(font()));
|
||||
g->drawUIText(text(), fg, gfx::ColorNone, textRc.origin(), 0);
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,6 @@
|
||||
#include "app/ui_context.h"
|
||||
#include "app/util/cel_ops.h"
|
||||
#include "app/util/clipboard.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/clamp.h"
|
||||
#include "base/scoped_value.h"
|
||||
#include "doc/cel.h"
|
||||
@ -257,18 +256,18 @@ ColorBar::ColorBar(int align, TooltipManager* tooltipManager)
|
||||
m_fgColor.setExpansive(true);
|
||||
m_bgColor.setExpansive(true);
|
||||
|
||||
m_remapPalButton.Click.connect(base::Bind<void>(&ColorBar::onRemapPalButtonClick, this));
|
||||
m_remapTilesButton.Click.connect(base::Bind<void>(&ColorBar::onRemapTilesButtonClick, this));
|
||||
m_remapPalButton.Click.connect([this]{ onRemapPalButtonClick(); });
|
||||
m_remapTilesButton.Click.connect([this]{ onRemapTilesButtonClick(); });
|
||||
m_fgColor.Change.connect(&ColorBar::onFgColorButtonChange, this);
|
||||
m_fgColor.BeforeChange.connect(&ColorBar::onFgColorButtonBeforeChange, this);
|
||||
m_bgColor.Change.connect(&ColorBar::onBgColorButtonChange, this);
|
||||
m_fgWarningIcon->Click.connect(base::Bind<void>(&ColorBar::onFixWarningClick, this, &m_fgColor, m_fgWarningIcon));
|
||||
m_bgWarningIcon->Click.connect(base::Bind<void>(&ColorBar::onFixWarningClick, this, &m_bgColor, m_bgWarningIcon));
|
||||
m_redrawTimer.Tick.connect(base::Bind<void>(&ColorBar::onTimerTick, this));
|
||||
m_editPal.ItemChange.connect(base::Bind<void>(&ColorBar::onSwitchPalEditMode, this));
|
||||
m_buttons.ItemChange.connect(base::Bind<void>(&ColorBar::onPaletteButtonClick, this));
|
||||
m_tilesButton.ItemChange.connect(base::Bind<void>(&ColorBar::onTilesButtonClick, this));
|
||||
m_tilesetModeButtons.ItemChange.connect(base::Bind<void>(&ColorBar::onTilesetModeButtonClick, this));
|
||||
m_fgWarningIcon->Click.connect([this]{ onFixWarningClick(&m_fgColor, m_fgWarningIcon); });
|
||||
m_bgWarningIcon->Click.connect([this]{ onFixWarningClick(&m_bgColor, m_bgWarningIcon); });
|
||||
m_redrawTimer.Tick.connect([this]{ onTimerTick(); });
|
||||
m_editPal.ItemChange.connect([this]{ onSwitchPalEditMode(); });
|
||||
m_buttons.ItemChange.connect([this]{ onPaletteButtonClick(); });
|
||||
m_tilesButton.ItemChange.connect([this]{ onTilesButtonClick(); });
|
||||
m_tilesetModeButtons.ItemChange.connect([this]{ onTilesetModeButtonClick(); });
|
||||
|
||||
InitTheme.connect(
|
||||
[this, fgBox, bgBox]{
|
||||
@ -334,14 +333,14 @@ ColorBar::ColorBar(int align, TooltipManager* tooltipManager)
|
||||
UIContext::instance()->add_observer(this);
|
||||
m_beforeCmdConn = UIContext::instance()->BeforeCommandExecution.connect(&ColorBar::onBeforeExecuteCommand, this);
|
||||
m_afterCmdConn = UIContext::instance()->AfterCommandExecution.connect(&ColorBar::onAfterExecuteCommand, this);
|
||||
m_fgConn = Preferences::instance().colorBar.fgColor.AfterChange.connect(base::Bind<void>(&ColorBar::onFgColorChangeFromPreferences, this));
|
||||
m_bgConn = Preferences::instance().colorBar.bgColor.AfterChange.connect(base::Bind<void>(&ColorBar::onBgColorChangeFromPreferences, this));
|
||||
m_sepConn = Preferences::instance().colorBar.entriesSeparator.AfterChange.connect(base::Bind<void>(&ColorBar::invalidate, this));
|
||||
m_fgConn = Preferences::instance().colorBar.fgColor.AfterChange.connect([this]{ onFgColorChangeFromPreferences(); });
|
||||
m_bgConn = Preferences::instance().colorBar.bgColor.AfterChange.connect([this]{ onBgColorChangeFromPreferences(); });
|
||||
m_sepConn = Preferences::instance().colorBar.entriesSeparator.AfterChange.connect([this]{ invalidate(); });
|
||||
m_paletteView.FocusOrClick.connect(&ColorBar::onFocusPaletteOrTilesView, this);
|
||||
m_tilesView.FocusOrClick.connect(&ColorBar::onFocusPaletteOrTilesView, this);
|
||||
m_appPalChangeConn = App::instance()->PaletteChange.connect(&ColorBar::onAppPaletteChange, this);
|
||||
KeyboardShortcuts::instance()->UserChange.connect(
|
||||
base::Bind<void>(&ColorBar::setupTooltips, this, tooltipManager));
|
||||
[this, tooltipManager]{ setupTooltips(tooltipManager); });
|
||||
|
||||
setEditMode(false);
|
||||
registerCommands();
|
||||
@ -1703,18 +1702,18 @@ void ColorBar::showPaletteSortOptions()
|
||||
if (m_ascending) asc.setSelected(true);
|
||||
else des.setSelected(true);
|
||||
|
||||
rev.Click.connect(base::Bind<void>(&ColorBar::onReverseColors, this));
|
||||
grd.Click.connect(base::Bind<void>(&ColorBar::onGradient, this));
|
||||
hue.Click.connect(base::Bind<void>(&ColorBar::onSortBy, this, SortPaletteBy::HUE));
|
||||
sat.Click.connect(base::Bind<void>(&ColorBar::onSortBy, this, SortPaletteBy::SATURATION));
|
||||
bri.Click.connect(base::Bind<void>(&ColorBar::onSortBy, this, SortPaletteBy::VALUE));
|
||||
lum.Click.connect(base::Bind<void>(&ColorBar::onSortBy, this, SortPaletteBy::LUMA));
|
||||
red.Click.connect(base::Bind<void>(&ColorBar::onSortBy, this, SortPaletteBy::RED));
|
||||
grn.Click.connect(base::Bind<void>(&ColorBar::onSortBy, this, SortPaletteBy::GREEN));
|
||||
blu.Click.connect(base::Bind<void>(&ColorBar::onSortBy, this, SortPaletteBy::BLUE));
|
||||
alp.Click.connect(base::Bind<void>(&ColorBar::onSortBy, this, SortPaletteBy::ALPHA));
|
||||
asc.Click.connect(base::Bind<void>(&ColorBar::setAscending, this, true));
|
||||
des.Click.connect(base::Bind<void>(&ColorBar::setAscending, this, false));
|
||||
rev.Click.connect([this]{ onReverseColors(); });
|
||||
grd.Click.connect([this]{ onGradient(); });
|
||||
hue.Click.connect([this]{ onSortBy(SortPaletteBy::HUE); });
|
||||
sat.Click.connect([this]{ onSortBy(SortPaletteBy::SATURATION); });
|
||||
bri.Click.connect([this]{ onSortBy(SortPaletteBy::VALUE); });
|
||||
lum.Click.connect([this]{ onSortBy(SortPaletteBy::LUMA); });
|
||||
red.Click.connect([this]{ onSortBy(SortPaletteBy::RED); });
|
||||
grn.Click.connect([this]{ onSortBy(SortPaletteBy::GREEN); });
|
||||
blu.Click.connect([this]{ onSortBy(SortPaletteBy::BLUE); });
|
||||
alp.Click.connect([this]{ onSortBy(SortPaletteBy::ALPHA); });
|
||||
asc.Click.connect([this]{ setAscending(true); });
|
||||
des.Click.connect([this]{ setAscending(false); });
|
||||
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y+bounds.h));
|
||||
}
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "app/ui/palette_view.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/scoped_value.h"
|
||||
#include "doc/image_impl.h"
|
||||
#include "doc/palette.h"
|
||||
@ -251,7 +250,7 @@ ColorPopup::ColorPopup(const ColorButtonOptions& options)
|
||||
m_vbox.addChild(&m_maskLabel);
|
||||
addChild(&m_vbox);
|
||||
|
||||
m_colorType.ItemChange.connect(base::Bind<void>(&ColorPopup::onColorTypeClick, this));
|
||||
m_colorType.ItemChange.connect([this]{ onColorTypeClick(); });
|
||||
|
||||
m_sliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this);
|
||||
m_hexColorEntry.ColorChange.connect(&ColorPopup::onColorHexEntryChange, this);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user