mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-29 21:33:12 +00:00
Unify palette editor with color selection (fix #1102)
Added a new A key shortcut (equal to F4) to switch between selection/edition modes.
This commit is contained in:
parent
85b7996e9a
commit
7d1404de0a
@ -102,6 +102,7 @@
|
||||
<color id="flag_clicked" value="#7d929e" />
|
||||
<color id="select_box_ruler" value="#0000ff" />
|
||||
<color id="select_box_grid" value="#64c864" />
|
||||
<color id="edit_pal_face" value="#655561" />
|
||||
</colors>
|
||||
<parts>
|
||||
<part id="cursor_normal" x="80" y="0" w="16" h="16" focusx="0" focusy="0" />
|
||||
|
@ -114,6 +114,9 @@
|
||||
<key command="Timeline" shortcut="Tab">
|
||||
<param name="switch" value="true" />
|
||||
</key>
|
||||
<key command="PaletteEditor" shortcut="A">
|
||||
<param name="switch" value="true" />
|
||||
</key>
|
||||
<key command="PaletteEditor" shortcut="F4">
|
||||
<param name="switch" value="true" />
|
||||
</key>
|
||||
@ -937,7 +940,7 @@
|
||||
</menu>
|
||||
|
||||
<menu id="palette_popup">
|
||||
<item command="PaletteEditor" text="&Palette Editor">
|
||||
<item command="PaletteEditor" text="Edit &Palette">
|
||||
<param name="switch" value="true" />
|
||||
</item>
|
||||
<item command="PaletteSize" text="Palette Si&ze" />
|
||||
|
@ -8,123 +8,12 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/cmd/set_palette.h"
|
||||
#include "app/cmd_sequence.h"
|
||||
#include "app/color.h"
|
||||
#include "app/color_utils.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/params.h"
|
||||
#include "app/console.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/document_undo.h"
|
||||
#include "app/file_selector.h"
|
||||
#include "app/ini_file.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/modules/palettes.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/color_bar.h"
|
||||
#include "app/ui/color_sliders.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/hex_color_entry.h"
|
||||
#include "app/ui/palette_view.h"
|
||||
#include "app/ui/skin/skin_slider_property.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/toolbar.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/fs.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/palette.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "gfx/hsl.h"
|
||||
#include "gfx/hsv.h"
|
||||
#include "gfx/rgb.h"
|
||||
#include "gfx/size.h"
|
||||
#include "ui/graphics.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace gfx;
|
||||
using namespace ui;
|
||||
|
||||
enum { RGB_MODE, HSV_MODE, HSL_MODE };
|
||||
enum { ABS_MODE, REL_MODE };
|
||||
|
||||
class PaletteEntryEditor : public Window {
|
||||
public:
|
||||
PaletteEntryEditor();
|
||||
|
||||
void setColor(const app::Color& color);
|
||||
|
||||
protected:
|
||||
bool onProcessMessage(Message* msg) override;
|
||||
|
||||
void onExit();
|
||||
void onCloseWindow();
|
||||
void onFgBgColorChange(const app::Color& _color);
|
||||
void onColorSlidersChange(ColorSlidersChangeEvent& ev);
|
||||
void onColorHexEntryChange(const app::Color& color);
|
||||
void onColorTypeClick();
|
||||
void onChangeModeClick();
|
||||
|
||||
private:
|
||||
void selectColorType(app::Color::Type type);
|
||||
void setPaletteEntry(const app::Color& color);
|
||||
void setAbsolutePaletteEntryChannel(ColorSliders::Channel channel, const app::Color& color);
|
||||
void setRelativePaletteEntryChannel(ColorSliders::Channel channel, int delta);
|
||||
void setNewPalette(Palette* palette, const char* operationName);
|
||||
void updateCurrentSpritePalette(const char* operationName);
|
||||
void updateColorBar();
|
||||
void updateWidgetsFromSelectedEntries();
|
||||
void onPalChange();
|
||||
void resetRelativeInfo();
|
||||
void getPicks(PalettePicks& picks);
|
||||
|
||||
app::Color::Type m_type;
|
||||
Box m_vbox;
|
||||
Box m_topBox;
|
||||
Box m_bottomBox;
|
||||
ButtonSet m_colorType;
|
||||
ButtonSet m_changeMode;
|
||||
HexColorEntry m_hexColorEntry;
|
||||
Label m_entryLabel;
|
||||
ColorSliders m_sliders;
|
||||
|
||||
// This variable is used to avoid updating the m_hexColorEntry text
|
||||
// when the color change is generated from a
|
||||
// HexColorEntry::ColorChange signal. In this way we don't override
|
||||
// what the user is writting in the text field.
|
||||
bool m_disableHexUpdate;
|
||||
|
||||
ui::Timer m_redrawTimer;
|
||||
bool m_redrawAll;
|
||||
|
||||
// True if the palette change must be implant in the UndoHistory
|
||||
// (e.g. when two or more changes in the palette are made in short
|
||||
// time).
|
||||
bool m_implantChange;
|
||||
|
||||
// True if the PaletteChange signal is generated by the same
|
||||
// PaletteEntryEditor instance.
|
||||
bool m_selfPalChange;
|
||||
|
||||
obs::scoped_connection m_palChangeConn;
|
||||
|
||||
// Palette used for relative changes.
|
||||
Palette m_fromPalette;
|
||||
std::map<ColorSliders::Channel, int> m_relDeltas;
|
||||
};
|
||||
|
||||
static PaletteEntryEditor* g_window = NULL;
|
||||
|
||||
class PaletteEditorCommand : public Command {
|
||||
public:
|
||||
PaletteEditorCommand();
|
||||
@ -132,8 +21,8 @@ public:
|
||||
|
||||
protected:
|
||||
void onLoadParams(const Params& params) override;
|
||||
void onExecute(Context* context) override;
|
||||
bool onChecked(Context* context) override;
|
||||
void onExecute(Context* context) override;
|
||||
|
||||
private:
|
||||
bool m_open;
|
||||
@ -144,7 +33,7 @@ private:
|
||||
|
||||
PaletteEditorCommand::PaletteEditorCommand()
|
||||
: Command("PaletteEditor",
|
||||
"Palette Editor",
|
||||
"Edit Palette",
|
||||
CmdRecordableFlag)
|
||||
{
|
||||
m_open = true;
|
||||
@ -172,656 +61,23 @@ void PaletteEditorCommand::onLoadParams(const Params& params)
|
||||
else m_switch = false;
|
||||
}
|
||||
|
||||
void PaletteEditorCommand::onExecute(Context* context)
|
||||
{
|
||||
// If this is the first time the command is execute...
|
||||
if (!g_window) {
|
||||
// If the command says "Close the palette editor" and it is not
|
||||
// created yet, we just do nothing.
|
||||
if (m_close)
|
||||
return;
|
||||
|
||||
// If this is "open" or "switch", we have to create the frame.
|
||||
g_window = new PaletteEntryEditor();
|
||||
}
|
||||
// If the frame is already created and it's visible, close it (only in "switch" or "close" modes)
|
||||
else if (g_window->isVisible() && (m_switch || m_close)) {
|
||||
// Hide the frame
|
||||
g_window->closeWindow(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_switch || m_open) {
|
||||
if (!g_window->isVisible()) {
|
||||
// Default bounds
|
||||
g_window->remapWindow();
|
||||
|
||||
int width = MAX(g_window->bounds().w, ui::display_w()/2);
|
||||
g_window->setBounds(Rect(
|
||||
ui::display_w() - width - ToolBar::instance()->bounds().w,
|
||||
ui::display_h() - g_window->bounds().h - StatusBar::instance()->bounds().h,
|
||||
width, g_window->bounds().h));
|
||||
|
||||
// Load window configuration
|
||||
load_window_pos(g_window, "PaletteEditor");
|
||||
}
|
||||
|
||||
// Run the frame in background.
|
||||
g_window->openWindow();
|
||||
ColorBar::instance()->setPaletteEditorButtonState(true);
|
||||
}
|
||||
|
||||
// Show the specified target color
|
||||
{
|
||||
app::Color color =
|
||||
(m_background ? Preferences::instance().colorBar.bgColor():
|
||||
Preferences::instance().colorBar.fgColor());
|
||||
|
||||
g_window->setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
bool PaletteEditorCommand::onChecked(Context* context)
|
||||
{
|
||||
if(!g_window)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return g_window->isVisible();
|
||||
return ColorBar::instance()->inEditMode();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// PaletteEntryEditor implementation
|
||||
//
|
||||
// Based on ColorPopup class.
|
||||
|
||||
PaletteEntryEditor::PaletteEntryEditor()
|
||||
: Window(WithTitleBar, "Palette Editor (F4)")
|
||||
, m_type(app::Color::MaskType)
|
||||
, m_vbox(VERTICAL)
|
||||
, m_topBox(HORIZONTAL)
|
||||
, m_bottomBox(HORIZONTAL)
|
||||
, m_colorType(3)
|
||||
, m_changeMode(2)
|
||||
, m_entryLabel("")
|
||||
, m_disableHexUpdate(false)
|
||||
, m_redrawTimer(250, this)
|
||||
, m_redrawAll(false)
|
||||
, m_implantChange(false)
|
||||
, m_selfPalChange(false)
|
||||
, m_fromPalette(0, 0)
|
||||
void PaletteEditorCommand::onExecute(Context* context)
|
||||
{
|
||||
m_colorType.addItem("RGB")->setFocusStop(false);
|
||||
m_colorType.addItem("HSV")->setFocusStop(false);
|
||||
m_colorType.addItem("HSL")->setFocusStop(false);
|
||||
m_changeMode.addItem("Abs")->setFocusStop(false);
|
||||
m_changeMode.addItem("Rel")->setFocusStop(false);
|
||||
bool state = ColorBar::instance()->inEditMode();
|
||||
|
||||
m_topBox.setBorder(gfx::Border(0));
|
||||
m_topBox.setChildSpacing(0);
|
||||
m_bottomBox.setBorder(gfx::Border(0));
|
||||
if (m_switch)
|
||||
state = !state;
|
||||
else if (m_open)
|
||||
state = true;
|
||||
else if (m_close)
|
||||
state = false;
|
||||
|
||||
// Top box
|
||||
m_topBox.addChild(&m_colorType);
|
||||
m_topBox.addChild(new Separator("", VERTICAL));
|
||||
m_topBox.addChild(&m_changeMode);
|
||||
m_topBox.addChild(new Separator("", VERTICAL));
|
||||
m_topBox.addChild(&m_hexColorEntry);
|
||||
m_topBox.addChild(&m_entryLabel);
|
||||
m_topBox.addChild(new BoxFiller);
|
||||
|
||||
// Main vertical box
|
||||
m_vbox.addChild(&m_topBox);
|
||||
m_vbox.addChild(&m_sliders);
|
||||
m_vbox.addChild(&m_bottomBox);
|
||||
addChild(&m_vbox);
|
||||
|
||||
m_colorType.ItemChange.connect(base::Bind<void>(&PaletteEntryEditor::onColorTypeClick, this));
|
||||
m_changeMode.ItemChange.connect(base::Bind<void>(&PaletteEntryEditor::onChangeModeClick, this));
|
||||
|
||||
m_sliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this);
|
||||
m_hexColorEntry.ColorChange.connect(&PaletteEntryEditor::onColorHexEntryChange, this);
|
||||
|
||||
m_changeMode.setSelectedItem(ABS_MODE);
|
||||
selectColorType(app::Color::RgbType);
|
||||
|
||||
// We hook fg/bg color changes (by eyedropper mainly) to update the selected entry color
|
||||
Preferences::instance().colorBar.fgColor.AfterChange.connect(
|
||||
&PaletteEntryEditor::onFgBgColorChange, this);
|
||||
Preferences::instance().colorBar.bgColor.AfterChange.connect(
|
||||
&PaletteEntryEditor::onFgBgColorChange, this);
|
||||
|
||||
// We hook the Window::Close event to save the frame position before closing it.
|
||||
this->Close.connect(base::Bind<void>(&PaletteEntryEditor::onCloseWindow, this));
|
||||
|
||||
// We hook App::Exit signal to destroy the g_window singleton at exit.
|
||||
App::instance()->Exit.connect(&PaletteEntryEditor::onExit, this);
|
||||
|
||||
// Hook for palette change to redraw the palette editor frame
|
||||
m_palChangeConn =
|
||||
App::instance()->PaletteChange.connect(&PaletteEntryEditor::onPalChange, this);
|
||||
|
||||
initTheme();
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::setColor(const app::Color& color)
|
||||
{
|
||||
m_sliders.setColor(color);
|
||||
if (!m_disableHexUpdate)
|
||||
m_hexColorEntry.setColor(color);
|
||||
|
||||
PalettePicks entries;
|
||||
getPicks(entries);
|
||||
int i, j, i2;
|
||||
|
||||
// Find the first selected entry
|
||||
for (i=0; i<(int)entries.size(); ++i)
|
||||
if (entries[i])
|
||||
break;
|
||||
|
||||
// Find the first unselected entry after i
|
||||
for (i2=i+1; i2<(int)entries.size(); ++i2)
|
||||
if (!entries[i2])
|
||||
break;
|
||||
|
||||
// Find the last selected entry
|
||||
for (j=entries.size()-1; j>=0; --j)
|
||||
if (entries[j])
|
||||
break;
|
||||
|
||||
if (i == j) {
|
||||
m_entryLabel.setTextf(" Entry: %d", i);
|
||||
}
|
||||
else if (j-i+1 == i2-i) {
|
||||
m_entryLabel.setTextf(" Range: %d-%d", i, j);
|
||||
}
|
||||
else if (i == int(entries.size())) {
|
||||
m_entryLabel.setText(" No Entry");
|
||||
}
|
||||
else {
|
||||
m_entryLabel.setText(" Multiple Entries");
|
||||
}
|
||||
|
||||
m_topBox.layout();
|
||||
}
|
||||
|
||||
bool PaletteEntryEditor::onProcessMessage(Message* msg)
|
||||
{
|
||||
if (msg->type() == kTimerMessage &&
|
||||
static_cast<TimerMessage*>(msg)->timer() == &m_redrawTimer) {
|
||||
// Redraw all editors
|
||||
if (m_redrawAll) {
|
||||
m_redrawAll = false;
|
||||
m_implantChange = false;
|
||||
m_redrawTimer.stop();
|
||||
|
||||
// Call all observers of PaletteChange event.
|
||||
m_selfPalChange = true;
|
||||
App::instance()->PaletteChange();
|
||||
m_selfPalChange = false;
|
||||
|
||||
// Redraw all editors
|
||||
try {
|
||||
ContextWriter writer(UIContext::instance());
|
||||
Document* document(writer.document());
|
||||
if (document != NULL)
|
||||
document->notifyGeneralUpdate();
|
||||
}
|
||||
catch (...) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
// Redraw just the current editor
|
||||
else {
|
||||
m_redrawAll = true;
|
||||
if (current_editor != NULL)
|
||||
current_editor->updateEditor();
|
||||
}
|
||||
}
|
||||
return Window::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::onExit()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::onCloseWindow()
|
||||
{
|
||||
// Save window configuration
|
||||
save_window_pos(this, "PaletteEditor");
|
||||
|
||||
// Uncheck the "Edit Palette" button.
|
||||
ColorBar::instance()->setPaletteEditorButtonState(false);
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::onFgBgColorChange(const app::Color& _color)
|
||||
{
|
||||
app::Color color = _color;
|
||||
|
||||
if (!color.isValid())
|
||||
return;
|
||||
|
||||
if (color.getType() != app::Color::IndexType) {
|
||||
PaletteView* paletteView = ColorBar::instance()->getPaletteView();
|
||||
int index = paletteView->getSelectedEntry();
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
color = app::Color::fromIndex(index);
|
||||
}
|
||||
|
||||
if (color.getType() == app::Color::IndexType) {
|
||||
setColor(color);
|
||||
resetRelativeInfo();
|
||||
}
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::onColorSlidersChange(ColorSlidersChangeEvent& ev)
|
||||
{
|
||||
setColor(ev.color());
|
||||
|
||||
if (ev.mode() == ColorSliders::Mode::Absolute)
|
||||
setAbsolutePaletteEntryChannel(ev.channel(), ev.color());
|
||||
else
|
||||
setRelativePaletteEntryChannel(ev.channel(), ev.delta());
|
||||
|
||||
updateCurrentSpritePalette("Color Change");
|
||||
updateColorBar();
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::onColorHexEntryChange(const app::Color& color)
|
||||
{
|
||||
// Disable updating the hex entry so we don't override what the user
|
||||
// is writting in the text field.
|
||||
m_disableHexUpdate = true;
|
||||
|
||||
setColor(color);
|
||||
setPaletteEntry(color);
|
||||
updateCurrentSpritePalette("Color Change");
|
||||
updateColorBar();
|
||||
|
||||
m_disableHexUpdate = false;
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::onColorTypeClick()
|
||||
{
|
||||
switch (m_colorType.selectedItem()) {
|
||||
case RGB_MODE:
|
||||
selectColorType(app::Color::RgbType);
|
||||
break;
|
||||
case HSV_MODE:
|
||||
selectColorType(app::Color::HsvType);
|
||||
break;
|
||||
case HSL_MODE:
|
||||
selectColorType(app::Color::HslType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::onChangeModeClick()
|
||||
{
|
||||
switch (m_changeMode.selectedItem()) {
|
||||
case ABS_MODE:
|
||||
m_sliders.setMode(ColorSliders::Mode::Absolute);
|
||||
break;
|
||||
case REL_MODE:
|
||||
m_sliders.setMode(ColorSliders::Mode::Relative);
|
||||
break;
|
||||
}
|
||||
|
||||
// Update sliders, entries, etc.
|
||||
updateWidgetsFromSelectedEntries();
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::setPaletteEntry(const app::Color& color)
|
||||
{
|
||||
PalettePicks entries;
|
||||
getPicks(entries);
|
||||
|
||||
color_t new_pal_color = doc::rgba(color.getRed(),
|
||||
color.getGreen(),
|
||||
color.getBlue(), 255);
|
||||
|
||||
Palette* palette = get_current_palette();
|
||||
for (int c=0; c<palette->size(); c++) {
|
||||
if (entries[c])
|
||||
palette->setEntry(c, new_pal_color);
|
||||
}
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel channel, const app::Color& color)
|
||||
{
|
||||
PalettePicks entries;
|
||||
getPicks(entries);
|
||||
int picksCount = entries.picks();
|
||||
|
||||
uint32_t src_color;
|
||||
int r, g, b, a;
|
||||
|
||||
Palette* palette = get_current_palette();
|
||||
for (int c=0; c<palette->size(); c++) {
|
||||
if (!entries[c])
|
||||
continue;
|
||||
|
||||
// Get the current RGB values of the palette entry
|
||||
src_color = palette->getEntry(c);
|
||||
r = rgba_getr(src_color);
|
||||
g = rgba_getg(src_color);
|
||||
b = rgba_getb(src_color);
|
||||
a = rgba_geta(src_color);
|
||||
|
||||
switch (m_type) {
|
||||
|
||||
case app::Color::RgbType:
|
||||
// Modify one entry
|
||||
if (picksCount == 1) {
|
||||
r = color.getRed();
|
||||
g = color.getGreen();
|
||||
b = color.getBlue();
|
||||
a = color.getAlpha();
|
||||
}
|
||||
// Modify one channel a set of entries
|
||||
else {
|
||||
// Setup the new RGB values depending of the modified channel.
|
||||
switch (channel) {
|
||||
case ColorSliders::Channel::Red:
|
||||
r = color.getRed();
|
||||
case ColorSliders::Channel::Green:
|
||||
g = color.getGreen();
|
||||
break;
|
||||
case ColorSliders::Channel::Blue:
|
||||
b = color.getBlue();
|
||||
break;
|
||||
case ColorSliders::Channel::Alpha:
|
||||
a = color.getAlpha();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case app::Color::HsvType: {
|
||||
Hsv hsv;
|
||||
|
||||
// Modify one entry
|
||||
if (picksCount == 1) {
|
||||
hsv.hue(color.getHsvHue());
|
||||
hsv.saturation(color.getHsvSaturation());
|
||||
hsv.value(color.getHsvValue());
|
||||
a = color.getAlpha();
|
||||
}
|
||||
// Modify one channel a set of entries
|
||||
else {
|
||||
// Convert RGB to HSV
|
||||
hsv = Hsv(Rgb(r, g, b));
|
||||
|
||||
// Only modify the desired HSV channel
|
||||
switch (channel) {
|
||||
case ColorSliders::Channel::HsvHue:
|
||||
hsv.hue(color.getHsvHue());
|
||||
break;
|
||||
case ColorSliders::Channel::HsvSaturation:
|
||||
hsv.saturation(color.getHsvSaturation());
|
||||
break;
|
||||
case ColorSliders::Channel::HsvValue:
|
||||
hsv.value(color.getHsvValue());
|
||||
break;
|
||||
case ColorSliders::Channel::Alpha:
|
||||
a = color.getAlpha();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert HSV back to RGB
|
||||
Rgb rgb(hsv);
|
||||
r = rgb.red();
|
||||
g = rgb.green();
|
||||
b = rgb.blue();
|
||||
break;
|
||||
}
|
||||
|
||||
case app::Color::HslType: {
|
||||
Hsl hsl;
|
||||
|
||||
// Modify one entry
|
||||
if (picksCount == 1) {
|
||||
hsl.hue(color.getHslHue());
|
||||
hsl.saturation(color.getHslSaturation());
|
||||
hsl.lightness(color.getHslLightness());
|
||||
a = color.getAlpha();
|
||||
}
|
||||
// Modify one channel a set of entries
|
||||
else {
|
||||
// Convert RGB to HSL
|
||||
hsl = Hsl(Rgb(r, g, b));
|
||||
|
||||
// Only modify the desired HSL channel
|
||||
switch (channel) {
|
||||
case ColorSliders::Channel::HslHue:
|
||||
hsl.hue(color.getHslHue());
|
||||
break;
|
||||
case ColorSliders::Channel::HslSaturation:
|
||||
hsl.saturation(color.getHslSaturation());
|
||||
break;
|
||||
case ColorSliders::Channel::HslLightness:
|
||||
hsl.lightness(color.getHslLightness());
|
||||
break;
|
||||
case ColorSliders::Channel::Alpha:
|
||||
a = color.getAlpha();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert HSL back to RGB
|
||||
Rgb rgb(hsl);
|
||||
r = rgb.red();
|
||||
g = rgb.green();
|
||||
b = rgb.blue();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
palette->setEntry(c, doc::rgba(r, g, b, a));
|
||||
}
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel channel, int delta)
|
||||
{
|
||||
PalettePicks entries;
|
||||
getPicks(entries);
|
||||
|
||||
// Update modified delta
|
||||
m_relDeltas[channel] = delta;
|
||||
|
||||
uint32_t src_color;
|
||||
int r, g, b, a;
|
||||
|
||||
Palette* palette = get_current_palette();
|
||||
for (int c=0; c<palette->size(); c++) {
|
||||
if (!entries[c])
|
||||
continue;
|
||||
|
||||
// Get the current RGB values of the palette entry
|
||||
src_color = m_fromPalette.getEntry(c);
|
||||
r = rgba_getr(src_color);
|
||||
g = rgba_getg(src_color);
|
||||
b = rgba_getb(src_color);
|
||||
a = rgba_geta(src_color);
|
||||
|
||||
switch (m_type) {
|
||||
|
||||
case app::Color::RgbType:
|
||||
r = MID(0, r+m_relDeltas[ColorSliders::Channel::Red], 255);
|
||||
g = MID(0, g+m_relDeltas[ColorSliders::Channel::Green], 255);
|
||||
b = MID(0, b+m_relDeltas[ColorSliders::Channel::Blue], 255);
|
||||
a = MID(0, a+m_relDeltas[ColorSliders::Channel::Alpha], 255);
|
||||
break;
|
||||
|
||||
case app::Color::HsvType: {
|
||||
// Convert RGB to HSV
|
||||
Hsv hsv(Rgb(r, g, b));
|
||||
|
||||
double h = hsv.hue() +m_relDeltas[ColorSliders::Channel::HsvHue];
|
||||
double s = hsv.saturation()+m_relDeltas[ColorSliders::Channel::HsvSaturation]/100.0;
|
||||
double v = hsv.value() +m_relDeltas[ColorSliders::Channel::HsvValue] /100.0;
|
||||
|
||||
if (h < 0.0) h += 360.0;
|
||||
else if (h > 360.0) h -= 360.0;
|
||||
|
||||
hsv.hue (MID(0.0, h, 360.0));
|
||||
hsv.saturation(MID(0.0, s, 1.0));
|
||||
hsv.value (MID(0.0, v, 1.0));
|
||||
|
||||
// Convert HSV back to RGB
|
||||
Rgb rgb(hsv);
|
||||
r = rgb.red();
|
||||
g = rgb.green();
|
||||
b = rgb.blue();
|
||||
a = MID(0, a+m_relDeltas[ColorSliders::Channel::Alpha], 255);
|
||||
break;
|
||||
}
|
||||
|
||||
case app::Color::HslType: {
|
||||
// Convert RGB to HSL
|
||||
Hsl hsl(Rgb(r, g, b));
|
||||
|
||||
double h = hsl.hue() +m_relDeltas[ColorSliders::Channel::HslHue];
|
||||
double s = hsl.saturation()+m_relDeltas[ColorSliders::Channel::HslSaturation]/100.0;
|
||||
double l = hsl.lightness() +m_relDeltas[ColorSliders::Channel::HslLightness] /100.0;
|
||||
|
||||
if (h < 0.0) h += 360.0;
|
||||
else if (h > 360.0) h -= 360.0;
|
||||
|
||||
hsl.hue (h);
|
||||
hsl.saturation(MID(0.0, s, 1.0));
|
||||
hsl.lightness (MID(0.0, l, 1.0));
|
||||
|
||||
// Convert HSL back to RGB
|
||||
Rgb rgb(hsl);
|
||||
r = rgb.red();
|
||||
g = rgb.green();
|
||||
b = rgb.blue();
|
||||
a = MID(0, a+m_relDeltas[ColorSliders::Alpha], 255);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
palette->setEntry(c, doc::rgba(r, g, b, a));
|
||||
}
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::selectColorType(app::Color::Type type)
|
||||
{
|
||||
m_type = type;
|
||||
m_sliders.setColorType(type);
|
||||
|
||||
resetRelativeInfo();
|
||||
|
||||
switch (type) {
|
||||
case app::Color::RgbType: m_colorType.setSelectedItem(RGB_MODE); break;
|
||||
case app::Color::HsvType: m_colorType.setSelectedItem(HSV_MODE); break;
|
||||
case app::Color::HslType: m_colorType.setSelectedItem(HSL_MODE); break;
|
||||
}
|
||||
|
||||
m_vbox.layout();
|
||||
m_vbox.invalidate();
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::updateCurrentSpritePalette(const char* operationName)
|
||||
{
|
||||
if (UIContext::instance()->activeDocument() &&
|
||||
UIContext::instance()->activeDocument()->sprite()) {
|
||||
try {
|
||||
ContextWriter writer(UIContext::instance());
|
||||
Document* document(writer.document());
|
||||
Sprite* sprite(writer.sprite());
|
||||
Palette* newPalette = get_current_palette(); // System current pal
|
||||
frame_t frame = writer.frame();
|
||||
Palette* currentSpritePalette = sprite->palette(frame); // Sprite current pal
|
||||
int from, to;
|
||||
|
||||
// Check differences between current sprite palette and current system palette
|
||||
from = to = -1;
|
||||
currentSpritePalette->countDiff(newPalette, &from, &to);
|
||||
|
||||
if (from >= 0 && to >= from) {
|
||||
DocumentUndo* undo = document->undoHistory();
|
||||
Cmd* cmd = new cmd::SetPalette(sprite, frame, newPalette);
|
||||
|
||||
// Add undo information to save the range of pal entries that will be modified.
|
||||
if (m_implantChange &&
|
||||
undo->lastExecutedCmd() &&
|
||||
undo->lastExecutedCmd()->label() == operationName) {
|
||||
// Implant the cmd in the last CmdSequence if it's
|
||||
// related about color palette modifications
|
||||
ASSERT(dynamic_cast<CmdSequence*>(undo->lastExecutedCmd()));
|
||||
static_cast<CmdSequence*>(undo->lastExecutedCmd())->add(cmd);
|
||||
cmd->execute(UIContext::instance());
|
||||
}
|
||||
else {
|
||||
Transaction transaction(writer.context(), operationName, ModifyDocument);
|
||||
transaction.execute(cmd);
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (base::Exception& e) {
|
||||
Console::showException(e);
|
||||
}
|
||||
}
|
||||
|
||||
PaletteView* palette_editor = ColorBar::instance()->getPaletteView();
|
||||
palette_editor->invalidate();
|
||||
|
||||
if (!m_redrawTimer.isRunning())
|
||||
m_redrawTimer.start();
|
||||
|
||||
m_redrawAll = false;
|
||||
m_implantChange = true;
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::updateColorBar()
|
||||
{
|
||||
ColorBar::instance()->invalidate();
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::updateWidgetsFromSelectedEntries()
|
||||
{
|
||||
PaletteView* palette_editor = ColorBar::instance()->getPaletteView();
|
||||
int index = palette_editor->getSelectedEntry();
|
||||
if (index >= 0)
|
||||
setColor(app::Color::fromIndex(index));
|
||||
|
||||
resetRelativeInfo();
|
||||
|
||||
// Redraw the window
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::onPalChange()
|
||||
{
|
||||
if (!m_selfPalChange)
|
||||
updateWidgetsFromSelectedEntries();
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::resetRelativeInfo()
|
||||
{
|
||||
m_sliders.resetRelativeSliders();
|
||||
get_current_palette()->copyColorsTo(&m_fromPalette);
|
||||
m_relDeltas.clear();
|
||||
}
|
||||
|
||||
void PaletteEntryEditor::getPicks(PalettePicks& picks)
|
||||
{
|
||||
PaletteView* palView = ColorBar::instance()->getPaletteView();
|
||||
palView->getSelectedEntries(picks);
|
||||
if (picks.picks() == 0) {
|
||||
int i = palView->getSelectedEntry();
|
||||
if (i >= 0 && i < picks.size())
|
||||
picks[i] = true;
|
||||
}
|
||||
ColorBar::instance()->setEditMode(state);
|
||||
}
|
||||
|
||||
Command* CommandFactory::createPaletteEditorCommand()
|
||||
|
@ -47,12 +47,18 @@ WidgetType buttonset_item_type()
|
||||
ButtonSet::Item::Item()
|
||||
: Widget(buttonset_item_type())
|
||||
, m_icon(NULL)
|
||||
, m_hotColor(gfx::ColorNone)
|
||||
{
|
||||
setup_mini_font(this);
|
||||
setAlign(CENTER | MIDDLE);
|
||||
setFocusStop(true);
|
||||
}
|
||||
|
||||
void ButtonSet::Item::setHotColor(gfx::Color color)
|
||||
{
|
||||
m_hotColor = color;
|
||||
}
|
||||
|
||||
void ButtonSet::Item::setIcon(const SkinPartPtr& icon, bool mono)
|
||||
{
|
||||
m_icon = icon;
|
||||
@ -121,7 +127,22 @@ void ButtonSet::Item::onPaint(ui::PaintEvent& ev)
|
||||
rc.h += 3*guiscale();
|
||||
}
|
||||
|
||||
theme->drawRect(g, rc, nw.get());
|
||||
theme->drawRect(g, rc, nw.get(),
|
||||
gfx::is_transparent(m_hotColor));
|
||||
|
||||
if (!gfx::is_transparent(m_hotColor)) {
|
||||
gfx::Rect rc2(rc);
|
||||
gfx::Rect sprite(nw->spriteBounds());
|
||||
gfx::Rect slices(nw->slicesBounds());
|
||||
rc2.shrink(
|
||||
gfx::Border(
|
||||
slices.x-1, // TODO this "-1" is an ugly hack for the pal edit
|
||||
// button, replace all this with styles
|
||||
slices.y-1,
|
||||
sprite.w-slices.w-slices.x-1,
|
||||
sprite.h-slices.h-slices.y));
|
||||
g->fillRect(m_hotColor, rc2);
|
||||
}
|
||||
|
||||
if (m_icon) {
|
||||
she::Surface* bmp = m_icon->bitmap(0);
|
||||
|
@ -21,6 +21,7 @@ namespace app {
|
||||
class Item : public ui::Widget {
|
||||
public:
|
||||
Item();
|
||||
void setHotColor(gfx::Color color);
|
||||
void setIcon(const skin::SkinPartPtr& icon, bool mono = false);
|
||||
skin::SkinPartPtr icon() const { return m_icon; }
|
||||
ButtonSet* buttonSet();
|
||||
@ -33,6 +34,7 @@ namespace app {
|
||||
private:
|
||||
skin::SkinPartPtr m_icon;
|
||||
bool m_mono;
|
||||
gfx::Color m_hotColor;
|
||||
};
|
||||
|
||||
ButtonSet(int columns);
|
||||
|
@ -16,12 +16,14 @@
|
||||
#include "app/cmd/replace_image.h"
|
||||
#include "app/cmd/set_palette.h"
|
||||
#include "app/cmd/set_transparent_color.h"
|
||||
#include "app/cmd_sequence.h"
|
||||
#include "app/color.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/commands/params.h"
|
||||
#include "app/console.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/document_undo.h"
|
||||
#include "app/document_api.h"
|
||||
#include "app/ini_file.h"
|
||||
#include "app/modules/editors.h"
|
||||
@ -64,10 +66,8 @@
|
||||
#include "ui/system.h"
|
||||
#include "ui/tooltips.h"
|
||||
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace app {
|
||||
|
||||
enum class PalButton {
|
||||
@ -122,11 +122,18 @@ ColorBar::ColorBar(int align)
|
||||
, m_bgColor(app::Color::fromRgb(0, 0, 0), IMAGE_RGB, true, false)
|
||||
, m_fgWarningIcon(new WarningIcon)
|
||||
, m_bgWarningIcon(new WarningIcon)
|
||||
, m_lock(false)
|
||||
, m_syncingWithPref(false)
|
||||
, m_fromPalView(false)
|
||||
, m_fromPref(false)
|
||||
, m_fromFgButton(false)
|
||||
, m_fromBgButton(false)
|
||||
, m_lastDocument(nullptr)
|
||||
, m_ascending(true)
|
||||
, m_lastButtons(kButtonLeft)
|
||||
, m_editMode(false)
|
||||
, m_redrawTimer(250, this)
|
||||
, m_redrawAll(false)
|
||||
, m_implantChange(false)
|
||||
, m_selfPalChange(false)
|
||||
{
|
||||
m_instance = this;
|
||||
|
||||
@ -135,9 +142,16 @@ ColorBar::ColorBar(int align)
|
||||
setBorder(gfx::Border(2*guiscale(), 0, 0, 0));
|
||||
setChildSpacing(2*guiscale());
|
||||
|
||||
m_buttons.addItem(theme->parts.palEdit());
|
||||
m_buttons.addItem(theme->parts.palSort());
|
||||
m_buttons.addItem(theme->parts.palPresets());
|
||||
m_buttons.addItem(theme->parts.palOptions());
|
||||
|
||||
m_paletteView.setColumns(8);
|
||||
m_fgColor.setSizeHint(0, m_fgColor.sizeHint().h);
|
||||
m_bgColor.setSizeHint(0, m_bgColor.sizeHint().h);
|
||||
m_buttons.setMaxSize(gfx::Size(m_buttons.sizeHint().w,
|
||||
16*ui::guiscale()));
|
||||
|
||||
// TODO hardcoded scroll bar width should be get from skin.xml file
|
||||
int scrollBarWidth = 6*guiscale();
|
||||
@ -184,9 +198,12 @@ ColorBar::ColorBar(int align)
|
||||
|
||||
m_remapButton.Click.connect(base::Bind<void>(&ColorBar::onRemapButtonClick, this));
|
||||
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_buttons.ItemChange.connect(base::Bind<void>(&ColorBar::onPaletteButtonClick, this));
|
||||
|
||||
m_tooltips.addTooltipFor(&m_fgColor, "Foreground color", LEFT);
|
||||
m_tooltips.addTooltipFor(&m_bgColor, "Background color", LEFT);
|
||||
@ -206,16 +223,6 @@ ColorBar::ColorBar(int align)
|
||||
Widget::setBgColor(theme->colors.tabActiveFace());
|
||||
m_paletteView.setBgColor(theme->colors.tabActiveFace());
|
||||
|
||||
// Change labels foreground color
|
||||
m_buttons.ItemChange.connect(base::Bind<void>(&ColorBar::onPaletteButtonClick, this));
|
||||
|
||||
m_buttons.addItem(theme->parts.palEdit());
|
||||
m_buttons.addItem(theme->parts.palSort());
|
||||
m_buttons.addItem(theme->parts.palPresets());
|
||||
m_buttons.addItem(theme->parts.palOptions());
|
||||
m_buttons.setMaxSize(gfx::Size(m_buttons.sizeHint().w,
|
||||
16*ui::guiscale()));
|
||||
|
||||
// Tooltips
|
||||
TooltipManager* tooltipManager = new TooltipManager();
|
||||
addChild(tooltipManager);
|
||||
@ -234,6 +241,8 @@ ColorBar::ColorBar(int align)
|
||||
m_bgConn = Preferences::instance().colorBar.bgColor.AfterChange.connect(base::Bind<void>(&ColorBar::onBgColorChangeFromPreferences, this));
|
||||
m_paletteView.FocusEnter.connect(&ColorBar::onFocusPaletteView, this);
|
||||
m_appPalChangeConn = App::instance()->PaletteChange.connect(&ColorBar::onAppPaletteChange, this);
|
||||
|
||||
setEditMode(false);
|
||||
}
|
||||
|
||||
ColorBar::~ColorBar()
|
||||
@ -247,29 +256,33 @@ void ColorBar::setPixelFormat(PixelFormat pixelFormat)
|
||||
m_bgColor.setPixelFormat(pixelFormat);
|
||||
}
|
||||
|
||||
app::Color ColorBar::getFgColor()
|
||||
app::Color ColorBar::getFgColor() const
|
||||
{
|
||||
return m_fgColor.getColor();
|
||||
}
|
||||
|
||||
app::Color ColorBar::getBgColor()
|
||||
app::Color ColorBar::getBgColor() const
|
||||
{
|
||||
return m_bgColor.getColor();
|
||||
}
|
||||
|
||||
void ColorBar::setFgColor(const app::Color& color)
|
||||
{
|
||||
m_fgColor.setColor(color);
|
||||
if (m_fromFgButton)
|
||||
return;
|
||||
|
||||
if (!m_lock)
|
||||
m_fgColor.setColor(color);
|
||||
if (!m_fromPalView)
|
||||
onColorButtonChange(color);
|
||||
}
|
||||
|
||||
void ColorBar::setBgColor(const app::Color& color)
|
||||
{
|
||||
m_bgColor.setColor(color);
|
||||
if (m_fromBgButton)
|
||||
return;
|
||||
|
||||
if (!m_lock)
|
||||
m_bgColor.setColor(color);
|
||||
if (!m_fromPalView)
|
||||
onColorButtonChange(color);
|
||||
}
|
||||
|
||||
@ -278,7 +291,7 @@ PaletteView* ColorBar::getPaletteView()
|
||||
return &m_paletteView;
|
||||
}
|
||||
|
||||
ColorBar::ColorSelector ColorBar::getColorSelector()
|
||||
ColorBar::ColorSelector ColorBar::getColorSelector() const
|
||||
{
|
||||
return m_selector;
|
||||
}
|
||||
@ -340,9 +353,20 @@ void ColorBar::setColorSelector(ColorSelector selector)
|
||||
m_selectorPlaceholder.layout();
|
||||
}
|
||||
|
||||
void ColorBar::setPaletteEditorButtonState(bool state)
|
||||
void ColorBar::setEditMode(bool state)
|
||||
{
|
||||
m_buttons.getItem(int(PalButton::EDIT))->setSelected(state);
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
|
||||
ButtonSet::Item* item = m_buttons.getItem((int)PalButton::EDIT);
|
||||
|
||||
m_editMode = state;
|
||||
item->setIcon(state ? theme->parts.timelineOpenPadlockActive():
|
||||
theme->parts.timelineClosedPadlockNormal());
|
||||
item->setHotColor(state ? theme->colors.editPalFace():
|
||||
gfx::ColorNone);
|
||||
|
||||
// Deselect color entries when we cancel editing
|
||||
if (!state)
|
||||
m_paletteView.deselect();
|
||||
}
|
||||
|
||||
void ColorBar::onActiveSiteChange(const doc::Site& site)
|
||||
@ -368,6 +392,9 @@ void ColorBar::onGeneralUpdate(doc::DocumentEvent& ev)
|
||||
|
||||
void ColorBar::onAppPaletteChange()
|
||||
{
|
||||
if (inEditMode())
|
||||
return;
|
||||
|
||||
fixColorIndex(m_fgColor);
|
||||
fixColorIndex(m_bgColor);
|
||||
|
||||
@ -594,7 +621,7 @@ void ColorBar::onRemapButtonClick()
|
||||
|
||||
void ColorBar::onPaletteViewIndexChange(int index, ui::MouseButtons buttons)
|
||||
{
|
||||
m_lock = true;
|
||||
base::ScopedValue<bool> lock(m_fromPalView, true, m_fromPalView);
|
||||
|
||||
app::Color color = app::Color::fromIndex(index);
|
||||
|
||||
@ -606,7 +633,6 @@ void ColorBar::onPaletteViewIndexChange(int index, ui::MouseButtons buttons)
|
||||
setTransparentIndex(index);
|
||||
|
||||
ChangeSelection();
|
||||
m_lock = false;
|
||||
}
|
||||
|
||||
void ColorBar::onPaletteViewModification(const Palette* newPalette,
|
||||
@ -725,31 +751,62 @@ app::Color ColorBar::onPaletteViewGetBackgroundIndex()
|
||||
|
||||
void ColorBar::onFgColorChangeFromPreferences()
|
||||
{
|
||||
if (m_syncingWithPref)
|
||||
if (m_fromPref)
|
||||
return;
|
||||
|
||||
base::ScopedValue<bool> sync(m_syncingWithPref, true, false);
|
||||
base::ScopedValue<bool> sync(m_fromPref, true, false);
|
||||
setFgColor(Preferences::instance().colorBar.fgColor());
|
||||
}
|
||||
|
||||
void ColorBar::onBgColorChangeFromPreferences()
|
||||
{
|
||||
if (m_syncingWithPref)
|
||||
if (m_fromPref)
|
||||
return;
|
||||
|
||||
base::ScopedValue<bool> sync(m_syncingWithPref, true, false);
|
||||
setBgColor(Preferences::instance().colorBar.bgColor());
|
||||
if (inEditMode()) {
|
||||
// In edit mode, clicking with right-click will copy the color
|
||||
// selected with eyedropper to the active color entry.
|
||||
setFgColor(Preferences::instance().colorBar.bgColor());
|
||||
}
|
||||
else {
|
||||
base::ScopedValue<bool> sync(m_fromPref, true, false);
|
||||
setBgColor(Preferences::instance().colorBar.bgColor());
|
||||
}
|
||||
}
|
||||
|
||||
void ColorBar::onFgColorButtonBeforeChange(app::Color& color)
|
||||
{
|
||||
if (m_fromPalView)
|
||||
return;
|
||||
|
||||
if (!inEditMode()) {
|
||||
m_paletteView.deselect();
|
||||
return;
|
||||
}
|
||||
|
||||
// Here we change the selected colors in the
|
||||
// palette. "m_fromPref" must be false to edit the color. (It
|
||||
// means, if the eyedropper was used with the left-click, we don't
|
||||
// edit the color, we just select the color to as the normal
|
||||
// non-edit mode.)
|
||||
if (!m_fromPref) {
|
||||
int i = setPaletteEntry(color);
|
||||
if (i >= 0) {
|
||||
updateCurrentSpritePalette("Color Change");
|
||||
color = app::Color::fromIndex(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ColorBar::onFgColorButtonChange(const app::Color& color)
|
||||
{
|
||||
if (!m_lock) {
|
||||
m_paletteView.deselect();
|
||||
m_paletteView.invalidate();
|
||||
}
|
||||
if (m_fromFgButton)
|
||||
return;
|
||||
|
||||
if (!m_syncingWithPref) {
|
||||
base::ScopedValue<bool> sync(m_syncingWithPref, true, false);
|
||||
base::ScopedValue<bool> lock(m_fromFgButton, true, false);
|
||||
|
||||
if (!m_fromPref) {
|
||||
base::ScopedValue<bool> sync(m_fromPref, true, false);
|
||||
Preferences::instance().colorBar.fgColor(color);
|
||||
}
|
||||
|
||||
@ -759,13 +816,16 @@ void ColorBar::onFgColorButtonChange(const app::Color& color)
|
||||
|
||||
void ColorBar::onBgColorButtonChange(const app::Color& color)
|
||||
{
|
||||
if (!m_lock) {
|
||||
m_paletteView.deselect();
|
||||
m_paletteView.invalidate();
|
||||
}
|
||||
if (m_fromBgButton)
|
||||
return;
|
||||
|
||||
if (!m_syncingWithPref) {
|
||||
base::ScopedValue<bool> sync(m_syncingWithPref, true, false);
|
||||
base::ScopedValue<bool> lock(m_fromBgButton, true, false);
|
||||
|
||||
if (!m_fromPalView && !inEditMode())
|
||||
m_paletteView.deselect();
|
||||
|
||||
if (!m_fromPref) {
|
||||
base::ScopedValue<bool> sync(m_fromPref, true, false);
|
||||
Preferences::instance().colorBar.bgColor(color);
|
||||
}
|
||||
|
||||
@ -775,14 +835,17 @@ void ColorBar::onBgColorButtonChange(const app::Color& color)
|
||||
|
||||
void ColorBar::onColorButtonChange(const app::Color& color)
|
||||
{
|
||||
if (color.getType() == app::Color::IndexType)
|
||||
m_paletteView.selectColor(color.getIndex());
|
||||
else {
|
||||
m_paletteView.selectExactMatchColor(color);
|
||||
if (!inEditMode() ||
|
||||
m_fromPref) {
|
||||
if (color.getType() == app::Color::IndexType)
|
||||
m_paletteView.selectColor(color.getIndex());
|
||||
else {
|
||||
m_paletteView.selectExactMatchColor(color);
|
||||
|
||||
// As foreground or background color changed, we've to redraw the
|
||||
// palette view fg/bg indicators.
|
||||
m_paletteView.invalidate();
|
||||
// As foreground or background color changed, we've to redraw the
|
||||
// palette view fg/bg indicators.
|
||||
m_paletteView.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_tintShadeTone && m_tintShadeTone->isVisible())
|
||||
@ -989,6 +1052,38 @@ void ColorBar::onFixWarningClick(ColorButton* colorButton, ui::Button* warningIc
|
||||
UIContext::instance()->executeCommand(command, params);
|
||||
}
|
||||
|
||||
void ColorBar::onTimerTick()
|
||||
{
|
||||
// Redraw all editors
|
||||
if (m_redrawAll) {
|
||||
m_redrawAll = false;
|
||||
m_implantChange = false;
|
||||
m_redrawTimer.stop();
|
||||
|
||||
// Call all observers of PaletteChange event.
|
||||
m_selfPalChange = true;
|
||||
App::instance()->PaletteChange();
|
||||
m_selfPalChange = false;
|
||||
|
||||
// Redraw all editors
|
||||
try {
|
||||
ContextWriter writer(UIContext::instance());
|
||||
Document* document(writer.document());
|
||||
if (document != NULL)
|
||||
document->notifyGeneralUpdate();
|
||||
}
|
||||
catch (...) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
// Redraw just the current editor
|
||||
else {
|
||||
m_redrawAll = true;
|
||||
if (current_editor != NULL)
|
||||
current_editor->updateEditor();
|
||||
}
|
||||
}
|
||||
|
||||
void ColorBar::updateWarningIcon(const app::Color& color, ui::Button* warningIcon)
|
||||
{
|
||||
int index = -1;
|
||||
@ -1013,6 +1108,94 @@ void ColorBar::updateWarningIcon(const app::Color& color, ui::Button* warningIco
|
||||
warningIcon->parent()->layout();
|
||||
}
|
||||
|
||||
// Changes the selected color palettes with the given
|
||||
// app::Color. Returns the first modified index in the palette.
|
||||
int ColorBar::setPaletteEntry(const app::Color& color)
|
||||
{
|
||||
int selIdx = m_paletteView.getSelectedEntry();
|
||||
if (selIdx < 0) {
|
||||
if (getFgColor().getType() == app::Color::IndexType) {
|
||||
selIdx = getFgColor().getIndex();
|
||||
}
|
||||
}
|
||||
|
||||
PalettePicks entries;
|
||||
m_paletteView.getSelectedEntries(entries);
|
||||
if (entries.picks() == 0) {
|
||||
if (selIdx >= 0 && selIdx < entries.size()) {
|
||||
entries[selIdx] = true;
|
||||
}
|
||||
}
|
||||
|
||||
doc::color_t c =
|
||||
doc::rgba(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
|
||||
|
||||
Palette* palette = get_current_palette();
|
||||
for (int i=0; i<palette->size(); ++i) {
|
||||
if (entries[i])
|
||||
palette->setEntry(i, c);
|
||||
}
|
||||
|
||||
if (selIdx < 0 ||
|
||||
selIdx >= entries.size() ||
|
||||
!entries[selIdx])
|
||||
selIdx = entries.firstPick();
|
||||
|
||||
return selIdx;
|
||||
}
|
||||
|
||||
void ColorBar::updateCurrentSpritePalette(const char* operationName)
|
||||
{
|
||||
if (UIContext::instance()->activeDocument() &&
|
||||
UIContext::instance()->activeDocument()->sprite()) {
|
||||
try {
|
||||
ContextWriter writer(UIContext::instance());
|
||||
Document* document(writer.document());
|
||||
Sprite* sprite(writer.sprite());
|
||||
Palette* newPalette = get_current_palette(); // System current pal
|
||||
frame_t frame = writer.frame();
|
||||
Palette* currentSpritePalette = sprite->palette(frame); // Sprite current pal
|
||||
int from, to;
|
||||
|
||||
// Check differences between current sprite palette and current system palette
|
||||
from = to = -1;
|
||||
currentSpritePalette->countDiff(newPalette, &from, &to);
|
||||
|
||||
if (from >= 0 && to >= from) {
|
||||
DocumentUndo* undo = document->undoHistory();
|
||||
Cmd* cmd = new cmd::SetPalette(sprite, frame, newPalette);
|
||||
|
||||
// Add undo information to save the range of pal entries that will be modified.
|
||||
if (m_implantChange &&
|
||||
undo->lastExecutedCmd() &&
|
||||
undo->lastExecutedCmd()->label() == operationName) {
|
||||
// Implant the cmd in the last CmdSequence if it's
|
||||
// related about color palette modifications
|
||||
ASSERT(dynamic_cast<CmdSequence*>(undo->lastExecutedCmd()));
|
||||
static_cast<CmdSequence*>(undo->lastExecutedCmd())->add(cmd);
|
||||
cmd->execute(UIContext::instance());
|
||||
}
|
||||
else {
|
||||
Transaction transaction(writer.context(), operationName, ModifyDocument);
|
||||
transaction.execute(cmd);
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (base::Exception& e) {
|
||||
Console::showException(e);
|
||||
}
|
||||
}
|
||||
|
||||
m_paletteView.invalidate();
|
||||
|
||||
if (!m_redrawTimer.isRunning())
|
||||
m_redrawTimer.start();
|
||||
|
||||
m_redrawAll = false;
|
||||
m_implantChange = true;
|
||||
}
|
||||
|
||||
// static
|
||||
void ColorBar::fixColorIndex(ColorButton& colorButton)
|
||||
{
|
||||
|
@ -60,19 +60,20 @@ namespace app {
|
||||
|
||||
void setPixelFormat(PixelFormat pixelFormat);
|
||||
|
||||
app::Color getFgColor();
|
||||
app::Color getBgColor();
|
||||
app::Color getFgColor() const;
|
||||
app::Color getBgColor() const;
|
||||
void setFgColor(const app::Color& color);
|
||||
void setBgColor(const app::Color& color);
|
||||
|
||||
PaletteView* getPaletteView();
|
||||
|
||||
ColorSelector getColorSelector();
|
||||
ColorSelector getColorSelector() const;
|
||||
void setColorSelector(ColorSelector selector);
|
||||
|
||||
// Used by the Palette Editor command to change the status of button
|
||||
// when the visibility of the dialog changes.
|
||||
void setPaletteEditorButtonState(bool state);
|
||||
bool inEditMode() const { return m_editMode; }
|
||||
void setEditMode(bool state);
|
||||
|
||||
// ContextObserver impl
|
||||
void onActiveSiteChange(const doc::Site& site) override;
|
||||
@ -104,6 +105,7 @@ namespace app {
|
||||
void onPaletteIndexChange(PaletteIndexChangeEvent& ev);
|
||||
void onFgColorChangeFromPreferences();
|
||||
void onBgColorChangeFromPreferences();
|
||||
void onFgColorButtonBeforeChange(app::Color& color);
|
||||
void onFgColorButtonChange(const app::Color& color);
|
||||
void onBgColorButtonChange(const app::Color& color);
|
||||
void onColorButtonChange(const app::Color& color);
|
||||
@ -112,6 +114,7 @@ namespace app {
|
||||
void onSortBy(doc::SortPaletteBy channel);
|
||||
void onGradient();
|
||||
void onFixWarningClick(ColorButton* colorButton, ui::Button* warningIcon);
|
||||
void onTimerTick();
|
||||
void setAscending(bool ascending);
|
||||
|
||||
// PaletteViewDelegate impl
|
||||
@ -128,6 +131,8 @@ namespace app {
|
||||
void setPalette(const doc::Palette* newPalette, const std::string& actionText);
|
||||
void setTransparentIndex(int index);
|
||||
void updateWarningIcon(const app::Color& color, ui::Button* warningIcon);
|
||||
int setPaletteEntry(const app::Color& color);
|
||||
void updateCurrentSpritePalette(const char* operationName);
|
||||
static void fixColorIndex(ColorButton& color);
|
||||
|
||||
class ScrollableView : public ui::View {
|
||||
@ -154,8 +159,18 @@ namespace app {
|
||||
ColorButton m_bgColor;
|
||||
WarningIcon* m_fgWarningIcon;
|
||||
WarningIcon* m_bgWarningIcon;
|
||||
bool m_lock;
|
||||
bool m_syncingWithPref;
|
||||
|
||||
// True when the user clicks the PaletteView so we're changing the
|
||||
// color from the palette view.
|
||||
bool m_fromPalView;
|
||||
|
||||
// If m_syncingWithPref is true it means that the eyedropper was
|
||||
// used to change the color.
|
||||
bool m_fromPref;
|
||||
|
||||
bool m_fromFgButton;
|
||||
bool m_fromBgButton;
|
||||
|
||||
base::UniquePtr<doc::Palette> m_oldPalette;
|
||||
doc::Document* m_lastDocument;
|
||||
bool m_ascending;
|
||||
@ -165,6 +180,22 @@ namespace app {
|
||||
obs::scoped_connection m_bgConn;
|
||||
obs::scoped_connection m_appPalChangeConn;
|
||||
ui::MouseButtons m_lastButtons;
|
||||
|
||||
// True if we the editing mode is on.
|
||||
bool m_editMode;
|
||||
|
||||
// Timer to redraw editors after a palette change.
|
||||
ui::Timer m_redrawTimer;
|
||||
bool m_redrawAll;
|
||||
|
||||
// True if a palette change must be implant in the UndoHistory
|
||||
// (e.g. when two or more changes in the palette are made in a
|
||||
// very short time).
|
||||
bool m_implantChange;
|
||||
|
||||
// True if the App::PaletteChange signal is generated by this same
|
||||
// ColorBar.
|
||||
bool m_selfPalChange;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -48,7 +48,7 @@ ColorButton::ColorButton(const app::Color& color,
|
||||
: ButtonBase("", colorbutton_type(), kButtonWidget, kButtonWidget)
|
||||
, m_color(color)
|
||||
, m_pixelFormat(pixelFormat)
|
||||
, m_window(NULL)
|
||||
, m_window(nullptr)
|
||||
, m_dependOnLayer(false)
|
||||
, m_canPinSelector(canPinSelector)
|
||||
, m_showSimpleColors(showSimpleColors)
|
||||
@ -82,13 +82,22 @@ app::Color ColorButton::getColor() const
|
||||
return m_color;
|
||||
}
|
||||
|
||||
void ColorButton::setColor(const app::Color& color)
|
||||
void ColorButton::setColor(const app::Color& origColor)
|
||||
{
|
||||
// Before change (this signal can modify the color)
|
||||
app::Color color = origColor;
|
||||
BeforeChange(color);
|
||||
|
||||
m_color = color;
|
||||
|
||||
// Change the color in its related window
|
||||
if (m_window)
|
||||
m_window->setColor(m_color, ColorPopup::DoNotChangeType);
|
||||
if (m_window) {
|
||||
// In the window we show the original color. In case
|
||||
// BeforeChange() has changed the color type (e.g. to index), we
|
||||
// don't care, in the window we prefer to keep the original
|
||||
// HSV/HSL values.
|
||||
m_window->setColor(origColor, ColorPopup::DoNotChangeType);
|
||||
}
|
||||
|
||||
// Emit signal
|
||||
Change(color);
|
||||
|
@ -42,6 +42,7 @@ namespace app {
|
||||
app::Color getColorByPosition(const gfx::Point& pos) override;
|
||||
|
||||
// Signals
|
||||
obs::signal<void(app::Color&)> BeforeChange;
|
||||
obs::signal<void(const app::Color&)> Change;
|
||||
|
||||
protected:
|
||||
|
Loading…
x
Reference in New Issue
Block a user