2006-01-16 22:02:54 +01:00
|
|
|
// Copyright (c) 2005, Niels Martin Hansen
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are met:
|
|
|
|
//
|
|
|
|
// * Redistributions of source code must retain the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer.
|
|
|
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
|
|
// and/or other materials provided with the distribution.
|
|
|
|
// * Neither the name of the Aegisub Group nor the names of its contributors
|
|
|
|
// may be used to endorse or promote products derived from this software
|
|
|
|
// without specific prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
//
|
2009-07-29 07:43:02 +02:00
|
|
|
// Aegisub Project http://www.aegisub.org/
|
|
|
|
|
|
|
|
/// @file dialog_colorpicker.cpp
|
|
|
|
/// @brief Custom colour-selection dialogue box
|
|
|
|
/// @ingroup tools_ui
|
|
|
|
///
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2009-01-04 07:31:48 +01:00
|
|
|
#include "config.h"
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
#include "dialog_colorpicker.h"
|
|
|
|
|
|
|
|
#include "ass_style.h"
|
|
|
|
#include "colorspace.h"
|
|
|
|
#include "compat.h"
|
|
|
|
#include "help_button.h"
|
|
|
|
#include "libresrc/libresrc.h"
|
|
|
|
#include "options.h"
|
|
|
|
#include "persist_location.h"
|
|
|
|
#include "utils.h"
|
|
|
|
|
|
|
|
#include <libaegisub/scoped_ptr.h>
|
2013-06-10 15:58:13 +02:00
|
|
|
#include <libaegisub/util.h>
|
2013-01-10 15:54:41 +01:00
|
|
|
|
2013-06-10 15:58:13 +02:00
|
|
|
#include <memory>
|
2010-06-09 10:14:50 +02:00
|
|
|
#include <vector>
|
2009-09-10 15:06:40 +02:00
|
|
|
|
2010-06-09 10:14:50 +02:00
|
|
|
#include <wx/bitmap.h>
|
|
|
|
#include <wx/button.h>
|
|
|
|
#include <wx/choice.h>
|
2007-09-12 01:22:26 +02:00
|
|
|
#include <wx/dcclient.h>
|
|
|
|
#include <wx/dcmemory.h>
|
|
|
|
#include <wx/dcscreen.h>
|
2010-06-09 10:14:50 +02:00
|
|
|
#include <wx/dialog.h>
|
2009-09-10 15:06:40 +02:00
|
|
|
#include <wx/event.h>
|
|
|
|
#include <wx/gbsizer.h>
|
|
|
|
#include <wx/image.h>
|
2011-01-11 18:22:44 +01:00
|
|
|
#include <wx/rawbmp.h>
|
2007-09-12 01:22:26 +02:00
|
|
|
#include <wx/settings.h>
|
2009-09-10 15:06:40 +02:00
|
|
|
#include <wx/sizer.h>
|
2010-06-09 10:14:50 +02:00
|
|
|
#include <wx/spinctrl.h>
|
|
|
|
#include <wx/statbmp.h>
|
2009-09-10 15:06:40 +02:00
|
|
|
#include <wx/statbox.h>
|
|
|
|
#include <wx/stattext.h>
|
2010-06-09 10:14:50 +02:00
|
|
|
#include <wx/textctrl.h>
|
2008-07-16 03:29:36 +02:00
|
|
|
|
2012-06-12 05:13:55 +02:00
|
|
|
#ifdef __WXMAC__
|
|
|
|
#include <ApplicationServices/ApplicationServices.h>
|
|
|
|
#endif
|
|
|
|
|
2013-01-13 19:46:30 +01:00
|
|
|
namespace {
|
|
|
|
|
2013-01-13 19:49:35 +01:00
|
|
|
enum class PickerDirection {
|
|
|
|
HorzVert,
|
|
|
|
Horz,
|
|
|
|
Vert
|
|
|
|
};
|
|
|
|
|
2013-01-13 19:52:39 +01:00
|
|
|
static const int spectrum_horz_vert_arrow_size = 4;
|
|
|
|
|
|
|
|
wxDEFINE_EVENT(EVT_SPECTRUM_CHANGE, wxCommandEvent);
|
|
|
|
|
2014-03-13 02:39:07 +01:00
|
|
|
class ColorPickerSpectrum final : public wxControl {
|
2011-10-17 19:52:49 +02:00
|
|
|
int x;
|
|
|
|
int y;
|
2010-06-09 10:14:50 +02:00
|
|
|
|
|
|
|
wxBitmap *background;
|
|
|
|
PickerDirection direction;
|
|
|
|
|
2013-01-13 19:52:39 +01:00
|
|
|
void OnPaint(wxPaintEvent &evt) {
|
|
|
|
if (!background) return;
|
|
|
|
|
|
|
|
int height = background->GetHeight();
|
|
|
|
int width = background->GetWidth();
|
|
|
|
wxPaintDC dc(this);
|
|
|
|
|
|
|
|
wxMemoryDC memdc;
|
|
|
|
memdc.SelectObject(*background);
|
|
|
|
dc.Blit(1, 1, width, height, &memdc, 0, 0);
|
|
|
|
|
|
|
|
wxPoint arrow[3];
|
|
|
|
wxRect arrow_box;
|
|
|
|
|
|
|
|
wxPen invpen(*wxWHITE, 3);
|
|
|
|
invpen.SetCap(wxCAP_BUTT);
|
|
|
|
dc.SetLogicalFunction(wxXOR);
|
|
|
|
dc.SetPen(invpen);
|
|
|
|
|
|
|
|
switch (direction) {
|
|
|
|
case PickerDirection::HorzVert:
|
|
|
|
// Make a little cross
|
|
|
|
dc.DrawLine(x-4, y+1, x+7, y+1);
|
|
|
|
dc.DrawLine(x+1, y-4, x+1, y+7);
|
|
|
|
break;
|
|
|
|
case PickerDirection::Horz:
|
|
|
|
// Make a vertical line stretching all the way across
|
|
|
|
dc.DrawLine(x+1, 1, x+1, height+1);
|
|
|
|
// Points for arrow
|
|
|
|
arrow[0] = wxPoint(x+1, height+2);
|
|
|
|
arrow[1] = wxPoint(x+1-spectrum_horz_vert_arrow_size, height+2+spectrum_horz_vert_arrow_size);
|
|
|
|
arrow[2] = wxPoint(x+1+spectrum_horz_vert_arrow_size, height+2+spectrum_horz_vert_arrow_size);
|
|
|
|
|
|
|
|
arrow_box.SetLeft(0);
|
|
|
|
arrow_box.SetTop(height + 2);
|
|
|
|
arrow_box.SetRight(width + 1 + spectrum_horz_vert_arrow_size);
|
|
|
|
arrow_box.SetBottom(height + 2 + spectrum_horz_vert_arrow_size);
|
|
|
|
break;
|
|
|
|
case PickerDirection::Vert:
|
|
|
|
// Make a horizontal line stretching all the way across
|
|
|
|
dc.DrawLine(1, y+1, width+1, y+1);
|
|
|
|
// Points for arrow
|
|
|
|
arrow[0] = wxPoint(width+2, y+1);
|
|
|
|
arrow[1] = wxPoint(width+2+spectrum_horz_vert_arrow_size, y+1-spectrum_horz_vert_arrow_size);
|
|
|
|
arrow[2] = wxPoint(width+2+spectrum_horz_vert_arrow_size, y+1+spectrum_horz_vert_arrow_size);
|
|
|
|
|
|
|
|
arrow_box.SetLeft(width + 2);
|
|
|
|
arrow_box.SetTop(0);
|
|
|
|
arrow_box.SetRight(width + 2 + spectrum_horz_vert_arrow_size);
|
|
|
|
arrow_box.SetBottom(height + 1 + spectrum_horz_vert_arrow_size);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (direction == PickerDirection::Horz || direction == PickerDirection::Vert) {
|
|
|
|
wxBrush bgBrush;
|
|
|
|
bgBrush.SetColour(GetBackgroundColour());
|
|
|
|
dc.SetLogicalFunction(wxCOPY);
|
|
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
|
|
|
dc.SetBrush(bgBrush);
|
|
|
|
dc.DrawRectangle(arrow_box);
|
|
|
|
|
|
|
|
// Arrow pointing at current point
|
|
|
|
dc.SetBrush(*wxBLACK_BRUSH);
|
|
|
|
dc.DrawPolygon(3, arrow);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Border around the spectrum
|
|
|
|
wxPen blkpen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT), 1);
|
|
|
|
blkpen.SetCap(wxCAP_BUTT);
|
|
|
|
|
|
|
|
dc.SetLogicalFunction(wxCOPY);
|
|
|
|
dc.SetPen(blkpen);
|
|
|
|
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
|
|
|
dc.DrawRectangle(0, 0, background->GetWidth()+2, background->GetHeight()+2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnMouse(wxMouseEvent &evt) {
|
|
|
|
evt.Skip();
|
|
|
|
|
|
|
|
// We only care about mouse move events during a drag
|
|
|
|
if (evt.Moving())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (evt.LeftDown()) {
|
|
|
|
CaptureMouse();
|
|
|
|
SetCursor(wxCursor(wxCURSOR_BLANK));
|
|
|
|
}
|
|
|
|
else if (evt.LeftUp() && HasCapture()) {
|
|
|
|
ReleaseMouse();
|
|
|
|
SetCursor(wxNullCursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (evt.LeftDown() || (HasCapture() && evt.LeftIsDown())) {
|
|
|
|
// Adjust for the 1px black border around the control
|
|
|
|
int newx = mid(0, evt.GetX() - 1, GetClientSize().x - 3);
|
|
|
|
int newy = mid(0, evt.GetY() - 1, GetClientSize().y - 3);
|
|
|
|
SetXY(newx, newy);
|
|
|
|
wxCommandEvent evt2(EVT_SPECTRUM_CHANGE, GetId());
|
|
|
|
AddPendingEvent(evt2);
|
|
|
|
}
|
|
|
|
}
|
2010-06-09 10:14:50 +02:00
|
|
|
|
2013-11-21 18:13:36 +01:00
|
|
|
bool AcceptsFocusFromKeyboard() const override { return false; }
|
2012-04-06 17:51:07 +02:00
|
|
|
|
2010-06-09 10:14:50 +02:00
|
|
|
public:
|
2013-01-13 19:52:39 +01:00
|
|
|
ColorPickerSpectrum(wxWindow *parent, PickerDirection direction, wxSize size)
|
|
|
|
: wxControl(parent, -1, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)
|
|
|
|
, x(-1)
|
|
|
|
, y(-1)
|
2013-11-21 18:13:36 +01:00
|
|
|
, background(nullptr)
|
2013-01-13 19:52:39 +01:00
|
|
|
, direction(direction)
|
|
|
|
{
|
|
|
|
size.x += 2;
|
|
|
|
size.y += 2;
|
|
|
|
|
|
|
|
if (direction == PickerDirection::Vert) size.x += spectrum_horz_vert_arrow_size + 1;
|
|
|
|
if (direction == PickerDirection::Horz) size.y += spectrum_horz_vert_arrow_size + 1;
|
|
|
|
|
|
|
|
SetClientSize(size);
|
|
|
|
SetMinSize(GetSize());
|
|
|
|
|
|
|
|
Bind(wxEVT_LEFT_DOWN, &ColorPickerSpectrum::OnMouse, this);
|
|
|
|
Bind(wxEVT_LEFT_UP, &ColorPickerSpectrum::OnMouse, this);
|
|
|
|
Bind(wxEVT_MOTION, &ColorPickerSpectrum::OnMouse, this);
|
|
|
|
Bind(wxEVT_PAINT, &ColorPickerSpectrum::OnPaint, this);
|
|
|
|
}
|
2010-06-09 10:14:50 +02:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
int GetX() const { return x; }
|
|
|
|
int GetY() const { return y; }
|
2013-01-13 19:52:39 +01:00
|
|
|
|
|
|
|
void SetXY(int xx, int yy) {
|
|
|
|
if (x != xx || y != yy) {
|
|
|
|
x = xx;
|
|
|
|
y = yy;
|
|
|
|
Refresh(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Set the background image for this spectrum
|
|
|
|
/// @param new_background New background image
|
|
|
|
/// @param force Repaint even if it appears to be the same image
|
|
|
|
void SetBackground(wxBitmap *new_background, bool force = false) {
|
|
|
|
if (background == new_background && !force) return;
|
|
|
|
background = new_background;
|
|
|
|
Refresh(false);
|
|
|
|
}
|
2010-06-09 10:14:50 +02:00
|
|
|
};
|
|
|
|
|
2013-01-13 19:52:39 +01:00
|
|
|
#ifdef WIN32
|
|
|
|
#define STATIC_BORDER_FLAG wxSTATIC_BORDER
|
|
|
|
#else
|
|
|
|
#define STATIC_BORDER_FLAG wxSIMPLE_BORDER
|
|
|
|
#endif
|
|
|
|
|
|
|
|
wxDEFINE_EVENT(EVT_RECENT_SELECT, wxThreadEvent);
|
|
|
|
|
2010-06-09 10:14:50 +02:00
|
|
|
/// @class ColorPickerRecent
|
2012-10-26 16:09:14 +02:00
|
|
|
/// @brief A grid of recently used colors which can be selected by clicking on them
|
2014-03-13 02:39:07 +01:00
|
|
|
class ColorPickerRecent final : public wxStaticBitmap {
|
2011-10-17 19:52:49 +02:00
|
|
|
int rows; ///< Number of rows of colors
|
|
|
|
int cols; ///< Number of cols of colors
|
|
|
|
int cellsize; ///< Width/Height of each cell
|
2010-06-09 10:14:50 +02:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
/// The colors currently displayed in the control
|
2012-10-26 16:09:14 +02:00
|
|
|
std::vector<agi::Color> colors;
|
2010-06-09 10:14:50 +02:00
|
|
|
|
2013-01-13 19:52:39 +01:00
|
|
|
void OnClick(wxMouseEvent &evt) {
|
|
|
|
wxSize cs = GetClientSize();
|
|
|
|
int cx = evt.GetX() * cols / cs.x;
|
|
|
|
int cy = evt.GetY() * rows / cs.y;
|
|
|
|
if (cx < 0 || cx > cols || cy < 0 || cy > rows) return;
|
|
|
|
int i = cols*cy + cx;
|
|
|
|
|
|
|
|
if (i >= 0 && i < (int)colors.size()) {
|
|
|
|
wxThreadEvent evnt(EVT_RECENT_SELECT, GetId());
|
|
|
|
evnt.SetPayload(colors[i]);
|
|
|
|
AddPendingEvent(evnt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-13 20:04:17 +01:00
|
|
|
void UpdateBitmap() {
|
|
|
|
wxSize sz = GetClientSize();
|
2013-01-13 19:52:39 +01:00
|
|
|
|
2013-01-13 20:04:17 +01:00
|
|
|
wxBitmap background(sz.x, sz.y);
|
|
|
|
wxMemoryDC dc(background);
|
2013-01-13 19:52:39 +01:00
|
|
|
|
2013-01-13 20:04:17 +01:00
|
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
2013-01-13 19:52:39 +01:00
|
|
|
|
2013-01-13 20:04:17 +01:00
|
|
|
for (int cy = 0; cy < rows; cy++) {
|
|
|
|
for (int cx = 0; cx < cols; cx++) {
|
|
|
|
int x = cx * cellsize;
|
|
|
|
int y = cy * cellsize;
|
2013-01-13 19:52:39 +01:00
|
|
|
|
2013-01-13 20:04:17 +01:00
|
|
|
dc.SetBrush(wxBrush(to_wx(colors[cy * cols + cx])));
|
|
|
|
dc.DrawRectangle(x, y, x+cellsize, y+cellsize);
|
2013-01-13 19:52:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-11 19:14:55 +01:00
|
|
|
{
|
|
|
|
wxEventBlocker blocker(this);
|
|
|
|
SetBitmap(background);
|
|
|
|
}
|
|
|
|
|
2013-01-13 20:04:17 +01:00
|
|
|
Refresh(false);
|
2013-01-13 19:52:39 +01:00
|
|
|
}
|
2010-06-09 10:14:50 +02:00
|
|
|
|
2013-11-21 18:13:36 +01:00
|
|
|
bool AcceptsFocusFromKeyboard() const override { return false; }
|
2012-04-06 17:51:07 +02:00
|
|
|
|
2010-06-09 10:14:50 +02:00
|
|
|
public:
|
2013-01-13 19:52:39 +01:00
|
|
|
ColorPickerRecent(wxWindow *parent, int cols, int rows, int cellsize)
|
2013-01-13 20:04:17 +01:00
|
|
|
: wxStaticBitmap(parent, -1, wxBitmap(), wxDefaultPosition, wxDefaultSize, STATIC_BORDER_FLAG)
|
2013-01-13 19:52:39 +01:00
|
|
|
, rows(rows)
|
|
|
|
, cols(cols)
|
|
|
|
, cellsize(cellsize)
|
|
|
|
{
|
|
|
|
colors.resize(rows * cols);
|
|
|
|
SetClientSize(cols*cellsize, rows*cellsize);
|
|
|
|
SetMinSize(GetSize());
|
|
|
|
SetMaxSize(GetSize());
|
|
|
|
SetCursor(*wxCROSS_CURSOR);
|
|
|
|
|
|
|
|
Bind(wxEVT_LEFT_DOWN, &ColorPickerRecent::OnClick, this);
|
2013-01-13 20:04:17 +01:00
|
|
|
Bind(wxEVT_SIZE, [=](wxSizeEvent&) { UpdateBitmap(); });
|
2013-01-13 19:52:39 +01:00
|
|
|
}
|
2010-06-09 10:14:50 +02:00
|
|
|
|
2012-10-26 16:09:14 +02:00
|
|
|
/// Load the colors to show
|
2013-01-13 19:52:39 +01:00
|
|
|
void Load(std::vector<agi::Color> const& recent_colors) {
|
|
|
|
colors = recent_colors;
|
|
|
|
colors.resize(rows * cols);
|
2013-01-13 20:04:17 +01:00
|
|
|
UpdateBitmap();
|
2013-01-13 19:52:39 +01:00
|
|
|
}
|
2012-10-26 16:09:14 +02:00
|
|
|
|
|
|
|
/// Get the list of recent colors
|
2013-01-13 19:52:39 +01:00
|
|
|
std::vector<agi::Color> Save() const { return colors; }
|
2012-10-26 16:09:14 +02:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
/// Add a color to the beginning of the recent list
|
2013-01-13 19:52:39 +01:00
|
|
|
void AddColor(agi::Color color) {
|
|
|
|
auto existing = find(colors.begin(), colors.end(), color);
|
|
|
|
if (existing != colors.end())
|
|
|
|
rotate(colors.begin(), existing, existing + 1);
|
|
|
|
else {
|
|
|
|
colors.insert(colors.begin(), color);
|
|
|
|
colors.pop_back();
|
|
|
|
}
|
|
|
|
|
2013-01-13 20:04:17 +01:00
|
|
|
UpdateBitmap();
|
2013-01-13 19:52:39 +01:00
|
|
|
}
|
2010-06-09 10:14:50 +02:00
|
|
|
};
|
|
|
|
|
2013-01-13 19:52:39 +01:00
|
|
|
wxDEFINE_EVENT(EVT_DROPPER_SELECT, wxThreadEvent);
|
|
|
|
|
2014-03-13 02:39:07 +01:00
|
|
|
class ColorPickerScreenDropper final : public wxControl {
|
2010-06-09 10:14:50 +02:00
|
|
|
wxBitmap capture;
|
|
|
|
|
|
|
|
int resx, resy;
|
|
|
|
int magnification;
|
|
|
|
|
2013-01-13 19:52:39 +01:00
|
|
|
void OnMouse(wxMouseEvent &evt) {
|
|
|
|
int x = evt.GetX();
|
|
|
|
int y = evt.GetY();
|
|
|
|
|
|
|
|
if (x >= 0 && x < capture.GetWidth() && y >= 0 && y < capture.GetHeight()) {
|
|
|
|
wxNativePixelData pd(capture, wxRect(x, y, 1, 1));
|
|
|
|
wxNativePixelData::Iterator pdi(pd.GetPixels());
|
|
|
|
agi::Color color(pdi.Red(), pdi.Green(), pdi.Blue(), 0);
|
|
|
|
|
|
|
|
wxThreadEvent evnt(EVT_DROPPER_SELECT, GetId());
|
|
|
|
evnt.SetPayload(color);
|
|
|
|
AddPendingEvent(evnt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnPaint(wxPaintEvent &evt) {
|
|
|
|
wxPaintDC(this).DrawBitmap(capture, 0, 0);
|
|
|
|
}
|
2010-06-09 10:14:50 +02:00
|
|
|
|
2013-11-21 18:13:36 +01:00
|
|
|
bool AcceptsFocusFromKeyboard() const override { return false; }
|
2012-04-06 17:51:07 +02:00
|
|
|
|
2010-06-09 10:14:50 +02:00
|
|
|
public:
|
2013-01-13 19:52:39 +01:00
|
|
|
ColorPickerScreenDropper(wxWindow *parent, int resx, int resy, int magnification)
|
|
|
|
: wxControl(parent, -1, wxDefaultPosition, wxDefaultSize, STATIC_BORDER_FLAG)
|
|
|
|
, capture(resx * magnification, resy * magnification, wxNativePixelFormat::BitsPerPixel)
|
|
|
|
, resx(resx)
|
|
|
|
, resy(resy)
|
|
|
|
, magnification(magnification)
|
|
|
|
{
|
|
|
|
SetClientSize(resx*magnification, resy*magnification);
|
|
|
|
SetMinSize(GetSize());
|
|
|
|
SetMaxSize(GetSize());
|
|
|
|
SetCursor(*wxCROSS_CURSOR);
|
|
|
|
|
|
|
|
wxMemoryDC capdc(capture);
|
|
|
|
capdc.SetPen(*wxTRANSPARENT_PEN);
|
|
|
|
capdc.SetBrush(*wxWHITE_BRUSH);
|
|
|
|
capdc.DrawRectangle(0, 0, capture.GetWidth(), capture.GetHeight());
|
|
|
|
|
|
|
|
Bind(wxEVT_PAINT, &ColorPickerScreenDropper::OnPaint, this);
|
|
|
|
Bind(wxEVT_LEFT_DOWN, &ColorPickerScreenDropper::OnMouse, this);
|
|
|
|
}
|
2010-06-09 10:14:50 +02:00
|
|
|
|
|
|
|
void DropFromScreenXY(int x, int y);
|
|
|
|
};
|
|
|
|
|
2013-01-13 19:52:39 +01:00
|
|
|
void ColorPickerScreenDropper::DropFromScreenXY(int x, int y) {
|
|
|
|
wxMemoryDC capdc(capture);
|
|
|
|
capdc.SetPen(*wxTRANSPARENT_PEN);
|
|
|
|
#ifndef __WXMAC__
|
|
|
|
wxScreenDC screen;
|
|
|
|
capdc.StretchBlit(0, 0, resx * magnification, resy * magnification,
|
|
|
|
&screen, x - resx / 2, y - resy / 2, resx, resy);
|
|
|
|
#else
|
|
|
|
// wxScreenDC doesn't work on recent versions of OS X so do it manually
|
|
|
|
|
|
|
|
// Doesn't bother handling the case where the rect overlaps two monitors
|
|
|
|
CGDirectDisplayID display_id;
|
|
|
|
uint32_t display_count;
|
|
|
|
CGGetDisplaysWithPoint(CGPointMake(x, y), 1, &display_id, &display_count);
|
|
|
|
|
|
|
|
agi::scoped_holder<CGImageRef> img(CGDisplayCreateImageForRect(display_id, CGRectMake(x - resx / 2, y - resy / 2, resx, resy)), CGImageRelease);
|
|
|
|
NSUInteger width = CGImageGetWidth(img);
|
|
|
|
NSUInteger height = CGImageGetHeight(img);
|
|
|
|
std::vector<uint8_t> imgdata(height * width * 4);
|
|
|
|
|
|
|
|
agi::scoped_holder<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB(), CGColorSpaceRelease);
|
|
|
|
agi::scoped_holder<CGContextRef> bmp_context(CGBitmapContextCreate(&imgdata[0], width, height, 8, 4 * width, colorspace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big), CGContextRelease);
|
|
|
|
|
|
|
|
CGContextDrawImage(bmp_context, CGRectMake(0, 0, width, height), img);
|
|
|
|
|
|
|
|
for (int x = 0; x < resx; x++) {
|
|
|
|
for (int y = 0; y < resy; y++) {
|
|
|
|
uint8_t *pixel = &imgdata[y * width * 4 + x * 4];
|
|
|
|
capdc.SetBrush(wxBrush(wxColour(pixel[0], pixel[1], pixel[2])));
|
|
|
|
capdc.DrawRectangle(x * magnification, y * magnification, magnification, magnification);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Refresh(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-13 02:39:07 +01:00
|
|
|
class DialogColorPicker final : public wxDialog {
|
2013-06-10 15:58:13 +02:00
|
|
|
std::unique_ptr<PersistLocation> persist;
|
2010-06-09 10:14:50 +02:00
|
|
|
|
2012-10-26 16:09:14 +02:00
|
|
|
agi::Color cur_color; ///< Currently selected colour
|
2010-06-09 10:14:50 +02:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
bool spectrum_dirty; ///< Does the spectrum image need to be regenerated?
|
|
|
|
ColorPickerSpectrum *spectrum; ///< The 2D color spectrum
|
|
|
|
ColorPickerSpectrum *slider; ///< The 1D slider for the color component not in the slider
|
2013-01-10 15:54:41 +01:00
|
|
|
ColorPickerSpectrum *alpha_slider;
|
2010-06-09 10:14:50 +02:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
wxChoice *colorspace_choice; ///< The dropdown list to select colorspaces
|
2010-06-09 10:14:50 +02:00
|
|
|
|
|
|
|
wxSpinCtrl *rgb_input[3];
|
2013-01-10 15:54:41 +01:00
|
|
|
wxBitmap rgb_spectrum[3]; ///< x/y spectrum bitmap where color "i" is excluded from
|
|
|
|
wxBitmap rgb_slider[3]; ///< z spectrum for color "i"
|
2011-10-17 19:52:49 +02:00
|
|
|
|
2010-06-09 10:14:50 +02:00
|
|
|
wxSpinCtrl *hsl_input[3];
|
2013-01-10 15:54:41 +01:00
|
|
|
wxBitmap hsl_spectrum; ///< h/s spectrum
|
|
|
|
wxBitmap hsl_slider; ///< l spectrum
|
2011-10-17 19:52:49 +02:00
|
|
|
|
2010-06-09 10:14:50 +02:00
|
|
|
wxSpinCtrl *hsv_input[3];
|
2013-01-10 15:54:41 +01:00
|
|
|
wxBitmap hsv_spectrum; ///< s/v spectrum
|
|
|
|
wxBitmap hsv_slider; ///< h spectrum
|
|
|
|
wxBitmap alpha_slider_img;
|
2010-06-09 10:14:50 +02:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
wxTextCtrl *ass_input;
|
|
|
|
wxTextCtrl *html_input;
|
2013-01-10 15:54:41 +01:00
|
|
|
wxSpinCtrl *alpha_input;
|
2011-10-17 19:52:49 +02:00
|
|
|
|
|
|
|
/// The eyedropper is set to a blank icon when it's clicked, so store its normal bitmap
|
2010-06-09 10:14:50 +02:00
|
|
|
wxBitmap eyedropper_bitmap;
|
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
/// The point where the eyedropper was click, used to make it possible to either
|
|
|
|
/// click the eyedropper or drag the eyedropper
|
2010-06-09 10:14:50 +02:00
|
|
|
wxPoint eyedropper_grab_point;
|
|
|
|
|
|
|
|
bool eyedropper_is_grabbed;
|
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
wxStaticBitmap *preview_box; ///< A box which simply shows the current color
|
|
|
|
ColorPickerRecent *recent_box; ///< A grid of recently used colors
|
2010-06-09 10:14:50 +02:00
|
|
|
|
|
|
|
ColorPickerScreenDropper *screen_dropper;
|
|
|
|
|
|
|
|
wxStaticBitmap *screen_dropper_icon;
|
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
/// Update all other controls as a result of modifying an RGB control
|
|
|
|
void UpdateFromRGB(bool dirty = true);
|
|
|
|
/// Update all other controls as a result of modifying an HSL control
|
|
|
|
void UpdateFromHSL(bool dirty = true);
|
|
|
|
/// Update all other controls as a result of modifying an HSV control
|
|
|
|
void UpdateFromHSV(bool dirty = true);
|
|
|
|
/// Update all other controls as a result of modifying the ASS format control
|
2012-10-12 03:52:36 +02:00
|
|
|
void UpdateFromAss();
|
2011-10-17 19:52:49 +02:00
|
|
|
/// Update all other controls as a result of modifying the HTML format control
|
|
|
|
void UpdateFromHTML();
|
2013-01-10 15:54:41 +01:00
|
|
|
void UpdateFromAlpha();
|
2011-10-17 19:52:49 +02:00
|
|
|
|
2012-10-26 16:09:14 +02:00
|
|
|
void SetRGB(agi::Color new_color);
|
2011-10-17 19:52:49 +02:00
|
|
|
void SetHSL(unsigned char r, unsigned char g, unsigned char b);
|
|
|
|
void SetHSV(unsigned char r, unsigned char g, unsigned char b);
|
|
|
|
|
|
|
|
/// Redraw the spectrum display
|
|
|
|
void UpdateSpectrumDisplay();
|
2010-06-09 10:14:50 +02:00
|
|
|
|
|
|
|
wxBitmap *MakeGBSpectrum();
|
|
|
|
wxBitmap *MakeRBSpectrum();
|
|
|
|
wxBitmap *MakeRGSpectrum();
|
|
|
|
wxBitmap *MakeHSSpectrum();
|
|
|
|
wxBitmap *MakeSVSpectrum();
|
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
/// Constructor helper function for making the color input box sizers
|
|
|
|
template<int N, class Control>
|
|
|
|
wxSizer *MakeColorInputSizer(wxString (&labels)[N], Control *(&inputs)[N]);
|
|
|
|
|
2010-06-09 10:14:50 +02:00
|
|
|
void OnChangeMode(wxCommandEvent &evt);
|
|
|
|
void OnSpectrumChange(wxCommandEvent &evt);
|
|
|
|
void OnSliderChange(wxCommandEvent &evt);
|
2013-01-10 15:54:41 +01:00
|
|
|
void OnAlphaSliderChange(wxCommandEvent &evt);
|
2012-10-26 16:09:14 +02:00
|
|
|
void OnRecentSelect(wxThreadEvent &evt); // also handles dropper pick
|
2010-06-09 10:14:50 +02:00
|
|
|
void OnDropperMouse(wxMouseEvent &evt);
|
|
|
|
void OnMouse(wxMouseEvent &evt);
|
2011-12-22 22:26:30 +01:00
|
|
|
void OnCaptureLost(wxMouseCaptureLostEvent&);
|
2010-06-09 10:14:50 +02:00
|
|
|
|
2012-09-25 01:35:27 +02:00
|
|
|
std::function<void (agi::Color)> callback;
|
2010-06-09 10:14:50 +02:00
|
|
|
|
|
|
|
public:
|
2013-01-13 20:19:13 +01:00
|
|
|
DialogColorPicker(wxWindow *parent, agi::Color initial_color, std::function<void (agi::Color)> callback, bool alpha);
|
2010-06-09 10:14:50 +02:00
|
|
|
~DialogColorPicker();
|
|
|
|
|
2012-10-26 16:09:14 +02:00
|
|
|
void SetColor(agi::Color new_color);
|
2012-11-26 01:47:39 +01:00
|
|
|
void AddColorToRecent();
|
2010-06-09 10:14:50 +02:00
|
|
|
};
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
static const int slider_width = 10; ///< width in pixels of the color slider control
|
|
|
|
static const int alpha_box_size = 5;
|
|
|
|
|
|
|
|
template<typename Func>
|
2013-01-28 16:15:44 +01:00
|
|
|
static wxBitmap make_slider_img(Func func) {
|
2013-01-10 15:54:41 +01:00
|
|
|
unsigned char *slid = (unsigned char *)calloc(slider_width * 256 * 3, 1);
|
|
|
|
func(slid);
|
|
|
|
wxImage img(slider_width, 256, slid);
|
|
|
|
return wxBitmap(img);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-28 16:15:44 +01:00
|
|
|
template<typename Func>
|
|
|
|
static wxBitmap make_slider(Func func) {
|
|
|
|
return make_slider_img([&](unsigned char *slid) {
|
|
|
|
for (int y = 0; y < 256; ++y) {
|
|
|
|
unsigned char rgb[3];
|
|
|
|
func(y, rgb);
|
|
|
|
for (int x = 0; x < slider_width; ++x)
|
|
|
|
memcpy(slid + y * slider_width * 3 + x * 3, rgb, 3);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-01-13 20:19:13 +01:00
|
|
|
DialogColorPicker::DialogColorPicker(wxWindow *parent, agi::Color initial_color, std::function<void (agi::Color)> callback, bool alpha)
|
2012-04-03 19:38:50 +02:00
|
|
|
: wxDialog(parent, -1, _("Select Color"))
|
2013-11-21 18:13:36 +01:00
|
|
|
, callback(std::move(callback))
|
2006-01-16 22:02:54 +01:00
|
|
|
{
|
|
|
|
// generate spectrum slider bar images
|
2013-01-10 15:54:41 +01:00
|
|
|
for (int i = 0; i < 3; ++i) {
|
2013-01-28 16:15:44 +01:00
|
|
|
rgb_slider[i] = make_slider([=](int y, unsigned char *rgb) {
|
|
|
|
memset(rgb, 0, 3);
|
|
|
|
rgb[i] = y;
|
2013-01-10 15:54:41 +01:00
|
|
|
});
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2013-01-28 16:15:44 +01:00
|
|
|
hsl_slider = make_slider([](int y, unsigned char *rgb) { memset(rgb, y, 3); });
|
|
|
|
hsv_slider = make_slider([](int y, unsigned char *rgb) { hsv_to_rgb(y, 255, 255, rgb, rgb + 1, rgb + 2); });
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
// Create the controls for the dialog
|
2012-04-03 19:38:50 +02:00
|
|
|
wxSizer *spectrum_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Color spectrum"));
|
2013-01-13 19:49:35 +01:00
|
|
|
spectrum = new ColorPickerSpectrum(this, PickerDirection::HorzVert, wxSize(256, 256));
|
|
|
|
slider = new ColorPickerSpectrum(this, PickerDirection::Vert, wxSize(slider_width, 256));
|
|
|
|
alpha_slider = new ColorPickerSpectrum(this, PickerDirection::Vert, wxSize(slider_width, 256));
|
2011-10-17 19:52:49 +02:00
|
|
|
wxString modes[] = { _("RGB/R"), _("RGB/G"), _("RGB/B"), _("HSL/L"), _("HSV/H") };
|
|
|
|
colorspace_choice = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, 5, modes);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
wxSize colorinput_size = GetTextExtent(" &H10117B& ");
|
|
|
|
colorinput_size.SetHeight(-1);
|
2006-01-16 22:02:54 +01:00
|
|
|
wxSize colorinput_labelsize(40, -1);
|
|
|
|
|
2012-04-03 19:38:50 +02:00
|
|
|
wxSizer *rgb_box = new wxStaticBoxSizer(wxHORIZONTAL, this, _("RGB color"));
|
|
|
|
wxSizer *hsl_box = new wxStaticBoxSizer(wxVERTICAL, this, _("HSL color"));
|
|
|
|
wxSizer *hsv_box = new wxStaticBoxSizer(wxVERTICAL, this, _("HSV color"));
|
2012-04-06 17:51:00 +02:00
|
|
|
|
2013-11-21 18:13:36 +01:00
|
|
|
for (auto& elem : rgb_input)
|
|
|
|
elem = new wxSpinCtrl(this, -1, "", wxDefaultPosition, colorinput_size, wxSP_ARROW_KEYS, 0, 255);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
ass_input = new wxTextCtrl(this, -1, "", wxDefaultPosition, colorinput_size);
|
|
|
|
html_input = new wxTextCtrl(this, -1, "", wxDefaultPosition, colorinput_size);
|
2013-01-10 15:54:41 +01:00
|
|
|
alpha_input = new wxSpinCtrl(this, -1, "", wxDefaultPosition, colorinput_size, wxSP_ARROW_KEYS, 0, 255);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2013-11-21 18:13:36 +01:00
|
|
|
for (auto& elem : hsl_input)
|
|
|
|
elem = new wxSpinCtrl(this, -1, "", wxDefaultPosition, colorinput_size, wxSP_ARROW_KEYS, 0, 255);
|
2012-04-06 17:51:00 +02:00
|
|
|
|
2013-11-21 18:13:36 +01:00
|
|
|
for (auto& elem : hsv_input)
|
|
|
|
elem = new wxSpinCtrl(this, -1, "", wxDefaultPosition, colorinput_size, wxSP_ARROW_KEYS, 0, 255);
|
2012-04-06 17:51:00 +02:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
preview_box = new wxStaticBitmap(this, -1, wxBitmap(40, 40, 24), wxDefaultPosition, wxSize(40, 40), STATIC_BORDER_FLAG);
|
|
|
|
recent_box = new ColorPickerRecent(this, 8, 4, 16);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2009-07-25 06:49:59 +02:00
|
|
|
eyedropper_bitmap = GETIMAGE(eyedropper_tool_24);
|
2007-07-05 00:16:24 +02:00
|
|
|
eyedropper_bitmap.SetMask(new wxMask(eyedropper_bitmap, wxColour(255, 0, 255)));
|
2011-10-17 19:52:49 +02:00
|
|
|
screen_dropper_icon = new wxStaticBitmap(this, -1, eyedropper_bitmap, wxDefaultPosition, wxDefaultSize, wxRAISED_BORDER);
|
|
|
|
screen_dropper = new ColorPickerScreenDropper(this, 7, 7, 8);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
// Arrange the controls in a nice way
|
|
|
|
wxSizer *spectop_sizer = new wxBoxSizer(wxHORIZONTAL);
|
|
|
|
spectop_sizer->Add(new wxStaticText(this, -1, _("Spectrum mode:")), 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxRIGHT, 5);
|
|
|
|
spectop_sizer->Add(colorspace_choice, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT);
|
|
|
|
spectop_sizer->Add(5, 5, 1, wxEXPAND);
|
|
|
|
spectop_sizer->Add(preview_box, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT);
|
2013-01-13 20:19:13 +01:00
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
wxSizer *spectrum_sizer = new wxFlexGridSizer(3, 5, 5);
|
2006-01-16 22:02:54 +01:00
|
|
|
spectrum_sizer->Add(spectop_sizer, wxEXPAND);
|
|
|
|
spectrum_sizer->AddStretchSpacer(1);
|
2013-01-10 15:54:41 +01:00
|
|
|
spectrum_sizer->AddStretchSpacer(1);
|
2006-01-16 22:02:54 +01:00
|
|
|
spectrum_sizer->Add(spectrum);
|
|
|
|
spectrum_sizer->Add(slider);
|
2013-01-10 15:54:41 +01:00
|
|
|
spectrum_sizer->Add(alpha_slider);
|
2013-01-13 20:19:13 +01:00
|
|
|
if (!alpha)
|
|
|
|
spectrum_sizer->Hide(alpha_slider);
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
spectrum_box->Add(spectrum_sizer, 0, wxALL, 3);
|
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
wxString rgb_labels[] = { _("Red:"), _("Green:"), _("Blue:") };
|
|
|
|
rgb_box->Add(MakeColorInputSizer(rgb_labels, rgb_input), 1, wxALL|wxEXPAND, 3);
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
wxString ass_labels[] = { "ASS:", "HTML:", _("Alpha:") };
|
|
|
|
wxControl *ass_ctrls[] = { ass_input, html_input, alpha_input };
|
2013-01-13 20:19:13 +01:00
|
|
|
auto ass_colors_sizer = MakeColorInputSizer(ass_labels, ass_ctrls);
|
|
|
|
if (!alpha)
|
|
|
|
ass_colors_sizer->Hide(alpha_input);
|
|
|
|
rgb_box->Add(ass_colors_sizer, 0, wxALL|wxCENTER|wxEXPAND, 3);
|
2011-10-17 19:52:49 +02:00
|
|
|
|
|
|
|
wxString hsl_labels[] = { _("Hue:"), _("Sat.:"), _("Lum.:") };
|
|
|
|
hsl_box->Add(MakeColorInputSizer(hsl_labels, hsl_input), 0, wxALL|wxEXPAND, 3);
|
|
|
|
|
|
|
|
wxString hsv_labels[] = { _("Hue:"), _("Sat.:"), _("Value:") };
|
|
|
|
hsv_box->Add(MakeColorInputSizer(hsv_labels, hsv_input), 0, wxALL|wxEXPAND, 3);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2006-07-07 00:16:27 +02:00
|
|
|
wxSizer *hsx_sizer = new wxBoxSizer(wxHORIZONTAL);
|
|
|
|
hsx_sizer->Add(hsl_box);
|
|
|
|
hsx_sizer->AddSpacer(5);
|
|
|
|
hsx_sizer->Add(hsv_box);
|
|
|
|
|
|
|
|
wxSizer *picker_sizer = new wxBoxSizer(wxHORIZONTAL);
|
|
|
|
picker_sizer->AddStretchSpacer();
|
2007-07-05 00:16:24 +02:00
|
|
|
picker_sizer->Add(screen_dropper_icon, 0, wxALIGN_CENTER|wxRIGHT, 5);
|
2006-07-07 00:16:27 +02:00
|
|
|
picker_sizer->Add(screen_dropper, 0, wxALIGN_CENTER);
|
|
|
|
picker_sizer->AddStretchSpacer();
|
2013-12-11 18:38:40 +01:00
|
|
|
picker_sizer->Add(recent_box, 0, wxALIGN_CENTER);
|
2006-07-07 00:16:27 +02:00
|
|
|
picker_sizer->AddStretchSpacer();
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
wxStdDialogButtonSizer *button_sizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL | wxHELP);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2006-07-07 00:16:27 +02:00
|
|
|
wxSizer *input_sizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
input_sizer->Add(rgb_box, 0, wxALIGN_CENTER|wxEXPAND);
|
|
|
|
input_sizer->AddSpacer(5);
|
|
|
|
input_sizer->Add(hsx_sizer, 0, wxALIGN_CENTER|wxEXPAND);
|
|
|
|
input_sizer->AddStretchSpacer(1);
|
|
|
|
input_sizer->Add(picker_sizer, 0, wxALIGN_CENTER|wxEXPAND);
|
|
|
|
input_sizer->AddStretchSpacer(2);
|
|
|
|
input_sizer->Add(button_sizer, 0, wxALIGN_RIGHT|wxALIGN_BOTTOM);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
wxSizer *main_sizer = new wxBoxSizer(wxHORIZONTAL);
|
2008-01-18 18:07:00 +01:00
|
|
|
main_sizer->Add(spectrum_box, 1, wxALL | wxEXPAND, 5);
|
2006-07-07 00:16:27 +02:00
|
|
|
main_sizer->Add(input_sizer, 0, (wxALL&~wxLEFT)|wxEXPAND, 5);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
SetSizerAndFit(main_sizer);
|
|
|
|
|
2013-06-10 15:58:13 +02:00
|
|
|
persist = agi::util::make_unique<PersistLocation>(this, "Tool/Colour Picker");
|
2011-10-17 19:52:49 +02:00
|
|
|
|
2012-05-15 15:39:30 +02:00
|
|
|
// Fill the controls
|
|
|
|
int mode = OPT_GET("Tool/Colour Picker/Mode")->GetInt();
|
|
|
|
if (mode < 0 || mode > 4) mode = 3; // HSL default
|
|
|
|
colorspace_choice->SetSelection(mode);
|
|
|
|
SetColor(initial_color);
|
2012-10-26 16:09:14 +02:00
|
|
|
recent_box->Load(OPT_GET("Tool/Colour Picker/Recent Colours")->GetListColor());
|
2012-05-15 15:39:30 +02:00
|
|
|
|
2012-09-25 01:35:27 +02:00
|
|
|
using std::bind;
|
2011-10-17 19:52:49 +02:00
|
|
|
for (int i = 0; i < 3; ++i) {
|
2013-12-12 03:25:13 +01:00
|
|
|
rgb_input[i]->Bind(wxEVT_SPINCTRL, bind(&DialogColorPicker::UpdateFromRGB, this, true));
|
|
|
|
rgb_input[i]->Bind(wxEVT_TEXT, bind(&DialogColorPicker::UpdateFromRGB, this, true));
|
|
|
|
hsl_input[i]->Bind(wxEVT_SPINCTRL, bind(&DialogColorPicker::UpdateFromHSL, this, true));
|
|
|
|
hsl_input[i]->Bind(wxEVT_TEXT, bind(&DialogColorPicker::UpdateFromHSL, this, true));
|
|
|
|
hsv_input[i]->Bind(wxEVT_SPINCTRL, bind(&DialogColorPicker::UpdateFromHSV, this, true));
|
|
|
|
hsv_input[i]->Bind(wxEVT_TEXT, bind(&DialogColorPicker::UpdateFromHSV, this, true));
|
2011-10-17 19:52:49 +02:00
|
|
|
}
|
2013-12-12 03:25:13 +01:00
|
|
|
ass_input->Bind(wxEVT_TEXT, bind(&DialogColorPicker::UpdateFromAss, this));
|
|
|
|
html_input->Bind(wxEVT_TEXT, bind(&DialogColorPicker::UpdateFromHTML, this));
|
|
|
|
alpha_input->Bind(wxEVT_SPINCTRL, bind(&DialogColorPicker::UpdateFromAlpha, this));
|
|
|
|
alpha_input->Bind(wxEVT_TEXT, bind(&DialogColorPicker::UpdateFromAlpha, this));
|
2011-10-17 19:52:49 +02:00
|
|
|
|
|
|
|
screen_dropper_icon->Bind(wxEVT_MOTION, &DialogColorPicker::OnDropperMouse, this);
|
|
|
|
screen_dropper_icon->Bind(wxEVT_LEFT_DOWN, &DialogColorPicker::OnDropperMouse, this);
|
|
|
|
screen_dropper_icon->Bind(wxEVT_LEFT_UP, &DialogColorPicker::OnDropperMouse, this);
|
2011-12-22 22:26:30 +01:00
|
|
|
screen_dropper_icon->Bind(wxEVT_MOUSE_CAPTURE_LOST, &DialogColorPicker::OnCaptureLost, this);
|
2011-10-17 19:52:49 +02:00
|
|
|
Bind(wxEVT_MOTION, &DialogColorPicker::OnMouse, this);
|
|
|
|
Bind(wxEVT_LEFT_DOWN, &DialogColorPicker::OnMouse, this);
|
|
|
|
Bind(wxEVT_LEFT_UP, &DialogColorPicker::OnMouse, this);
|
|
|
|
|
|
|
|
spectrum->Bind(EVT_SPECTRUM_CHANGE, &DialogColorPicker::OnSpectrumChange, this);
|
|
|
|
slider->Bind(EVT_SPECTRUM_CHANGE, &DialogColorPicker::OnSliderChange, this);
|
2013-01-10 15:54:41 +01:00
|
|
|
alpha_slider->Bind(EVT_SPECTRUM_CHANGE, &DialogColorPicker::OnAlphaSliderChange, this);
|
2011-10-17 19:52:49 +02:00
|
|
|
recent_box->Bind(EVT_RECENT_SELECT, &DialogColorPicker::OnRecentSelect, this);
|
|
|
|
screen_dropper->Bind(EVT_DROPPER_SELECT, &DialogColorPicker::OnRecentSelect, this);
|
|
|
|
|
2013-12-12 03:25:13 +01:00
|
|
|
colorspace_choice->Bind(wxEVT_CHOICE, &DialogColorPicker::OnChangeMode, this);
|
2011-10-17 19:52:49 +02:00
|
|
|
|
2013-12-12 03:25:13 +01:00
|
|
|
button_sizer->GetHelpButton()->Bind(wxEVT_BUTTON, bind(&HelpButton::OpenPage, "Colour Picker"));
|
2011-10-17 19:52:49 +02:00
|
|
|
}
|
2007-07-05 00:16:24 +02:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
template<int N, class Control>
|
2013-01-10 15:54:41 +01:00
|
|
|
wxSizer *DialogColorPicker::MakeColorInputSizer(wxString (&labels)[N], Control *(&inputs)[N]) {
|
2013-11-21 18:13:36 +01:00
|
|
|
auto sizer = new wxFlexGridSizer(2, 5, 5);
|
2011-10-17 19:52:49 +02:00
|
|
|
for (int i = 0; i < N; ++i) {
|
2012-05-15 15:39:40 +02:00
|
|
|
sizer->Add(new wxStaticText(this, -1, labels[i]), wxSizerFlags(1).Center().Left());
|
2011-10-17 19:52:49 +02:00
|
|
|
sizer->Add(inputs[i]);
|
|
|
|
}
|
|
|
|
sizer->AddGrowableCol(0,1);
|
|
|
|
return sizer;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
DialogColorPicker::~DialogColorPicker() {
|
2009-11-01 08:28:09 +01:00
|
|
|
if (screen_dropper_icon->HasCapture()) screen_dropper_icon->ReleaseMouse();
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-14 05:33:49 +01:00
|
|
|
static void change_value(wxSpinCtrl *ctrl, int value) {
|
|
|
|
wxEventBlocker blocker(ctrl);
|
|
|
|
ctrl->SetValue(value);
|
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::SetColor(agi::Color new_color) {
|
2013-01-14 05:33:49 +01:00
|
|
|
change_value(alpha_input, new_color.a);
|
|
|
|
alpha_slider->SetXY(0, new_color.a);
|
|
|
|
cur_color.a = new_color.a;
|
|
|
|
|
2012-10-26 16:09:14 +02:00
|
|
|
SetRGB(new_color);
|
2010-10-16 22:11:48 +02:00
|
|
|
spectrum_dirty = true;
|
2006-01-16 22:02:54 +01:00
|
|
|
UpdateFromRGB();
|
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::AddColorToRecent() {
|
2006-01-16 22:02:54 +01:00
|
|
|
recent_box->AddColor(cur_color);
|
2012-10-26 16:09:14 +02:00
|
|
|
OPT_SET("Tool/Colour Picker/Recent Colours")->SetListColor(recent_box->Save());
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::SetRGB(agi::Color new_color) {
|
2012-10-26 16:09:14 +02:00
|
|
|
change_value(rgb_input[0], new_color.r);
|
|
|
|
change_value(rgb_input[1], new_color.g);
|
|
|
|
change_value(rgb_input[2], new_color.b);
|
2013-01-10 15:54:41 +01:00
|
|
|
new_color.a = cur_color.a;
|
2012-10-26 16:09:14 +02:00
|
|
|
cur_color = new_color;
|
2011-10-17 19:52:49 +02:00
|
|
|
}
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::SetHSL(unsigned char r, unsigned char g, unsigned char b) {
|
2011-10-17 19:52:49 +02:00
|
|
|
unsigned char h, s, l;
|
2006-01-16 22:02:54 +01:00
|
|
|
rgb_to_hsl(r, g, b, &h, &s, &l);
|
2012-05-15 15:39:35 +02:00
|
|
|
change_value(hsl_input[0], h);
|
|
|
|
change_value(hsl_input[1], s);
|
|
|
|
change_value(hsl_input[2], l);
|
2011-10-17 19:52:49 +02:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::SetHSV(unsigned char r, unsigned char g, unsigned char b) {
|
2011-10-17 19:52:49 +02:00
|
|
|
unsigned char h, s, v;
|
|
|
|
rgb_to_hsv(r, g, b, &h, &s, &v);
|
2012-05-15 15:39:35 +02:00
|
|
|
change_value(hsv_input[0], h);
|
|
|
|
change_value(hsv_input[1], s);
|
|
|
|
change_value(hsv_input[2], v);
|
2011-10-17 19:52:49 +02:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::UpdateFromRGB(bool dirty) {
|
|
|
|
unsigned char r = rgb_input[0]->GetValue();
|
|
|
|
unsigned char g = rgb_input[1]->GetValue();
|
|
|
|
unsigned char b = rgb_input[2]->GetValue();
|
2011-10-17 19:52:49 +02:00
|
|
|
SetHSL(r, g, b);
|
|
|
|
SetHSV(r, g, b);
|
2013-01-10 15:54:41 +01:00
|
|
|
cur_color = agi::Color(r, g, b, cur_color.a);
|
2012-11-22 17:21:47 +01:00
|
|
|
ass_input->ChangeValue(to_wx(cur_color.GetAssOverrideFormatted()));
|
2012-10-26 16:09:14 +02:00
|
|
|
html_input->ChangeValue(to_wx(cur_color.GetHexFormatted()));
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
if (dirty)
|
|
|
|
spectrum_dirty = true;
|
|
|
|
UpdateSpectrumDisplay();
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::UpdateFromHSL(bool dirty) {
|
2011-10-17 19:52:49 +02:00
|
|
|
unsigned char r, g, b, h, s, l;
|
2006-01-16 22:02:54 +01:00
|
|
|
h = hsl_input[0]->GetValue();
|
|
|
|
s = hsl_input[1]->GetValue();
|
|
|
|
l = hsl_input[2]->GetValue();
|
|
|
|
hsl_to_rgb(h, s, l, &r, &g, &b);
|
2012-10-26 16:09:14 +02:00
|
|
|
SetRGB(agi::Color(r, g, b));
|
2011-10-17 19:52:49 +02:00
|
|
|
SetHSV(r, g, b);
|
|
|
|
|
2012-11-22 17:21:47 +01:00
|
|
|
ass_input->ChangeValue(to_wx(cur_color.GetAssOverrideFormatted()));
|
2012-10-26 16:09:14 +02:00
|
|
|
html_input->ChangeValue(to_wx(cur_color.GetHexFormatted()));
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
if (dirty)
|
|
|
|
spectrum_dirty = true;
|
|
|
|
UpdateSpectrumDisplay();
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::UpdateFromHSV(bool dirty) {
|
2011-10-17 19:52:49 +02:00
|
|
|
unsigned char r, g, b, h, s, v;
|
|
|
|
h = hsv_input[0]->GetValue();
|
|
|
|
s = hsv_input[1]->GetValue();
|
|
|
|
v = hsv_input[2]->GetValue();
|
|
|
|
hsv_to_rgb(h, s, v, &r, &g, &b);
|
2012-10-26 16:09:14 +02:00
|
|
|
SetRGB(agi::Color(r, g, b));
|
2011-10-17 19:52:49 +02:00
|
|
|
SetHSL(r, g, b);
|
2012-11-22 17:21:47 +01:00
|
|
|
ass_input->ChangeValue(to_wx(cur_color.GetAssOverrideFormatted()));
|
2012-10-26 16:09:14 +02:00
|
|
|
html_input->ChangeValue(to_wx(cur_color.GetHexFormatted()));
|
2011-10-17 19:52:49 +02:00
|
|
|
|
|
|
|
if (dirty)
|
|
|
|
spectrum_dirty = true;
|
2006-01-16 22:02:54 +01:00
|
|
|
UpdateSpectrumDisplay();
|
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::UpdateFromAss() {
|
2012-10-26 16:09:14 +02:00
|
|
|
agi::Color color(from_wx(ass_input->GetValue()));
|
|
|
|
SetRGB(color);
|
|
|
|
SetHSL(color.r, color.g, color.b);
|
|
|
|
SetHSV(color.r, color.g, color.b);
|
|
|
|
html_input->ChangeValue(to_wx(cur_color.GetHexFormatted()));
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
spectrum_dirty = true;
|
|
|
|
UpdateSpectrumDisplay();
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::UpdateFromHTML() {
|
2012-10-26 16:09:14 +02:00
|
|
|
agi::Color color(from_wx(html_input->GetValue()));
|
|
|
|
SetRGB(color);
|
|
|
|
SetHSL(color.r, color.g, color.b);
|
|
|
|
SetHSV(color.r, color.g, color.b);
|
2012-11-22 17:29:33 +01:00
|
|
|
ass_input->ChangeValue(to_wx(cur_color.GetAssOverrideFormatted()));
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
spectrum_dirty = true;
|
|
|
|
UpdateSpectrumDisplay();
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::UpdateFromAlpha() {
|
|
|
|
cur_color.a = alpha_input->GetValue();
|
|
|
|
alpha_slider->SetXY(0, cur_color.a);
|
|
|
|
callback(cur_color);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DialogColorPicker::UpdateSpectrumDisplay() {
|
2006-01-16 22:02:54 +01:00
|
|
|
int i = colorspace_choice->GetSelection();
|
2013-01-10 15:54:41 +01:00
|
|
|
if (spectrum_dirty) {
|
|
|
|
switch (i) {
|
|
|
|
case 0: spectrum->SetBackground(MakeGBSpectrum(), true); break;
|
|
|
|
case 1: spectrum->SetBackground(MakeRBSpectrum(), true); break;
|
|
|
|
case 2: spectrum->SetBackground(MakeRGSpectrum(), true); break;
|
|
|
|
case 3: spectrum->SetBackground(MakeHSSpectrum(), true); break;
|
|
|
|
case 4: spectrum->SetBackground(MakeSVSpectrum(), true); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
switch (i) {
|
2013-01-10 15:54:41 +01:00
|
|
|
case 0: case 1: case 2:
|
|
|
|
slider->SetBackground(&rgb_slider[i]);
|
|
|
|
slider->SetXY(0, rgb_input[i]->GetValue());
|
|
|
|
spectrum->SetXY(rgb_input[2 - (i == 2)]->GetValue(), rgb_input[1 == 0]->GetValue());
|
2006-01-16 22:02:54 +01:00
|
|
|
break;
|
2006-03-16 02:26:26 +01:00
|
|
|
case 3:
|
2013-01-10 15:54:41 +01:00
|
|
|
slider->SetBackground(&hsl_slider);
|
2006-01-16 22:02:54 +01:00
|
|
|
slider->SetXY(0, hsl_input[2]->GetValue());
|
|
|
|
spectrum->SetXY(hsl_input[1]->GetValue(), hsl_input[0]->GetValue());
|
|
|
|
break;
|
2006-03-16 02:26:26 +01:00
|
|
|
case 4:
|
2013-01-10 15:54:41 +01:00
|
|
|
slider->SetBackground(&hsv_slider);
|
2006-01-16 22:02:54 +01:00
|
|
|
slider->SetXY(0, hsv_input[0]->GetValue());
|
|
|
|
spectrum->SetXY(hsv_input[1]->GetValue(), hsv_input[2]->GetValue());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
spectrum_dirty = false;
|
|
|
|
|
2007-01-01 23:56:16 +01:00
|
|
|
wxBitmap tempBmp = preview_box->GetBitmap();
|
|
|
|
{
|
|
|
|
wxMemoryDC previewdc;
|
|
|
|
previewdc.SelectObject(tempBmp);
|
|
|
|
previewdc.SetPen(*wxTRANSPARENT_PEN);
|
2012-10-26 16:09:14 +02:00
|
|
|
previewdc.SetBrush(wxBrush(to_wx(cur_color)));
|
2007-01-01 23:56:16 +01:00
|
|
|
previewdc.DrawRectangle(0, 0, 40, 40);
|
|
|
|
}
|
|
|
|
preview_box->SetBitmap(tempBmp);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2013-01-28 16:15:44 +01:00
|
|
|
alpha_slider_img = make_slider_img([=](unsigned char *slid) {
|
2013-01-10 15:54:41 +01:00
|
|
|
static_assert(slider_width % alpha_box_size == 0, "Slider width must be a multiple of alpha box width");
|
Note: This was done using a script! it's far from perfect but 95% of the work has been done already formatting-wise.
Document all functions, class, struct, union, enum, macro, variable, typedefs. This isn't the actual document in itself but empty documentation using any old documentation if it was there.
This was done using exuberant ctags to get tag info, then a TCL script to parse/remove old comments and convert them into Doxygen-style.
Some notes:
* Anything labeled 'DOCME' needs to be documented, @param and @return have been left blank as it would be annoying to delete the 'DOCME' from every one of those.
* Some multiline comments may have been munged into single line comments
* Leave the /// comments above global variables with a space, if they're harder to read then we'll be less likey to use them.
* Enum comments can go after the enumeration itself '[value] /// comment'
* include/aegisub/*.h haven't been converted yet, this will be done in a later commit
* Some documentation blocks are in the wrong place, in the .h when it should be in the .cpp, or vice versa.
See http://devel.aegisub.org/wiki/Doxygen for some details on Doxygen and a 'style guide'.
Originally committed to SVN as r3312.
2009-07-30 00:59:22 +02:00
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
for (int y = 0; y < 256; ++y) {
|
|
|
|
unsigned char inv_y = 0xFF - y;
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
unsigned char box_colors[] = {
|
|
|
|
static_cast<unsigned char>(0x66 - inv_y * 0x66 / 0xFF),
|
|
|
|
static_cast<unsigned char>(0x99 - inv_y * 0x99 / 0xFF)
|
|
|
|
};
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
if ((y / alpha_box_size) & 1)
|
|
|
|
std::swap(box_colors[0], box_colors[1]);
|
|
|
|
|
|
|
|
unsigned char colors[2][3];
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
|
|
colors[i][0] = cur_color.r * inv_y / 0xFF + box_colors[i];
|
|
|
|
colors[i][1] = cur_color.g * inv_y / 0xFF + box_colors[i];
|
|
|
|
colors[i][2] = cur_color.b * inv_y / 0xFF + box_colors[i];
|
|
|
|
}
|
2011-12-26 23:20:49 +01:00
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
for (int x = 0; x < slider_width; ++x) {
|
|
|
|
*slid++ = colors[x / alpha_box_size][0];
|
|
|
|
*slid++ = colors[x / alpha_box_size][1];
|
|
|
|
*slid++ = colors[x / alpha_box_size][2];
|
|
|
|
}
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2013-01-10 15:54:41 +01:00
|
|
|
});
|
|
|
|
alpha_slider->SetBackground(&alpha_slider_img, true);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
callback(cur_color);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
template<typename Func>
|
|
|
|
static wxBitmap *make_spectrum(wxBitmap *bitmap, Func func) {
|
2013-07-02 18:12:36 +02:00
|
|
|
wxImage spectrum_image(256, 256);
|
|
|
|
func(spectrum_image.GetData());
|
2013-01-10 15:54:41 +01:00
|
|
|
*bitmap = wxBitmap(spectrum_image);
|
|
|
|
return bitmap;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
wxBitmap *DialogColorPicker::MakeGBSpectrum() {
|
|
|
|
return make_spectrum(&rgb_spectrum[0], [=](unsigned char *spec) {
|
2006-01-16 22:02:54 +01:00
|
|
|
for (int g = 0; g < 256; g++) {
|
2013-01-10 15:54:41 +01:00
|
|
|
for (int b = 0; b < 256; b++) {
|
|
|
|
*spec++ = cur_color.r;
|
|
|
|
*spec++ = g;
|
|
|
|
*spec++ = b;
|
|
|
|
}
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2013-01-10 15:54:41 +01:00
|
|
|
});
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
wxBitmap *DialogColorPicker::MakeRBSpectrum() {
|
|
|
|
return make_spectrum(&rgb_spectrum[1], [=](unsigned char *spec) {
|
|
|
|
for (int r = 0; r < 256; r++) {
|
|
|
|
for (int b = 0; b < 256; b++) {
|
|
|
|
*spec++ = r;
|
|
|
|
*spec++ = cur_color.g;
|
|
|
|
*spec++ = b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
wxBitmap *DialogColorPicker::MakeRGSpectrum() {
|
|
|
|
return make_spectrum(&rgb_spectrum[2], [=](unsigned char *spec) {
|
|
|
|
for (int r = 0; r < 256; r++) {
|
|
|
|
for (int g = 0; g < 256; g++) {
|
|
|
|
*spec++ = r;
|
|
|
|
*spec++ = g;
|
|
|
|
*spec++ = cur_color.b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2011-12-26 23:20:49 +01:00
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
wxBitmap *DialogColorPicker::MakeHSSpectrum() {
|
2006-01-16 22:02:54 +01:00
|
|
|
int l = hsl_input[2]->GetValue();
|
2013-01-10 15:54:41 +01:00
|
|
|
return make_spectrum(&hsl_spectrum, [=](unsigned char *spec) {
|
|
|
|
for (int h = 0; h < 256; h++) {
|
|
|
|
unsigned char maxr, maxg, maxb;
|
|
|
|
hsl_to_rgb(h, 255, l, &maxr, &maxg, &maxb);
|
|
|
|
|
|
|
|
for (int s = 0; s < 256; s++) {
|
|
|
|
*spec++ = maxr * s / 256 + (255-s) * l / 256;
|
|
|
|
*spec++ = maxg * s / 256 + (255-s) * l / 256;
|
|
|
|
*spec++ = maxb * s / 256 + (255-s) * l / 256;
|
|
|
|
}
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2013-01-10 15:54:41 +01:00
|
|
|
});
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
wxBitmap *DialogColorPicker::MakeSVSpectrum() {
|
2006-01-16 22:02:54 +01:00
|
|
|
int h = hsv_input[0]->GetValue();
|
|
|
|
unsigned char maxr, maxg, maxb;
|
|
|
|
hsv_to_rgb(h, 255, 255, &maxr, &maxg, &maxb);
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
return make_spectrum(&hsv_spectrum, [=](unsigned char *spec) {
|
|
|
|
for (int v = 0; v < 256; v++) {
|
|
|
|
int rr = (255-maxr) * v / 256;
|
|
|
|
int rg = (255-maxg) * v / 256;
|
|
|
|
int rb = (255-maxb) * v / 256;
|
|
|
|
for (int s = 0; s < 256; s++) {
|
|
|
|
*spec++ = 255 - rr * s / 256 - (255-v);
|
|
|
|
*spec++ = 255 - rg * s / 256 - (255-v);
|
|
|
|
*spec++ = 255 - rb * s / 256 - (255-v);
|
|
|
|
}
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2013-01-10 15:54:41 +01:00
|
|
|
});
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::OnChangeMode(wxCommandEvent &) {
|
2011-10-17 19:52:49 +02:00
|
|
|
spectrum_dirty = true;
|
2010-05-21 03:13:36 +02:00
|
|
|
OPT_SET("Tool/Colour Picker/Mode")->SetInt(colorspace_choice->GetSelection());
|
2006-01-16 22:02:54 +01:00
|
|
|
UpdateSpectrumDisplay();
|
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::OnSpectrumChange(wxCommandEvent &) {
|
2006-01-16 22:02:54 +01:00
|
|
|
int i = colorspace_choice->GetSelection();
|
|
|
|
switch (i) {
|
2013-01-10 15:54:41 +01:00
|
|
|
case 0: case 1: case 2:
|
|
|
|
change_value(rgb_input[2 - (i == 2)], spectrum->GetX());
|
|
|
|
change_value(rgb_input[i == 0], spectrum->GetY());
|
2006-01-16 22:02:54 +01:00
|
|
|
break;
|
2006-03-16 02:26:26 +01:00
|
|
|
case 3:
|
2012-05-15 15:39:45 +02:00
|
|
|
change_value(hsl_input[1], spectrum->GetX());
|
|
|
|
change_value(hsl_input[0], spectrum->GetY());
|
2006-01-16 22:02:54 +01:00
|
|
|
break;
|
2006-03-16 02:26:26 +01:00
|
|
|
case 4:
|
2012-05-15 15:39:45 +02:00
|
|
|
change_value(hsv_input[1], spectrum->GetX());
|
|
|
|
change_value(hsv_input[2], spectrum->GetY());
|
2006-01-16 22:02:54 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-10-17 19:52:49 +02:00
|
|
|
switch (i) {
|
|
|
|
case 0: case 1: case 2:
|
|
|
|
UpdateFromRGB(false);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
UpdateFromHSL(false);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
UpdateFromHSV(false);
|
|
|
|
break;
|
|
|
|
}
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::OnSliderChange(wxCommandEvent &) {
|
2006-01-16 22:02:54 +01:00
|
|
|
spectrum_dirty = true;
|
|
|
|
int i = colorspace_choice->GetSelection();
|
|
|
|
switch (i) {
|
2011-10-17 19:52:49 +02:00
|
|
|
case 0: case 1: case 2:
|
2012-05-15 15:39:45 +02:00
|
|
|
change_value(rgb_input[i], slider->GetY());
|
2011-10-17 19:52:49 +02:00
|
|
|
UpdateFromRGB(false);
|
2006-01-16 22:02:54 +01:00
|
|
|
break;
|
2006-03-16 02:26:26 +01:00
|
|
|
case 3:
|
2012-05-15 15:39:45 +02:00
|
|
|
change_value(hsl_input[2], slider->GetY());
|
2011-10-17 19:52:49 +02:00
|
|
|
UpdateFromHSL(false);
|
2006-01-16 22:02:54 +01:00
|
|
|
break;
|
2006-03-16 02:26:26 +01:00
|
|
|
case 4:
|
2012-05-15 15:39:45 +02:00
|
|
|
change_value(hsv_input[0], slider->GetY());
|
2011-10-17 19:52:49 +02:00
|
|
|
UpdateFromHSV(false);
|
2006-01-16 22:02:54 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::OnAlphaSliderChange(wxCommandEvent &) {
|
|
|
|
change_value(alpha_input, alpha_slider->GetY());
|
|
|
|
cur_color.a = alpha_slider->GetY();
|
|
|
|
callback(cur_color);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DialogColorPicker::OnRecentSelect(wxThreadEvent &evt) {
|
2013-12-24 16:43:19 +01:00
|
|
|
agi::Color new_color = evt.GetPayload<agi::Color>();
|
|
|
|
new_color.a = cur_color.a;
|
|
|
|
SetColor(new_color);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::OnDropperMouse(wxMouseEvent &evt) {
|
2007-07-05 01:47:20 +02:00
|
|
|
if (evt.LeftDown() && !screen_dropper_icon->HasCapture()) {
|
2007-07-05 00:16:24 +02:00
|
|
|
#ifdef WIN32
|
2011-09-28 21:43:11 +02:00
|
|
|
screen_dropper_icon->SetCursor(wxCursor("eyedropper_cursor"));
|
2007-07-05 00:16:24 +02:00
|
|
|
#else
|
2007-07-05 01:47:20 +02:00
|
|
|
screen_dropper_icon->SetCursor(*wxCROSS_CURSOR);
|
2007-07-05 00:16:24 +02:00
|
|
|
#endif
|
2007-07-05 01:47:20 +02:00
|
|
|
screen_dropper_icon->SetBitmap(wxNullBitmap);
|
2010-01-12 04:19:49 +01:00
|
|
|
screen_dropper_icon->CaptureMouse();
|
|
|
|
eyedropper_grab_point = evt.GetPosition();
|
|
|
|
eyedropper_is_grabbed = false;
|
2007-07-05 00:16:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (evt.LeftUp()) {
|
|
|
|
wxPoint ptdiff = evt.GetPosition() - eyedropper_grab_point;
|
2011-10-17 19:52:49 +02:00
|
|
|
bool release_now = eyedropper_is_grabbed || abs(ptdiff.x) + abs(ptdiff.y) > 7;
|
2007-07-05 01:47:20 +02:00
|
|
|
if (release_now) {
|
|
|
|
screen_dropper_icon->ReleaseMouse();
|
|
|
|
eyedropper_is_grabbed = false;
|
|
|
|
screen_dropper_icon->SetCursor(wxNullCursor);
|
|
|
|
screen_dropper_icon->SetBitmap(eyedropper_bitmap);
|
|
|
|
}
|
2013-01-10 15:54:41 +01:00
|
|
|
else
|
|
|
|
eyedropper_is_grabbed = true;
|
2007-07-05 00:16:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (screen_dropper_icon->HasCapture()) {
|
|
|
|
wxPoint scrpos = screen_dropper_icon->ClientToScreen(evt.GetPosition());
|
|
|
|
screen_dropper->DropFromScreenXY(scrpos.x, scrpos.y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-12 04:19:49 +01:00
|
|
|
/// @brief Hack to redirect events to the screen dropper icon
|
2013-01-10 15:54:41 +01:00
|
|
|
void DialogColorPicker::OnMouse(wxMouseEvent &evt) {
|
|
|
|
if (!screen_dropper_icon->HasCapture()) {
|
2010-01-12 04:19:49 +01:00
|
|
|
evt.Skip();
|
2013-01-10 15:54:41 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
wxPoint dropper_pos = screen_dropper_icon->ScreenToClient(ClientToScreen(evt.GetPosition()));
|
|
|
|
evt.m_x = dropper_pos.x;
|
|
|
|
evt.m_y = dropper_pos.y;
|
|
|
|
screen_dropper_icon->GetEventHandler()->ProcessEvent(evt);
|
2010-01-12 04:19:49 +01:00
|
|
|
}
|
2011-12-22 22:26:30 +01:00
|
|
|
|
|
|
|
void DialogColorPicker::OnCaptureLost(wxMouseCaptureLostEvent&) {
|
|
|
|
eyedropper_is_grabbed = false;
|
|
|
|
screen_dropper_icon->SetCursor(wxNullCursor);
|
|
|
|
screen_dropper_icon->SetBitmap(eyedropper_bitmap);
|
|
|
|
}
|
2013-01-13 19:46:30 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-01-13 20:19:13 +01:00
|
|
|
bool GetColorFromUser(wxWindow* parent, agi::Color original, bool alpha, std::function<void (agi::Color)> callback) {
|
|
|
|
DialogColorPicker dialog(parent, original, callback, alpha);
|
2013-01-13 19:46:30 +01:00
|
|
|
bool ok = dialog.ShowModal() == wxID_OK;
|
|
|
|
if (!ok)
|
|
|
|
callback(original);
|
|
|
|
else
|
|
|
|
dialog.AddColorToRecent();
|
|
|
|
return ok;
|
|
|
|
}
|