mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-01 01:20:25 +00:00
Add fg/bg tiles selectors in ColorBar
Now fg/bg colors and fg/bg tiles are different widgets, and the StatusBar can show tiles when the eyedropper is picking tiles.
This commit is contained in:
parent
fa46aff072
commit
5ee3ebdd71
@ -212,6 +212,8 @@
|
||||
<option id="tiles_box_size" type="int" default="16" />
|
||||
<option id="fg_color" type="app::Color" default="app::Color::fromRgb(255, 255, 255)" />
|
||||
<option id="bg_color" type="app::Color" default="app::Color::fromRgb(0, 0, 0)" />
|
||||
<option id="fg_tile" type="doc::tile_t" default="doc::tile_i_notile" />
|
||||
<option id="bg_tile" type="doc::tile_t" default="doc::tile_i_notile" />
|
||||
<option id="selector" type="app::ColorBar::ColorSelector" default="app::ColorBar::ColorSelector::TINT_SHADE_TONE" />
|
||||
<option id="discrete_wheel" type="bool" default="false" />
|
||||
<option id="wheel_model" type="int" default="0" />
|
||||
|
@ -388,6 +388,7 @@ if(ENABLE_UI)
|
||||
ui/tabs.cpp
|
||||
ui/tag_window.cpp
|
||||
ui/task_widget.cpp
|
||||
ui/tile_button.cpp
|
||||
ui/tileset_selector.cpp
|
||||
ui/timeline/ani_controls.cpp
|
||||
ui/timeline/timeline.cpp
|
||||
|
@ -96,8 +96,9 @@ bool get_cel_pixel(const Cel* cel,
|
||||
}
|
||||
|
||||
ColorPicker::ColorPicker()
|
||||
: m_alpha(0)
|
||||
, m_layer(NULL)
|
||||
: m_tile(doc::tile_i_notile)
|
||||
, m_alpha(0)
|
||||
, m_layer(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@ -136,8 +137,8 @@ void ColorPicker::pickColor(const Site& site,
|
||||
if (!cels.empty()) {
|
||||
const gfx::Point tilePos = site.grid().canvasToTile(gfx::Point(pos));
|
||||
if (cels.front()->image()->bounds().contains(tilePos)) {
|
||||
m_color = app::Color::fromIndex(
|
||||
doc::get_pixel(cels.front()->image(), tilePos.x, tilePos.y));
|
||||
m_tile = doc::get_pixel(cels.front()->image(), tilePos.x, tilePos.y);
|
||||
m_color = app::Color::fromIndex(m_tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,8 +161,8 @@ void ColorPicker::pickColor(const Site& site,
|
||||
if (site.tilemapMode() == TilemapMode::Tiles) {
|
||||
const gfx::Point tilePos = site.grid().canvasToTile(gfx::Point(pos));
|
||||
if (cel->image()->bounds().contains(tilePos)) {
|
||||
m_color = app::Color::fromIndex(
|
||||
doc::get_pixel(cel->image(), tilePos.x, tilePos.y));
|
||||
m_tile = doc::get_pixel(cel->image(), tilePos.x, tilePos.y);
|
||||
m_color = app::Color::fromIndex(m_tile);
|
||||
}
|
||||
}
|
||||
else if (site.tilemapMode() == TilemapMode::Pixels) {
|
||||
|
@ -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
|
||||
@ -10,6 +11,7 @@
|
||||
|
||||
#include "app/color.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/tile.h"
|
||||
#include "gfx/point.h"
|
||||
|
||||
namespace render {
|
||||
@ -35,11 +37,13 @@ namespace app {
|
||||
const Mode mode);
|
||||
|
||||
app::Color color() const { return m_color; }
|
||||
doc::tile_t tile() const { return m_tile; }
|
||||
int alpha() const { return m_alpha; }
|
||||
doc::Layer* layer() const { return m_layer; }
|
||||
|
||||
private:
|
||||
app::Color m_color;
|
||||
doc::tile_t m_tile;
|
||||
int m_alpha;
|
||||
doc::Layer* m_layer;
|
||||
};
|
||||
|
@ -37,7 +37,8 @@ EyedropperCommand::EyedropperCommand()
|
||||
void EyedropperCommand::pickSample(const Site& site,
|
||||
const gfx::PointF& pixelPos,
|
||||
const render::Projection& proj,
|
||||
app::Color& color)
|
||||
app::Color& color,
|
||||
doc::tile_t& tile)
|
||||
{
|
||||
// Check if we've to grab alpha channel or the merged color.
|
||||
Preferences& pref = Preferences::instance();
|
||||
@ -60,13 +61,12 @@ void EyedropperCommand::pickSample(const Site& site,
|
||||
app::gen::EyedropperChannel channel =
|
||||
pref.eyedropper.channel();
|
||||
|
||||
app::Color picked = picker.color();
|
||||
|
||||
if (site.tilemapMode() == TilemapMode::Tiles) {
|
||||
color = app::Color::fromIndex(picked.getIndex());
|
||||
tile = picker.tile();
|
||||
return;
|
||||
}
|
||||
|
||||
app::Color picked = picker.color();
|
||||
switch (channel) {
|
||||
case app::gen::EyedropperChannel::COLOR_ALPHA:
|
||||
color = picked;
|
||||
@ -218,19 +218,31 @@ void EyedropperCommand::executeOnMousePos(Context* context,
|
||||
DisableColorBarEditMode disable;
|
||||
Preferences& pref = Preferences::instance();
|
||||
app::Color color =
|
||||
foreground ? pref.colorBar.fgColor():
|
||||
pref.colorBar.bgColor();
|
||||
(foreground ? pref.colorBar.fgColor():
|
||||
pref.colorBar.bgColor());
|
||||
doc::tile_t tile =
|
||||
(foreground ? pref.colorBar.fgTile():
|
||||
pref.colorBar.bgTile());
|
||||
|
||||
pickSample(editor->getSite(),
|
||||
Site site = editor->getSite();
|
||||
pickSample(site,
|
||||
pixelPos,
|
||||
editor->projection(),
|
||||
color);
|
||||
color, tile);
|
||||
|
||||
if (site.tilemapMode() == TilemapMode::Tiles) {
|
||||
if (foreground)
|
||||
pref.colorBar.fgTile(tile);
|
||||
else
|
||||
pref.colorBar.bgTile(tile);
|
||||
}
|
||||
else {
|
||||
if (foreground)
|
||||
pref.colorBar.fgColor(color);
|
||||
else
|
||||
pref.colorBar.bgColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
Command* CommandFactory::createEyedropperCommand()
|
||||
{
|
||||
|
@ -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
|
||||
@ -28,7 +29,8 @@ namespace app {
|
||||
void pickSample(const Site& site,
|
||||
const gfx::PointF& pixelPos,
|
||||
const render::Projection& proj,
|
||||
app::Color& color);
|
||||
app::Color& color,
|
||||
doc::tile_t& tile);
|
||||
|
||||
void executeOnMousePos(Context* context,
|
||||
Editor* editor,
|
||||
|
@ -17,8 +17,10 @@
|
||||
#include "app/console.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/modules/palettes.h"
|
||||
#include "app/site.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/util/conversion_to_surface.h"
|
||||
#include "doc/blend_funcs.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/palette.h"
|
||||
@ -26,6 +28,7 @@
|
||||
#include "gfx/point.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "os/surface.h"
|
||||
#include "os/system.h"
|
||||
#include "ui/intern.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/theme.h"
|
||||
@ -181,6 +184,80 @@ void draw_color_button(ui::Graphics* g,
|
||||
}
|
||||
}
|
||||
|
||||
void draw_tile(ui::Graphics* g,
|
||||
const Rect& rc,
|
||||
const Site& site,
|
||||
doc::tile_t tile)
|
||||
{
|
||||
if (rc.w < 1 || rc.h < 1)
|
||||
return;
|
||||
|
||||
if (rc.w == rc.h)
|
||||
draw_checked_grid(g, rc, gfx::Size(rc.w/2, rc.h/2));
|
||||
else
|
||||
draw_checked_grid(g, rc, gfx::Size(rc.w/4, rc.h/2));
|
||||
|
||||
if (tile == doc::tile_i_notile)
|
||||
return;
|
||||
|
||||
doc::Tileset* ts = site.tileset();
|
||||
if (!ts)
|
||||
return;
|
||||
|
||||
doc::tile_index ti = doc::tile_geti(tile);
|
||||
if (ti < 0 || ti >= ts->size())
|
||||
return;
|
||||
|
||||
doc::ImageRef tileImage = ts->get(ti);
|
||||
if (!tileImage)
|
||||
return;
|
||||
|
||||
const int w = tileImage->width();
|
||||
const int h = tileImage->height();
|
||||
os::SurfaceRef surface = os::instance()->makeRgbaSurface(w, h);
|
||||
convert_image_to_surface(tileImage.get(), get_current_palette(),
|
||||
surface.get(), 0, 0, 0, 0, w, h);
|
||||
g->drawRgbaSurface(surface.get(), gfx::Rect(0, 0, w, h), rc);
|
||||
}
|
||||
|
||||
void draw_tile_button(ui::Graphics* g,
|
||||
const gfx::Rect& rc,
|
||||
const Site& site,
|
||||
doc::tile_t tile,
|
||||
const bool hot,
|
||||
const bool drag)
|
||||
{
|
||||
SkinTheme* theme = SkinTheme::instance();
|
||||
int scale = ui::guiscale();
|
||||
|
||||
// Draw background (the tile)
|
||||
draw_tile(g,
|
||||
Rect(rc.x+1*scale,
|
||||
rc.y+1*scale,
|
||||
rc.w-2*scale,
|
||||
rc.h-2*scale),
|
||||
site, tile);
|
||||
|
||||
// Draw opaque border
|
||||
theme->drawRect(
|
||||
g, rc,
|
||||
theme->parts.colorbar0()->bitmapNW(),
|
||||
theme->parts.colorbar0()->bitmapN(),
|
||||
theme->parts.colorbar1()->bitmapNE(),
|
||||
theme->parts.colorbar1()->bitmapE(),
|
||||
theme->parts.colorbar3()->bitmapSE(),
|
||||
theme->parts.colorbar2()->bitmapS(),
|
||||
theme->parts.colorbar2()->bitmapSW(),
|
||||
theme->parts.colorbar0()->bitmapW());
|
||||
|
||||
// Draw hot
|
||||
if (hot) {
|
||||
theme->drawRect(
|
||||
g, gfx::Rect(rc.x, rc.y, rc.w, rc.h-1 - 1*scale),
|
||||
theme->parts.colorbarSelection().get());
|
||||
}
|
||||
}
|
||||
|
||||
void draw_alpha_slider(ui::Graphics* g,
|
||||
const gfx::Rect& rc,
|
||||
const app::Color& color)
|
||||
|
@ -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
|
||||
@ -26,6 +26,7 @@ namespace ui {
|
||||
}
|
||||
|
||||
namespace app {
|
||||
class Site;
|
||||
|
||||
void draw_checked_grid(ui::Graphics* g,
|
||||
const gfx::Rect& rc,
|
||||
@ -48,6 +49,18 @@ namespace app {
|
||||
const bool hot,
|
||||
const bool drag);
|
||||
|
||||
void draw_tile(ui::Graphics* g,
|
||||
const gfx::Rect& rc,
|
||||
const Site& site,
|
||||
const doc::tile_t tile);
|
||||
|
||||
void draw_tile_button(ui::Graphics* g,
|
||||
const gfx::Rect& rc,
|
||||
const Site& site,
|
||||
doc::tile_t tile,
|
||||
const bool hot,
|
||||
const bool drag);
|
||||
|
||||
void draw_alpha_slider(ui::Graphics* g,
|
||||
const gfx::Rect& rc,
|
||||
const app::Color& color);
|
||||
|
@ -143,6 +143,19 @@ app::tools::InkType get_value_from_lua(lua_State* L, int index) {
|
||||
return (app::tools::InkType)lua_tointeger(L, index);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// doc::tile_t
|
||||
|
||||
template<>
|
||||
void push_value_to_lua(lua_State* L, const doc::tile_t& value) {
|
||||
lua_pushinteger(L, value);
|
||||
}
|
||||
|
||||
template<>
|
||||
doc::tile_t get_value_from_lua(lua_State* L, int index) {
|
||||
return lua_tointeger(L, index);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// enums
|
||||
|
||||
|
@ -74,6 +74,14 @@ void Site::range(const DocRange& range)
|
||||
}
|
||||
}
|
||||
|
||||
doc::Tileset* Site::tileset() const
|
||||
{
|
||||
if (m_layer && m_layer->isTilemap())
|
||||
return static_cast<LayerTilemap*>(m_layer)->tileset();
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Grid Site::grid() const
|
||||
{
|
||||
if (m_layer && m_layer->isTilemap()) {
|
||||
|
@ -25,6 +25,7 @@ namespace doc {
|
||||
class Palette;
|
||||
class RgbMap;
|
||||
class Sprite;
|
||||
class Tileset;
|
||||
} // namespace doc
|
||||
|
||||
namespace app {
|
||||
@ -106,6 +107,7 @@ namespace app {
|
||||
doc::Palette* palette() const;
|
||||
doc::RgbMap* rgbMap() const;
|
||||
|
||||
doc::Tileset* tileset() const;
|
||||
doc::Grid grid() const;
|
||||
gfx::Rect gridBounds() const;
|
||||
|
||||
|
@ -205,6 +205,7 @@ ColorBar::ColorBar(int align, TooltipManager* tooltipManager)
|
||||
m_scrollableTilesView.setExpansive(true);
|
||||
|
||||
m_scrollableTilesView.setVisible(false);
|
||||
m_tilesHelpers.setVisible(false);
|
||||
m_remapPalButton.setVisible(false);
|
||||
m_remapTilesButton.setVisible(false);
|
||||
|
||||
@ -243,14 +244,22 @@ ColorBar::ColorBar(int align, TooltipManager* tooltipManager)
|
||||
addChild(&m_tilesHBox);
|
||||
addChild(&m_splitter);
|
||||
|
||||
addChild(&m_colorHelpers);
|
||||
addChild(&m_tilesHelpers);
|
||||
|
||||
HBox* fgBox = new HBox;
|
||||
HBox* bgBox = new HBox;
|
||||
fgBox->addChild(&m_fgColor);
|
||||
fgBox->addChild(m_fgWarningIcon);
|
||||
bgBox->addChild(&m_bgColor);
|
||||
bgBox->addChild(m_bgWarningIcon);
|
||||
addChild(fgBox);
|
||||
addChild(bgBox);
|
||||
m_colorHelpers.addChild(fgBox);
|
||||
m_colorHelpers.addChild(bgBox);
|
||||
|
||||
m_tilesHelpers.addChild(new BoxFiller);
|
||||
m_tilesHelpers.addChild(&m_fgTile);
|
||||
m_tilesHelpers.addChild(&m_bgTile);
|
||||
m_tilesHelpers.addChild(new BoxFiller);
|
||||
|
||||
m_fgColor.setId("fg_color");
|
||||
m_bgColor.setId("bg_color");
|
||||
@ -336,6 +345,8 @@ ColorBar::ColorBar(int align, TooltipManager* tooltipManager)
|
||||
m_afterCmdConn = UIContext::instance()->AfterCommandExecution.connect(&ColorBar::onAfterExecuteCommand, this);
|
||||
m_fgConn = Preferences::instance().colorBar.fgColor.AfterChange.connect([this]{ onFgColorChangeFromPreferences(); });
|
||||
m_bgConn = Preferences::instance().colorBar.bgColor.AfterChange.connect([this]{ onBgColorChangeFromPreferences(); });
|
||||
m_fgTileConn = Preferences::instance().colorBar.fgTile.AfterChange.connect([this]{ onFgTileChangeFromPreferences(); });
|
||||
m_bgTileConn = Preferences::instance().colorBar.bgTile.AfterChange.connect([this]{ onBgTileChangeFromPreferences(); });
|
||||
m_sepConn = Preferences::instance().colorBar.entriesSeparator.AfterChange.connect([this]{ invalidate(); });
|
||||
m_paletteView.FocusOrClick.connect(&ColorBar::onFocusPaletteOrTilesView, this);
|
||||
m_tilesView.FocusOrClick.connect(&ColorBar::onFocusPaletteOrTilesView, this);
|
||||
@ -390,12 +401,12 @@ void ColorBar::setBgColor(const app::Color& color)
|
||||
|
||||
doc::tile_index ColorBar::getFgTile() const
|
||||
{
|
||||
return m_fgColor.getColor().getIndex(); // TODO
|
||||
return m_fgTile.getTile();
|
||||
}
|
||||
|
||||
doc::tile_index ColorBar::getBgTile() const
|
||||
{
|
||||
return m_bgColor.getColor().getIndex(); // TODO
|
||||
return m_bgTile.getTile();
|
||||
}
|
||||
|
||||
ColorBar::ColorSelector ColorBar::getColorSelector() const
|
||||
@ -518,11 +529,17 @@ void ColorBar::setTilemapMode(const TilemapMode mode)
|
||||
manager()->freeWidget(&m_paletteView);
|
||||
m_scrollablePalView.setVisible(false);
|
||||
m_scrollableTilesView.setVisible(true);
|
||||
m_selectorPlaceholder.setVisible(false);
|
||||
m_colorHelpers.setVisible(false);
|
||||
m_tilesHelpers.setVisible(true);
|
||||
}
|
||||
else {
|
||||
manager()->freeWidget(&m_tilesView);
|
||||
m_scrollablePalView.setVisible(true);
|
||||
m_scrollableTilesView.setVisible(false);
|
||||
m_selectorPlaceholder.setVisible(true);
|
||||
m_colorHelpers.setVisible(true);
|
||||
m_tilesHelpers.setVisible(false);
|
||||
}
|
||||
|
||||
layout();
|
||||
@ -1049,12 +1066,11 @@ void ColorBar::onTilesViewDragAndDrop(doc::Tileset* tileset,
|
||||
|
||||
void ColorBar::onTilesViewIndexChange(int index, ui::MouseButton button)
|
||||
{
|
||||
// TODO show tools to stamp/draw/pick tiles
|
||||
|
||||
auto& pref = Preferences::instance();
|
||||
if (button == kButtonRight)
|
||||
setBgColor(app::Color::fromIndex(index));
|
||||
pref.colorBar.bgTile(doc::tile(index, 0));
|
||||
else if (button == kButtonLeft)
|
||||
setFgColor(app::Color::fromIndex(index));
|
||||
pref.colorBar.fgTile(doc::tile(index, 0));
|
||||
else if (button == kButtonMiddle) {
|
||||
// TODO ?
|
||||
}
|
||||
@ -1091,6 +1107,24 @@ void ColorBar::onBgColorChangeFromPreferences()
|
||||
}
|
||||
}
|
||||
|
||||
void ColorBar::onFgTileChangeFromPreferences()
|
||||
{
|
||||
if (m_fromPref)
|
||||
return;
|
||||
|
||||
base::ScopedValue<bool> sync(m_fromPref, true, false);
|
||||
m_fgTile.setTile(Preferences::instance().colorBar.fgTile());
|
||||
}
|
||||
|
||||
void ColorBar::onBgTileChangeFromPreferences()
|
||||
{
|
||||
if (m_fromPref)
|
||||
return;
|
||||
|
||||
base::ScopedValue<bool> sync(m_fromPref, true, false);
|
||||
m_bgTile.setTile(Preferences::instance().colorBar.bgTile());
|
||||
}
|
||||
|
||||
void ColorBar::onFgColorButtonBeforeChange(app::Color& color)
|
||||
{
|
||||
COLOR_BAR_TRACE("ColorBar::onFgColorButtonBeforeChange(%s)\n", color.toString().c_str());
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/input_chain_element.h"
|
||||
#include "app/ui/palette_view.h"
|
||||
#include "app/ui/tile_button.h"
|
||||
#include "doc/object_id.h"
|
||||
#include "doc/palette_gradient_type.h"
|
||||
#include "doc/pixel_format.h"
|
||||
@ -133,6 +134,8 @@ namespace app {
|
||||
void onPaletteIndexChange(PaletteIndexChangeEvent& ev);
|
||||
void onFgColorChangeFromPreferences();
|
||||
void onBgColorChangeFromPreferences();
|
||||
void onFgTileChangeFromPreferences();
|
||||
void onBgTileChangeFromPreferences();
|
||||
void onFgColorButtonBeforeChange(app::Color& color);
|
||||
void onFgColorButtonChange(const app::Color& color);
|
||||
void onBgColorButtonChange(const app::Color& color);
|
||||
@ -203,6 +206,8 @@ namespace app {
|
||||
PaletteView m_tilesView;
|
||||
ui::Button m_remapPalButton;
|
||||
ui::Button m_remapTilesButton;
|
||||
ui::VBox m_colorHelpers;
|
||||
ui::HBox m_tilesHelpers;
|
||||
ColorSelector m_selector;
|
||||
ColorTintShadeTone* m_tintShadeTone;
|
||||
ColorSpectrum* m_spectrum;
|
||||
@ -211,6 +216,8 @@ namespace app {
|
||||
ColorButton m_bgColor;
|
||||
WarningIcon* m_fgWarningIcon;
|
||||
WarningIcon* m_bgWarningIcon;
|
||||
TileButton m_fgTile;
|
||||
TileButton m_bgTile;
|
||||
|
||||
// True when the user clicks the PaletteView so we're changing the
|
||||
// color from the palette view.
|
||||
@ -232,6 +239,8 @@ namespace app {
|
||||
obs::scoped_connection m_afterCmdConn;
|
||||
obs::scoped_connection m_fgConn;
|
||||
obs::scoped_connection m_bgConn;
|
||||
obs::scoped_connection m_fgTileConn;
|
||||
obs::scoped_connection m_bgTileConn;
|
||||
obs::scoped_connection m_sepConn;
|
||||
obs::scoped_connection m_appPalChangeConn;
|
||||
ui::MouseButton m_lastButton;
|
||||
|
@ -61,9 +61,11 @@ namespace app {
|
||||
void onSaveLayout(ui::SaveLayoutEvent& ev) override;
|
||||
|
||||
private:
|
||||
// ContextObserver impl
|
||||
void onActiveSiteChange(const Site& site) override;
|
||||
|
||||
void onWindowClose(ui::CloseEvent& ev);
|
||||
void onWindowColorChange(const app::Color& color);
|
||||
void onActiveSiteChange(const Site& site) override;
|
||||
bool canPin() const { return m_options.canPinSelector; }
|
||||
|
||||
app::Color m_color;
|
||||
|
@ -1663,6 +1663,7 @@ app::Color Editor::getColorByPosition(const gfx::Point& mousePos)
|
||||
gfx::PointF editorPos = screenToEditorF(mousePos);
|
||||
|
||||
ColorPicker picker;
|
||||
site.tilemapMode(TilemapMode::Pixels);
|
||||
picker.pickColor(site, editorPos, m_proj,
|
||||
ColorPicker::FromComposition);
|
||||
return picker.color();
|
||||
@ -1671,6 +1672,23 @@ app::Color Editor::getColorByPosition(const gfx::Point& mousePos)
|
||||
return app::Color::fromMask();
|
||||
}
|
||||
|
||||
doc::tile_t Editor::getTileByPosition(const gfx::Point& mousePos)
|
||||
{
|
||||
Site site = getSite();
|
||||
if (site.sprite()) {
|
||||
gfx::PointF editorPos = screenToEditorF(mousePos);
|
||||
|
||||
ColorPicker picker;
|
||||
site.tilemapMode(TilemapMode::Tiles);
|
||||
picker.pickColor(site, editorPos, m_proj,
|
||||
ColorPicker::FromComposition);
|
||||
|
||||
return picker.tile();
|
||||
}
|
||||
else
|
||||
return doc::tile_i_notile;
|
||||
}
|
||||
|
||||
bool Editor::startStraightLineWithFreehandTool(const ui::MouseMessage* msg)
|
||||
{
|
||||
tools::Tool* tool = App::instance()->activeToolManager()->selectedTool();
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "app/ui/editor/editor_observers.h"
|
||||
#include "app/ui/editor/editor_state.h"
|
||||
#include "app/ui/editor/editor_states_history.h"
|
||||
#include "app/ui/tile_source.h"
|
||||
#include "doc/algorithm/flip_type.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/image_buffer.h"
|
||||
@ -73,6 +74,7 @@ namespace app {
|
||||
class Editor : public ui::Widget,
|
||||
public app::DocObserver,
|
||||
public IColorSource,
|
||||
public ITileSource,
|
||||
public tools::ActiveToolObserver {
|
||||
public:
|
||||
enum EditorFlags {
|
||||
@ -282,6 +284,9 @@ namespace app {
|
||||
// IColorSource
|
||||
app::Color getColorByPosition(const gfx::Point& pos) override;
|
||||
|
||||
// ITileSource
|
||||
doc::tile_t getTileByPosition(const gfx::Point& pos) override;
|
||||
|
||||
void setTagFocusBand(int value) { m_tagFocusBand = value; }
|
||||
int tagFocusBand() const { return m_tagFocusBand; }
|
||||
|
||||
|
@ -542,19 +542,23 @@ bool StandbyState::onUpdateStatusBar(Editor* editor)
|
||||
}
|
||||
// For eye-dropper
|
||||
else if (ink->isEyedropper()) {
|
||||
Site site = editor->getSite();
|
||||
EyedropperCommand cmd;
|
||||
app::Color color = Preferences::instance().colorBar.fgColor();
|
||||
cmd.pickSample(editor->getSite(),
|
||||
doc::tile_t tile = Preferences::instance().colorBar.fgTile();
|
||||
cmd.pickSample(site,
|
||||
spritePos,
|
||||
editor->projection(),
|
||||
color);
|
||||
color, tile);
|
||||
|
||||
char buf[256];
|
||||
sprintf(buf, " :pos: %d %d",
|
||||
auto buf = fmt::format(" :pos: {} {}",
|
||||
int(std::floor(spritePos.x)),
|
||||
int(std::floor(spritePos.y)));
|
||||
|
||||
StatusBar::instance()->showColor(0, buf, color);
|
||||
if (site.tilemapMode() == TilemapMode::Tiles)
|
||||
StatusBar::instance()->showTile(0, buf.c_str(), tile);
|
||||
else
|
||||
StatusBar::instance()->showColor(0, buf.c_str(), color);
|
||||
}
|
||||
else {
|
||||
Site site = editor->getSite();
|
||||
|
@ -805,11 +805,8 @@ tools::ToolLoop* create_tool_loop(
|
||||
else {
|
||||
params.fg = colorbar->getFgColor();
|
||||
params.bg = colorbar->getBgColor();
|
||||
}
|
||||
|
||||
if (site.tilemapMode() == TilemapMode::Pixels &&
|
||||
(!params.fg.isValid() ||
|
||||
!params.bg.isValid())) {
|
||||
if (!params.fg.isValid() ||
|
||||
!params.bg.isValid()) {
|
||||
if (Preferences::instance().colorBar.showInvalidFgBgColorAlert()) {
|
||||
OptionalAlert::show(
|
||||
Preferences::instance().colorBar.showInvalidFgBgColorAlert,
|
||||
@ -817,6 +814,7 @@ tools::ToolLoop* create_tool_loop(
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the new tool loop
|
||||
try {
|
||||
@ -990,16 +988,14 @@ tools::ToolLoop* create_tool_loop_preview(
|
||||
if (site.tilemapMode() == TilemapMode::Tiles) {
|
||||
params.fg = app::Color::fromIndex(colorbar->getFgTile()); // TODO Color::fromTileIndex?
|
||||
params.bg = app::Color::fromIndex(colorbar->getBgTile());
|
||||
if (!params.fg.isValid() || !params.bg.isValid())
|
||||
return nullptr;
|
||||
}
|
||||
else {
|
||||
params.fg = colorbar->getFgColor();
|
||||
params.bg = colorbar->getBgColor();
|
||||
}
|
||||
if (!params.fg.isValid() ||
|
||||
!params.bg.isValid())
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
params.brush = brush;
|
||||
params.button = tools::ToolLoop::Left;
|
||||
|
@ -151,8 +151,7 @@ public:
|
||||
PaletteViewModification::DRAGANDDROP);
|
||||
}
|
||||
void showEntryInStatusBar(StatusBar* statusBar, int index) override {
|
||||
statusBar->showColor(
|
||||
0, "", app::Color::fromIndex(index));
|
||||
statusBar->showColor(0, "", app::Color::fromIndex(index));
|
||||
}
|
||||
void showDragInfoInStatusBar(StatusBar* statusBar, bool copy, int destIndex, int newSize) override {
|
||||
statusBar->setStatusText(
|
||||
@ -259,8 +258,7 @@ public:
|
||||
picks = newPicks;
|
||||
}
|
||||
void showEntryInStatusBar(StatusBar* statusBar, int index) override {
|
||||
statusBar->setStatusText(
|
||||
0, fmt::format("Tile {}", index));
|
||||
statusBar->showTile(0, "", doc::tile(index, 0));
|
||||
}
|
||||
void showDragInfoInStatusBar(StatusBar* statusBar, bool copy, int destIndex, int newSize) override {
|
||||
statusBar->setStatusText(
|
||||
@ -483,6 +481,16 @@ app::Color PaletteView::getColorByPosition(const gfx::Point& pos)
|
||||
return app::Color::fromMask();
|
||||
}
|
||||
|
||||
doc::tile_t PaletteView::getTileByPosition(const gfx::Point& pos)
|
||||
{
|
||||
gfx::Point relPos = pos - bounds().origin();
|
||||
for (int i=0; i<m_adapter->size(); ++i) {
|
||||
if (getPaletteEntryBounds(i).contains(relPos))
|
||||
return doc::tile(i, 0);
|
||||
}
|
||||
return doc::tile_i_notile;
|
||||
}
|
||||
|
||||
void PaletteView::onActiveSiteChange(const Site& site)
|
||||
{
|
||||
ASSERT(isTiles());
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "app/context_observer.h"
|
||||
#include "app/ui/color_source.h"
|
||||
#include "app/ui/marching_ants.h"
|
||||
#include "app/ui/tile_source.h"
|
||||
#include "doc/palette_picks.h"
|
||||
#include "doc/tile.h"
|
||||
#include "obs/connection.h"
|
||||
@ -64,6 +65,7 @@ namespace app {
|
||||
class PaletteView : public ui::Widget
|
||||
, public MarchingAnts
|
||||
, public IColorSource
|
||||
, public ITileSource
|
||||
, public ContextObserver {
|
||||
friend class PaletteViewAdapter;
|
||||
friend class TilesetViewAdapter;
|
||||
@ -102,6 +104,9 @@ namespace app {
|
||||
// IColorSource
|
||||
app::Color getColorByPosition(const gfx::Point& pos) override;
|
||||
|
||||
// ITileSource
|
||||
doc::tile_t getTileByPosition(const gfx::Point& pos) override;
|
||||
|
||||
// ContextObserver impl
|
||||
void onActiveSiteChange(const Site& site) override;
|
||||
|
||||
|
@ -68,7 +68,8 @@ class StatusBar::Indicators : public HBox {
|
||||
enum IndicatorType {
|
||||
kText,
|
||||
kIcon,
|
||||
kColor
|
||||
kColor,
|
||||
kTile
|
||||
};
|
||||
Indicator(IndicatorType type) : m_type(type) { }
|
||||
IndicatorType indicatorType() const { return m_type; }
|
||||
@ -195,6 +196,41 @@ class StatusBar::Indicators : public HBox {
|
||||
app::Color m_color;
|
||||
};
|
||||
|
||||
class TileIndicator : public Indicator {
|
||||
public:
|
||||
TileIndicator(doc::tile_t tile)
|
||||
: Indicator(kTile)
|
||||
, m_tile(doc::tile_i_notile) {
|
||||
updateIndicator(tile, true);
|
||||
}
|
||||
|
||||
bool updateIndicator(doc::tile_t tile, bool first = false) {
|
||||
if (m_tile == tile && !first)
|
||||
return false;
|
||||
|
||||
m_tile = tile;
|
||||
setMinSize(minSize().createUnion(Size(32*guiscale(), 1)));
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void onPaint(ui::PaintEvent& ev) override {
|
||||
Rect rc = clientBounds();
|
||||
Graphics* g = ev.graphics();
|
||||
|
||||
// TODO could the site came from the Indicators or StatusBar itself
|
||||
Site site = UIContext::instance()->activeSite();
|
||||
|
||||
g->fillRect(bgColor(), rc);
|
||||
draw_tile_button(
|
||||
g, Rect(rc.x, rc.y, 32*guiscale(), rc.h),
|
||||
site, m_tile,
|
||||
false, false);
|
||||
}
|
||||
|
||||
doc::tile_t m_tile;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Indicators()
|
||||
@ -282,6 +318,25 @@ public:
|
||||
m_redraw = true;
|
||||
}
|
||||
|
||||
void addTileIndicator(doc::tile_t tile) {
|
||||
if (m_iterator != m_indicators.end()) {
|
||||
if ((*m_iterator)->indicatorType() == Indicator::kTile) {
|
||||
m_redraw |= static_cast<TileIndicator*>(*m_iterator)
|
||||
->updateIndicator(tile);
|
||||
++m_iterator;
|
||||
return;
|
||||
}
|
||||
else
|
||||
removeAllNextIndicators();
|
||||
}
|
||||
|
||||
auto indicator = new TileIndicator(tile);
|
||||
m_indicators.push_back(indicator);
|
||||
m_iterator = m_indicators.end();
|
||||
m_leftArea.addChild(indicator);
|
||||
m_redraw = true;
|
||||
}
|
||||
|
||||
void showBackupIcon(BackupIcon icon) {
|
||||
m_backupIcon = icon;
|
||||
if (m_backupIcon != BackupIcon::None) {
|
||||
@ -394,10 +449,36 @@ public:
|
||||
std::string str = color.toHumanReadableString(
|
||||
app_get_current_pixel_format(),
|
||||
app::Color::LongHumanReadableString);
|
||||
if (color.getAlpha() < 255) {
|
||||
char buf[256];
|
||||
sprintf(buf, " A%d", color.getAlpha());
|
||||
str += buf;
|
||||
if (color.getAlpha() < 255)
|
||||
str += fmt::format(" A{}", color.getAlpha());
|
||||
m_indicators->addTextIndicator(str.c_str());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
IndicatorsGeneration& add(doc::tile_t tile) {
|
||||
auto theme = SkinTheme::instance();
|
||||
|
||||
// Eyedropper icon
|
||||
add(theme->getToolPart("eyedropper"), false);
|
||||
|
||||
// Color
|
||||
m_indicators->addTileIndicator(tile);
|
||||
|
||||
// Color description
|
||||
std::string str;
|
||||
if (tile == doc::tile_i_notile) {
|
||||
str += "Empty";
|
||||
}
|
||||
else {
|
||||
doc::tile_index ti = doc::tile_geti(tile);
|
||||
doc::tile_flags tf = doc::tile_getf(tile);
|
||||
str += fmt::format("{}", ti);
|
||||
if (tf) {
|
||||
if (tf & doc::tile_f_flipx) str += " FlipX";
|
||||
if (tf & doc::tile_f_flipy) str += " FlipY";
|
||||
if (tf & doc::tile_f_90cw) str += " Rot90CW";
|
||||
}
|
||||
}
|
||||
m_indicators->addTextIndicator(str.c_str());
|
||||
|
||||
@ -712,6 +793,18 @@ void StatusBar::showColor(int msecs, const char* text, const app::Color& color)
|
||||
}
|
||||
}
|
||||
|
||||
void StatusBar::showTile(int msecs, const char* text, doc::tile_t tile)
|
||||
{
|
||||
if ((base::current_tick() > m_timeout) || (msecs > 0)) {
|
||||
IndicatorsGeneration gen(m_indicators);
|
||||
gen.add(tile);
|
||||
if (text)
|
||||
gen.add(text);
|
||||
|
||||
m_timeout = base::current_tick() + msecs;
|
||||
}
|
||||
}
|
||||
|
||||
void StatusBar::showTool(int msecs, tools::Tool* tool)
|
||||
{
|
||||
ASSERT(tool != NULL);
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "app/tools/active_tool_observer.h"
|
||||
#include "app/ui/doc_observer_widget.h"
|
||||
#include "base/time.h"
|
||||
#include "doc/tile.h"
|
||||
#include "ui/base.h"
|
||||
#include "ui/box.h"
|
||||
|
||||
@ -60,6 +61,7 @@ namespace app {
|
||||
bool setStatusText(int msecs, const std::string& text);
|
||||
void showTip(int msecs, const std::string& msg);
|
||||
void showColor(int msecs, const char* text, const Color& color);
|
||||
void showTile(int msecs, const char* text, doc::tile_t tile);
|
||||
void showTool(int msecs, tools::Tool* tool);
|
||||
void showSnapToGridWarning(bool state);
|
||||
|
||||
|
164
src/app/ui/tile_button.cpp
Normal file
164
src/app/ui/tile_button.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
// 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 "app/ui/tile_button.h"
|
||||
|
||||
#include "app/modules/gfx.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/graphics.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/paint_event.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
#include "ui/system.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace app::skin;
|
||||
using namespace ui;
|
||||
|
||||
static WidgetType tilebutton_type()
|
||||
{
|
||||
static WidgetType type = kGenericWidget;
|
||||
if (type == kGenericWidget)
|
||||
type = register_widget_type();
|
||||
return type;
|
||||
}
|
||||
|
||||
TileButton::TileButton()
|
||||
: ButtonBase("", tilebutton_type(), kButtonWidget, kButtonWidget)
|
||||
{
|
||||
setFocusStop(true);
|
||||
initTheme();
|
||||
|
||||
UIContext::instance()->add_observer(this);
|
||||
}
|
||||
|
||||
TileButton::~TileButton()
|
||||
{
|
||||
UIContext::instance()->remove_observer(this);
|
||||
}
|
||||
|
||||
doc::tile_t TileButton::getTile() const
|
||||
{
|
||||
return m_tile;
|
||||
}
|
||||
|
||||
void TileButton::setTile(doc::tile_t origTile)
|
||||
{
|
||||
// Before change (this signal can modify the color)
|
||||
doc::tile_t tile = origTile;
|
||||
BeforeChange(tile);
|
||||
m_tile = tile;
|
||||
Change(tile);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
doc::tile_t TileButton::getTileByPosition(const gfx::Point& pos)
|
||||
{
|
||||
// Ignore the position
|
||||
return m_tile;
|
||||
}
|
||||
|
||||
void TileButton::onInitTheme(InitThemeEvent& ev)
|
||||
{
|
||||
ButtonBase::onInitTheme(ev);
|
||||
setStyle(SkinTheme::instance()->styles.colorButton());
|
||||
}
|
||||
|
||||
bool TileButton::onProcessMessage(Message* msg)
|
||||
{
|
||||
switch (msg->type()) {
|
||||
|
||||
case kMouseEnterMessage:
|
||||
StatusBar::instance()->showTile(0, "", m_tile);
|
||||
break;
|
||||
|
||||
case kMouseLeaveMessage:
|
||||
StatusBar::instance()->showDefaultText();
|
||||
break;
|
||||
|
||||
case kMouseMoveMessage:
|
||||
if (hasCapture()) {
|
||||
gfx::Point mousePos = static_cast<MouseMessage*>(msg)->position();
|
||||
Widget* picked = manager()->pick(mousePos);
|
||||
doc::tile_t tile = m_tile;
|
||||
|
||||
if (picked && picked != this) {
|
||||
// Pick a tile from a ITileSource
|
||||
if (ITileSource* tileSource = dynamic_cast<ITileSource*>(picked)) {
|
||||
tile = tileSource->getTileByPosition(mousePos);
|
||||
}
|
||||
}
|
||||
|
||||
// Did the tile change?
|
||||
if (tile != m_tile) {
|
||||
setTile(tile);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kSetCursorMessage:
|
||||
if (hasCapture()) {
|
||||
ui::set_mouse_cursor(kCustomCursor, SkinTheme::instance()->cursors.eyedropper());
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return ButtonBase::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void TileButton::onSizeHint(SizeHintEvent& ev)
|
||||
{
|
||||
ButtonBase::onSizeHint(ev);
|
||||
gfx::Size sz(32*guiscale(),
|
||||
32*guiscale());
|
||||
ev.setSizeHint(sz);
|
||||
}
|
||||
|
||||
void TileButton::onPaint(PaintEvent& ev)
|
||||
{
|
||||
Graphics* g = ev.graphics();
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
|
||||
gfx::Rect rc = clientBounds();
|
||||
|
||||
gfx::Color bg = bgColor();
|
||||
if (gfx::is_transparent(bg))
|
||||
bg = theme->colors.face();
|
||||
g->fillRect(bg, rc);
|
||||
|
||||
Site site = UIContext::instance()->activeSite();
|
||||
draw_tile_button(g, rc,
|
||||
site, m_tile,
|
||||
hasMouseOver(), false);
|
||||
|
||||
// Draw text
|
||||
if (m_tile != doc::tile_i_notile) {
|
||||
std::string str = fmt::format("{}", doc::tile_geti(m_tile));
|
||||
setTextQuiet(str.c_str());
|
||||
|
||||
// TODO calc a proper color for the text
|
||||
gfx::Color textcolor = gfx::rgba(0, 0, 0);
|
||||
gfx::Rect textrc;
|
||||
getTextIconInfo(NULL, &textrc);
|
||||
g->drawUIText(text(), textcolor, gfx::ColorNone, textrc.origin(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void TileButton::onActiveSiteChange(const Site& site)
|
||||
{
|
||||
invalidate();
|
||||
}
|
||||
|
||||
} // namespace app
|
52
src/app/ui/tile_button.h
Normal file
52
src/app/ui/tile_button.h
Normal file
@ -0,0 +1,52 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2020 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UI_TILE_BUTTON_H_INCLUDED
|
||||
#define APP_UI_TILE_BUTTON_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/color.h"
|
||||
#include "app/context_observer.h"
|
||||
#include "app/ui/tile_source.h"
|
||||
#include "doc/tile.h"
|
||||
#include "ui/button.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
class TileButton : public ui::ButtonBase,
|
||||
public ContextObserver,
|
||||
public ITileSource {
|
||||
public:
|
||||
TileButton();
|
||||
~TileButton();
|
||||
|
||||
doc::tile_t getTile() const;
|
||||
void setTile(doc::tile_t tile);
|
||||
|
||||
// ITileSource
|
||||
doc::tile_t getTileByPosition(const gfx::Point& pos) override;
|
||||
|
||||
// Signals
|
||||
obs::signal<void(doc::tile_t&)> BeforeChange;
|
||||
obs::signal<void(doc::tile_t)> Change;
|
||||
|
||||
protected:
|
||||
// Events
|
||||
void onInitTheme(ui::InitThemeEvent& ev) override;
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
void onSizeHint(ui::SizeHintEvent& ev) override;
|
||||
void onPaint(ui::PaintEvent& ev) override;
|
||||
|
||||
private:
|
||||
// ContextObserver impl
|
||||
void onActiveSiteChange(const Site& site) override;
|
||||
|
||||
doc::tile_t m_tile = doc::tile_i_notile;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
24
src/app/ui/tile_source.h
Normal file
24
src/app/ui/tile_source.h
Normal file
@ -0,0 +1,24 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2020 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UI_TILE_SOURCE_H_INCLUDED
|
||||
#define APP_UI_TILE_SOURCE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/tile.h"
|
||||
#include "gfx/point.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
class ITileSource {
|
||||
public:
|
||||
virtual ~ITileSource() { }
|
||||
virtual doc::tile_t getTileByPosition(const gfx::Point& pos) = 0;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user