mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-12 13:37:00 -04:00
ImageValueEditor; slice window; fixed bug in resample
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@97 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -93,8 +93,8 @@ void resample_pass(const Image& img_in, Image& img_out, int offset_in, int offse
|
|||||||
if (out_rem > 0) {
|
if (out_rem > 0) {
|
||||||
// eat a partial input pixel
|
// eat a partial input pixel
|
||||||
totR += in[0] * out_rem;
|
totR += in[0] * out_rem;
|
||||||
totR += in[1] * out_rem;
|
totG += in[1] * out_rem;
|
||||||
totR += in[2] * out_rem;
|
totB += in[2] * out_rem;
|
||||||
in_rem -= out_rem;
|
in_rem -= out_rem;
|
||||||
}
|
}
|
||||||
// store
|
// store
|
||||||
|
|||||||
@@ -175,30 +175,35 @@ bool CardListBase::canPaste() const {
|
|||||||
return wxTheClipboard->IsSupported(CardDataObject::format);
|
return wxTheClipboard->IsSupported(CardDataObject::format);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardListBase::doCopy() {
|
bool CardListBase::doCopy() {
|
||||||
if (!canCopy()) return;
|
if (!canCopy()) return false;
|
||||||
if (!wxTheClipboard->Open()) return;
|
if (!wxTheClipboard->Open()) return false;
|
||||||
wxTheClipboard->SetData(new CardOnClipboard(set, selected_card)); // ignore result
|
bool ok = wxTheClipboard->SetData(new CardOnClipboard(set, selected_card)); // ignore result
|
||||||
wxTheClipboard->Close();
|
wxTheClipboard->Close();
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
void CardListBase::doCut() {
|
bool CardListBase::doCut() {
|
||||||
// cut = copy + delete
|
// cut = copy + delete
|
||||||
if (!canCut()) return;
|
if (!canCut()) return false;
|
||||||
doCopy();
|
if (!doCopy()) return false;
|
||||||
set->actions.add(new RemoveCardAction(*set, selected_card) );
|
set->actions.add(new RemoveCardAction(*set, selected_card));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
void CardListBase::doPaste() {
|
bool CardListBase::doPaste() {
|
||||||
// get data
|
// get data
|
||||||
if (!canPaste()) return;
|
if (!canPaste()) return false;
|
||||||
if (!wxTheClipboard->Open()) return;
|
if (!wxTheClipboard->Open()) return false;
|
||||||
CardDataObject data;
|
CardDataObject data;
|
||||||
bool ok = wxTheClipboard->GetData(data);
|
bool ok = wxTheClipboard->GetData(data);
|
||||||
wxTheClipboard->Close();
|
wxTheClipboard->Close();
|
||||||
if (!ok) return;
|
if (!ok) return false;
|
||||||
// add card to set
|
// add card to set
|
||||||
CardP card = data.getCard(set);
|
CardP card = data.getCard(set);
|
||||||
if (card) {
|
if (card) {
|
||||||
set->actions.add(new AddCardAction(*set, card));
|
set->actions.add(new AddCardAction(*set, card));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,9 +69,10 @@ class CardListBase : public wxListView, public SetView {
|
|||||||
bool canCut() const;
|
bool canCut() const;
|
||||||
bool canCopy() const;
|
bool canCopy() const;
|
||||||
bool canPaste() const;
|
bool canPaste() const;
|
||||||
void doCut();
|
// Try to perform a clipboard operation, return success
|
||||||
void doCopy();
|
bool doCut();
|
||||||
void doPaste();
|
bool doCopy();
|
||||||
|
bool doPaste();
|
||||||
|
|
||||||
// --------------------------------------------------- : Set actions
|
// --------------------------------------------------- : Set actions
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,618 @@
|
|||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||||
|
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||||
|
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
|
#include <gui/image_slice_window.hpp>
|
||||||
|
#include <util/window_id.hpp>
|
||||||
|
#include <gfx/gfx.hpp>
|
||||||
|
#include <wx/spinctrl.h>
|
||||||
|
#include <wx/dcbuffer.h>
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSlice
|
||||||
|
|
||||||
|
ImageSlice::ImageSlice(const Image& source, const wxSize& target_size)
|
||||||
|
: source(source), target_size(target_size)
|
||||||
|
, selection(0, 0, source.GetWidth(), source.GetHeight())
|
||||||
|
, allow_outside(false), aspect_fixed(true)
|
||||||
|
, sharpen(true), sharpen_amount(25)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ImageSlice::constrain() {
|
||||||
|
sharpen_amount = min(100, max(0, sharpen_amount));
|
||||||
|
// minimum size
|
||||||
|
selection.width = max(1, selection.width);
|
||||||
|
selection.height = max(1, selection.height);
|
||||||
|
// inside source
|
||||||
|
if (!allow_outside) {
|
||||||
|
selection.width = min(selection.width, source.GetWidth());
|
||||||
|
selection.height = min(selection.height, source.GetHeight());
|
||||||
|
selection.x = max(selection.x, 0);
|
||||||
|
selection.y = max(selection.y, 0);
|
||||||
|
selection.x = min(selection.x, source.GetWidth() - selection.width);
|
||||||
|
selection.y = min(selection.y, source.GetHeight() - selection.height);
|
||||||
|
}
|
||||||
|
// fix aspect ratio
|
||||||
|
if (aspect_fixed) {
|
||||||
|
int diff = selection.width * target_size.GetHeight() - selection.height * target_size.GetWidth();
|
||||||
|
if (diff > 0) {
|
||||||
|
// too wide
|
||||||
|
selection.width -= diff / target_size.GetHeight();
|
||||||
|
} else {
|
||||||
|
// too high
|
||||||
|
selection.height -= -diff / target_size.GetWidth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image ImageSlice::getSlice() const {
|
||||||
|
if (selection.width == target_size.GetWidth() && selection.height == target_size.GetHeight() && selection.x == 0 && selection.y == 0) {
|
||||||
|
// exactly the right size
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
Image target(target_size.GetWidth(), target_size.GetHeight(), false);
|
||||||
|
// if (sharpen && sharpen_amount > 0) {
|
||||||
|
// sharp_resample_and_clip(source, target, selection, sharpen_amount);
|
||||||
|
// } else {
|
||||||
|
resample_and_clip(source, target, selection);
|
||||||
|
// }
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSliceWindow
|
||||||
|
|
||||||
|
ImageSliceWindow::ImageSliceWindow(Window* parent, const Image& source, const wxSize& target_size)
|
||||||
|
: wxDialog(parent,wxID_ANY,_("Slice image"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxFULL_REPAINT_ON_RESIZE)
|
||||||
|
, slice(source, target_size)
|
||||||
|
{
|
||||||
|
// init controls
|
||||||
|
const wxPoint defPos = wxDefaultPosition;
|
||||||
|
const wxSize spinSize(80,-1);
|
||||||
|
selector = new ImageSliceSelector(this, ID_SELECTOR, slice);
|
||||||
|
preview = new ImageSlicePreview (this, ID_PREVIEW, slice);
|
||||||
|
|
||||||
|
String sizes[] = { _("&Original Size")
|
||||||
|
, _("Size to &Fit")
|
||||||
|
, _("F&orce to Fit")
|
||||||
|
, _("&Custom Size") };
|
||||||
|
size = new wxRadioBox(this, ID_SIZE, _("Size"), defPos, wxDefaultSize, 4, sizes, 1);
|
||||||
|
|
||||||
|
left = new wxSpinCtrl(this, ID_LEFT, _(""), defPos, spinSize);
|
||||||
|
top = new wxSpinCtrl(this, ID_TOP, _(""), defPos, spinSize);
|
||||||
|
width = new wxSpinCtrl(this, ID_WIDTH, _(""), defPos, spinSize);
|
||||||
|
height = new wxSpinCtrl(this, ID_HEIGHT, _(""), defPos, spinSize);
|
||||||
|
top ->SetRange(-5000,5000);
|
||||||
|
left ->SetRange(-5000,5000);
|
||||||
|
width ->SetRange(0,5000);
|
||||||
|
height->SetRange(0,5000);
|
||||||
|
|
||||||
|
fix_aspect = new wxCheckBox(this, ID_FIX_ASPECT, _("Fix aspect ratio (width/height)"));
|
||||||
|
zoom_x = new wxSpinCtrl(this, ID_ZOOM_X, _(""), defPos, spinSize);
|
||||||
|
zoom_y = new wxSpinCtrl(this, ID_ZOOM_Y, _(""), defPos, spinSize);
|
||||||
|
zoom = new wxSpinCtrl(this, ID_ZOOM, _(""), defPos, spinSize);
|
||||||
|
zoom_x->SetRange(1,10000);
|
||||||
|
zoom_y->SetRange(1,10000);
|
||||||
|
zoom ->SetRange(1,10000);
|
||||||
|
|
||||||
|
sharpen = new wxCheckBox(this, ID_SHARPEN, _("&Sharpen Filter"));
|
||||||
|
sharpen_amount = new wxSlider(this, ID_SHARPEN_AMOUNT, 0, 0, 100);
|
||||||
|
// allowOutside= new CheckBox(&this, idSliceAllowOutside, _("Allow selection outside source"))
|
||||||
|
// bgColor = new ColorSelector(&this, wxID_ANY)
|
||||||
|
|
||||||
|
// init sizers
|
||||||
|
wxSizer* s = new wxBoxSizer(wxVERTICAL);
|
||||||
|
// top row: image editors
|
||||||
|
wxSizer* s2 = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
wxSizer* s3 = new wxBoxSizer(wxVERTICAL);
|
||||||
|
s3->Add(new wxStaticText(this, wxID_ANY, _("Original:")));
|
||||||
|
s3->Add(selector, 1, wxEXPAND | wxTOP, 4);
|
||||||
|
s2->Add(s3, 1, wxEXPAND | wxALL, 4);
|
||||||
|
wxSizer* s4 = new wxBoxSizer(wxVERTICAL);
|
||||||
|
s4->Add(new wxStaticText(this, wxID_ANY, _("Result:")));
|
||||||
|
s4->Add(preview, 0, wxTOP, 4);
|
||||||
|
s2->Add(s4, 0, wxALL, 4);
|
||||||
|
s->Add(s2, 1, wxEXPAND);
|
||||||
|
// bottom row: controls
|
||||||
|
wxSizer* s5 = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
s5->AddStretchSpacer(1);
|
||||||
|
s5->Add(size, 0, wxEXPAND | wxALL, 4);
|
||||||
|
s5->AddStretchSpacer(1);
|
||||||
|
wxSizer* s6 = new wxStaticBoxSizer(wxVERTICAL, this, _("Selection"));
|
||||||
|
wxSizer* s7 = new wxFlexGridSizer(0, 2, 4, 5);
|
||||||
|
s7->Add(new wxStaticText(this, wxID_ANY, _("&Left")), 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
s7->Add(left, 0, wxEXPAND);
|
||||||
|
s7->Add(new wxStaticText(this, wxID_ANY, _("&Top")), 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
s7->Add(top, 0, wxEXPAND);
|
||||||
|
s7->Add(new wxStaticText(this, wxID_ANY, _("&Width")), 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
s7->Add(width, 0, wxEXPAND);
|
||||||
|
s7->Add(new wxStaticText(this, wxID_ANY, _("&Height")), 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
s7->Add(height, 0, wxEXPAND);
|
||||||
|
s6->Add(s7, 1, wxEXPAND | wxALL, 4);
|
||||||
|
s5->Add(s6, 0, wxEXPAND | wxALL, 4);
|
||||||
|
s5->AddStretchSpacer(1);
|
||||||
|
wxSizer* s8 = zoom_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Zoom"));
|
||||||
|
s8->Add(fix_aspect, 0, wxEXPAND | wxALL & ~wxBOTTOM, 4);
|
||||||
|
wxSizer* s9 = zoom_fixed = new wxFlexGridSizer(0, 3, 4, 5);
|
||||||
|
s9->Add(new wxStaticText(this, wxID_ANY, _("&Zoom")), 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
s9->Add(zoom, 0, wxEXPAND);
|
||||||
|
s9->Add(new wxStaticText(this, wxID_ANY, _("%")), 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
s8->Add(s9, 0, wxEXPAND | wxALL, 4);
|
||||||
|
wxSizer* sA = zoom_free = new wxFlexGridSizer(0, 3, 4, 5);
|
||||||
|
sA->Add(new wxStaticText(this, wxID_ANY, _("Zoom &X")), 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
sA->Add(zoom_x, 0, wxEXPAND);
|
||||||
|
sA->Add(new wxStaticText(this, wxID_ANY, _("%")), 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
sA->Add(new wxStaticText(this, wxID_ANY, _("Zoom &Y")), 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
sA->Add(zoom_y, 0, wxEXPAND);
|
||||||
|
sA->Add(new wxStaticText(this, wxID_ANY, _("%")), 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
s8->Add(sA, 0, wxEXPAND | wxALL, 4);
|
||||||
|
s5->Add(s8, 0, wxEXPAND | wxALL, 4);
|
||||||
|
s5->AddStretchSpacer(1);
|
||||||
|
wxSizer* sB = new wxStaticBoxSizer(wxVERTICAL, this, _("Filter"));
|
||||||
|
sB->Add(sharpen, 0, wxEXPAND | wxALL & ~wxBOTTOM, 4);
|
||||||
|
sB->Add(sharpen_amount, 0, wxEXPAND | wxALL, 4);
|
||||||
|
s5->Add(sB, 0, wxEXPAND | wxALL, 4);
|
||||||
|
s5->AddStretchSpacer(1);
|
||||||
|
s->Add(s5, 0, wxEXPAND);
|
||||||
|
s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxALL, 8);
|
||||||
|
s->SetSizeHints(this);
|
||||||
|
SetSizer(s);
|
||||||
|
updateControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSliceWindow::onOk(wxCommandEvent&) {
|
||||||
|
EndModal(wxID_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
Image ImageSliceWindow::getImage() const {
|
||||||
|
return slice.getSlice();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSliceWindow : Controls
|
||||||
|
|
||||||
|
void ImageSliceWindow::onChangeSize(wxCommandEvent&) {
|
||||||
|
int sel = size->GetSelection();
|
||||||
|
if (sel == 0) {
|
||||||
|
// original size
|
||||||
|
slice.selection.width = slice.target_size.GetWidth();
|
||||||
|
slice.selection.height = slice.target_size.GetHeight();
|
||||||
|
slice.aspect_fixed = true;
|
||||||
|
onUpdateFromControl();
|
||||||
|
} else if (sel == 1) {
|
||||||
|
// size to fit
|
||||||
|
slice.selection.x = slice.selection.y = 0;
|
||||||
|
slice.selection.width = slice.source.GetWidth();
|
||||||
|
slice.selection.height = slice.source.GetHeight();
|
||||||
|
slice.aspect_fixed = true;
|
||||||
|
onUpdateFromControl();
|
||||||
|
} else if (sel == 2) {
|
||||||
|
// force to fit
|
||||||
|
slice.selection.x = slice.selection.y = 0;
|
||||||
|
slice.selection.width = slice.source.GetWidth();
|
||||||
|
slice.selection.height = slice.source.GetHeight();
|
||||||
|
slice.aspect_fixed = false;
|
||||||
|
onUpdateFromControl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSliceWindow::onChangeLeft(wxCommandEvent&) {
|
||||||
|
slice.selection.x = left->GetValue();
|
||||||
|
onUpdateFromControl();
|
||||||
|
}
|
||||||
|
void ImageSliceWindow::onChangeTop(wxCommandEvent&) {
|
||||||
|
slice.selection.y = top->GetValue();
|
||||||
|
onUpdateFromControl();
|
||||||
|
}
|
||||||
|
void ImageSliceWindow::onChangeWidth(wxCommandEvent&) {
|
||||||
|
slice.selection.width = width->GetValue();
|
||||||
|
onUpdateFromControl();
|
||||||
|
}
|
||||||
|
void ImageSliceWindow::onChangeHeight(wxCommandEvent&) {
|
||||||
|
slice.selection.height = height->GetValue();
|
||||||
|
onUpdateFromControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSliceWindow::onChangeFixAspect(wxCommandEvent&) {
|
||||||
|
slice.aspect_fixed = fix_aspect->GetValue();
|
||||||
|
onUpdateFromControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSliceWindow::onChangeZoom(wxSpinEvent&) {
|
||||||
|
slice.zoomX(zoom->GetValue() / 100.0);
|
||||||
|
slice.zoomY(zoom->GetValue() / 100.0);
|
||||||
|
onUpdateFromControl();
|
||||||
|
}
|
||||||
|
void ImageSliceWindow::onChangeZoomX(wxSpinEvent&) {
|
||||||
|
slice.zoomX(zoom_x->GetValue() / 100.0);
|
||||||
|
onUpdateFromControl();
|
||||||
|
}
|
||||||
|
void ImageSliceWindow::onChangeZoomY(wxSpinEvent&) {
|
||||||
|
slice.zoomY(zoom_x->GetValue() / 100.0);
|
||||||
|
onUpdateFromControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSliceWindow::onChangeSharpen(wxCommandEvent&) {
|
||||||
|
slice.sharpen = sharpen->GetValue();
|
||||||
|
onUpdateFromControl();
|
||||||
|
}
|
||||||
|
void ImageSliceWindow::onChangeSharpenAmount(wxScrollEvent&) {
|
||||||
|
slice.sharpen_amount = sharpen_amount->GetValue();
|
||||||
|
onUpdateFromControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSliceWindow : Updates
|
||||||
|
|
||||||
|
void ImageSliceWindow::onSelectionUpdate() {
|
||||||
|
slice.constrain();
|
||||||
|
// //preview.update();
|
||||||
|
selector->update();
|
||||||
|
updateControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSliceWindow::onUpdateFromControl() {
|
||||||
|
slice.constrain();
|
||||||
|
preview->update();
|
||||||
|
selector->update();
|
||||||
|
updateControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSliceWindow::updateControls() {
|
||||||
|
if (slice.selection.width == slice.target_size.GetWidth() && slice.selection.height == slice.target_size.GetHeight()) {
|
||||||
|
size->SetSelection(0); // original size
|
||||||
|
} else if (slice.selection.x == 0 && slice.selection.width == slice.source.GetWidth() &&
|
||||||
|
slice.selection.y == 0 && slice.selection.height == slice.source.GetHeight()) {
|
||||||
|
size->SetSelection(2); // force to fit
|
||||||
|
} else if (slice.selection.width <= slice.source.GetWidth() &&
|
||||||
|
slice.selection.height <= slice.source.GetHeight() &&
|
||||||
|
( (slice.selection.x == 0 && slice.selection.width == slice.source.GetWidth())
|
||||||
|
||(slice.selection.y == 0 && slice.selection.height == slice.source.GetHeight()))) {
|
||||||
|
size->SetSelection(1); // size to fit
|
||||||
|
} else {
|
||||||
|
size->SetSelection(3); // custom size
|
||||||
|
}
|
||||||
|
left ->SetValue(slice.selection.x);
|
||||||
|
top ->SetValue(slice.selection.y);
|
||||||
|
width ->SetValue(slice.selection.width);
|
||||||
|
height ->SetValue(slice.selection.height);
|
||||||
|
fix_aspect->SetValue(slice.aspect_fixed);
|
||||||
|
if (slice.aspect_fixed) {
|
||||||
|
zoom->SetValue(slice.zoomX() * 100);
|
||||||
|
if (zoom_x->IsShown()) {
|
||||||
|
zoom_sizer->Show(zoom_fixed, true);
|
||||||
|
zoom_sizer->Show(zoom_free, false);
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zoom_x->SetValue(slice.zoomX() * 100);
|
||||||
|
zoom_y->SetValue(slice.zoomY() * 100);
|
||||||
|
if (zoom->IsShown()) {
|
||||||
|
zoom_sizer->Show(zoom_fixed, false);
|
||||||
|
zoom_sizer->Show(zoom_free, true);
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sharpen ->SetValue(slice.sharpen);
|
||||||
|
sharpen_amount->SetValue(slice.sharpen_amount);
|
||||||
|
sharpen_amount->Enable(slice.sharpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSliceWindow : Event table
|
||||||
|
|
||||||
|
BEGIN_EVENT_TABLE(ImageSliceWindow, wxDialog)
|
||||||
|
EVT_BUTTON (wxID_OK, ImageSliceWindow::onOk)
|
||||||
|
EVT_RADIOBOX (ID_SIZE, ImageSliceWindow::onChangeSize)
|
||||||
|
EVT_TEXT (ID_LEFT, ImageSliceWindow::onChangeLeft)
|
||||||
|
EVT_TEXT (ID_TOP, ImageSliceWindow::onChangeTop)
|
||||||
|
EVT_TEXT (ID_WIDTH, ImageSliceWindow::onChangeWidth)
|
||||||
|
EVT_TEXT (ID_HEIGHT, ImageSliceWindow::onChangeHeight)
|
||||||
|
EVT_CHECKBOX (ID_FIX_ASPECT, ImageSliceWindow::onChangeFixAspect)
|
||||||
|
EVT_SPINCTRL (ID_ZOOM, ImageSliceWindow::onChangeZoom)
|
||||||
|
EVT_SPINCTRL (ID_ZOOM_X, ImageSliceWindow::onChangeZoomX)
|
||||||
|
EVT_SPINCTRL (ID_ZOOM_Y, ImageSliceWindow::onChangeZoomY)
|
||||||
|
EVT_CHECKBOX (ID_SHARPEN, ImageSliceWindow::onChangeSharpen)
|
||||||
|
EVT_COMMAND_SCROLL (ID_SHARPEN_AMOUNT, ImageSliceWindow::onChangeSharpenAmount)
|
||||||
|
// EVT_SIZE ( ImageSliceWindow::onSize)
|
||||||
|
END_EVENT_TABLE ()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSlicePreview
|
||||||
|
|
||||||
|
ImageSlicePreview::ImageSlicePreview(Window* parent, int id, ImageSlice& slice)
|
||||||
|
: wxControl(parent, id)
|
||||||
|
, slice(slice)
|
||||||
|
, mouse_down(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ImageSlicePreview::update() {
|
||||||
|
bitmap = wxNullBitmap;
|
||||||
|
Refresh(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
wxSize ImageSlicePreview::DoGetBestSize() const {
|
||||||
|
// We know the client size we want, calculate the size that goes with that
|
||||||
|
wxSize ws = GetSize(), cs = GetClientSize();
|
||||||
|
return slice.target_size + ws - cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSlicePreview::onPaint(wxPaintEvent&) {
|
||||||
|
wxPaintDC dc(this);
|
||||||
|
dc.BeginDrawing();
|
||||||
|
draw(dc);
|
||||||
|
dc.EndDrawing();
|
||||||
|
}
|
||||||
|
void ImageSlicePreview::draw(DC& dc) {
|
||||||
|
if (!bitmap.Ok()) {
|
||||||
|
bitmap = Bitmap(slice.getSlice());
|
||||||
|
}
|
||||||
|
if (bitmap.Ok()) {
|
||||||
|
dc.DrawBitmap(bitmap, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSlicePreview::onLeftDown(wxMouseEvent& ev) {
|
||||||
|
mouseX = ev.GetX();
|
||||||
|
mouseY = ev.GetY();
|
||||||
|
start_selection = slice.selection;
|
||||||
|
mouse_down = true;
|
||||||
|
CaptureMouse();
|
||||||
|
SetCursor(wxCURSOR_SIZING);
|
||||||
|
}
|
||||||
|
void ImageSlicePreview::onLeftUp(wxMouseEvent&v) {
|
||||||
|
mouse_down = false;
|
||||||
|
if (HasCapture()) ReleaseMouse();
|
||||||
|
SetCursor(wxNullCursor);
|
||||||
|
}
|
||||||
|
void ImageSlicePreview::onMotion(wxMouseEvent& ev) {
|
||||||
|
if (mouse_down) {
|
||||||
|
// drag the image
|
||||||
|
slice.selection.x = start_selection.x + (mouseX - ev.GetX()) / slice.zoomX();
|
||||||
|
slice.selection.y = start_selection.x + (mouseY - ev.GetY()) / slice.zoomY();
|
||||||
|
// parent->onSelectionUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BEGIN_EVENT_TABLE(ImageSlicePreview, wxControl)
|
||||||
|
EVT_PAINT (ImageSlicePreview::onPaint)
|
||||||
|
EVT_LEFT_DOWN (ImageSlicePreview::onLeftDown)
|
||||||
|
EVT_LEFT_UP (ImageSlicePreview::onLeftUp)
|
||||||
|
EVT_MOTION (ImageSlicePreview::onMotion)
|
||||||
|
END_EVENT_TABLE ()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSliceSelector
|
||||||
|
|
||||||
|
ImageSliceSelector::ImageSliceSelector(Window* parent, int id, ImageSlice& slice)
|
||||||
|
: wxControl(parent, id)
|
||||||
|
, slice(slice)
|
||||||
|
, mouse_down(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ImageSliceSelector::update() {
|
||||||
|
Refresh(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSliceSelector::onSize(wxSizeEvent&) {
|
||||||
|
bitmap = wxNullBitmap;
|
||||||
|
Refresh(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSliceSelector : Drawing
|
||||||
|
|
||||||
|
void ImageSliceSelector::onPaint(wxPaintEvent&) {
|
||||||
|
wxBufferedPaintDC dc(this);
|
||||||
|
dc.BeginDrawing();
|
||||||
|
draw(dc);
|
||||||
|
dc.EndDrawing();
|
||||||
|
}
|
||||||
|
void ImageSliceSelector::draw(DC& dc) {
|
||||||
|
if (!bitmap.Ok()) createBitmap();
|
||||||
|
if (!bitmap.Ok()) return;
|
||||||
|
// Selected region
|
||||||
|
wxSize s = GetClientSize();
|
||||||
|
int left = slice.selection.x * scaleX + border;
|
||||||
|
int top = slice.selection.y * scaleY + border;
|
||||||
|
int width = slice.selection.width * scaleX;
|
||||||
|
int height = slice.selection.height * scaleY;
|
||||||
|
// background
|
||||||
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||||
|
dc.SetBrush(Color(128,128,128));
|
||||||
|
dc.DrawRectangle(0, 0, s.GetWidth(), s.GetHeight());
|
||||||
|
// bitmap : unselected
|
||||||
|
dc.DrawBitmap(bitmap_no_sel, border, border);
|
||||||
|
// draw selected part ungreyed over it
|
||||||
|
{
|
||||||
|
wxMemoryDC mdc;
|
||||||
|
mdc.SelectObject(bitmap);
|
||||||
|
dc.Blit(left, top, width, height, &mdc, left - border, top - border);
|
||||||
|
mdc.SelectObject(wxNullBitmap);
|
||||||
|
}
|
||||||
|
// border around source
|
||||||
|
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||||
|
dc.SetPen(*wxBLACK_PEN);
|
||||||
|
dc.DrawRectangle(left - 1, top - 1, width + 2, height + 2);
|
||||||
|
dc.SetPen(Color(64,64,64));
|
||||||
|
dc.DrawRectangle(left - 2, top - 2, width + 4, height + 4);
|
||||||
|
// Draw handles on all sides
|
||||||
|
dc.SetBrush(Color(0,0,128));
|
||||||
|
dc.SetPen(*wxWHITE_PEN);
|
||||||
|
drawHandle(dc, -1, -1);
|
||||||
|
drawHandle(dc, -1, +1);
|
||||||
|
drawHandle(dc, +1, -1);
|
||||||
|
drawHandle(dc, +1, +1);
|
||||||
|
if (!slice.aspect_fixed) {
|
||||||
|
drawHandle(dc, -1, 0);
|
||||||
|
drawHandle(dc, 0, -1);
|
||||||
|
drawHandle(dc, 0, +1);
|
||||||
|
drawHandle(dc, +1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ImageSliceSelector::drawHandle(DC& dc, int dx, int dy) {
|
||||||
|
wxPoint p = handlePos(dx, dy);
|
||||||
|
dc.DrawRectangle(p.x - 3 + 4 * dx, p.y - 3 + 4 * dy, 6, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
int blur_pixel(Byte* in, int x, int y, int width, int height) {
|
||||||
|
return (2 * ( in[0]) + // center
|
||||||
|
(x == 0 ? in[0] : in[-3]) + // left
|
||||||
|
(y == 0 ? in[0] : in[-3*width]) + // up
|
||||||
|
(x == width - 1 ? in[0] : in[3]) + // right
|
||||||
|
(y == height - 1 ? in[0] : in[3*width]) // down
|
||||||
|
) / 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void blur_image(const Image& img_in, Image& img_out) {
|
||||||
|
int width = img_in.GetWidth(), height = img_in.GetHeight();
|
||||||
|
assert(img_out.GetWidth() == width && img_out.GetHeight() == height);
|
||||||
|
Byte* in = img_in.GetData(), *out = img_out.GetData();
|
||||||
|
for (int y = 0 ; y < height ; ++y) {
|
||||||
|
for (int x = 0 ; x < width ; ++x) {
|
||||||
|
out[0] = blur_pixel(in + 0, x, y, width, height);
|
||||||
|
out[1] = blur_pixel(in + 1, x, y, width, height);
|
||||||
|
out[2] = blur_pixel(in + 2, x, y, width, height);
|
||||||
|
in += 3; out += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void desaturate_image(Image& img) {
|
||||||
|
int width = img.GetWidth(), height = img.GetHeight();
|
||||||
|
Byte* in = img.GetData();
|
||||||
|
for (int y = 0 ; y < height ; ++y) {
|
||||||
|
for (int x = 0 ; x < width ; ++x) {
|
||||||
|
int r = in[0], g = in[1], b = in[2];
|
||||||
|
// desaturate
|
||||||
|
in[0] = (r + g + b + 5 * r + 255) / 9;
|
||||||
|
in[1] = (r + g + b + 5 * g + 255) / 9;
|
||||||
|
in[2] = (r + g + b + 5 * b + 255) / 9;
|
||||||
|
in += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSliceSelector::createBitmap() {
|
||||||
|
// create image, resampled to fit in control
|
||||||
|
wxSize s = GetClientSize();
|
||||||
|
int width = s.GetWidth() - 2*border, height = s.GetHeight() - 2*border;
|
||||||
|
Image img(width, height, false);
|
||||||
|
resample(slice.source, img);
|
||||||
|
bitmap = Bitmap(img);
|
||||||
|
scaleX = (double)width / slice.source.GetWidth();
|
||||||
|
scaleY = (double)height / slice.source.GetHeight();
|
||||||
|
// Initialize bitmap_no_sel to be the same bitmap, only with a faded color and blurred
|
||||||
|
Image img_no_sel(width, height, false);
|
||||||
|
blur_image(img, img_no_sel);
|
||||||
|
blur_image(img_no_sel, img_no_sel);
|
||||||
|
blur_image(img_no_sel, img_no_sel);
|
||||||
|
desaturate_image(img_no_sel);
|
||||||
|
bitmap_no_sel = Bitmap(img_no_sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSliceSelector : Mouse
|
||||||
|
|
||||||
|
void ImageSliceSelector::onLeftDown(wxMouseEvent& ev) {
|
||||||
|
mouseX = ev.GetX();
|
||||||
|
mouseY = ev.GetY();
|
||||||
|
start_selection = slice.selection;
|
||||||
|
mouse_down = true;
|
||||||
|
onAnyHandle(ev, &dragX, &dragY);
|
||||||
|
if (slice.aspect_fixed && (dragX == 0 || dragY == 0)) {
|
||||||
|
dragX = dragY = 0; // only drag corners if aspect fixed
|
||||||
|
}
|
||||||
|
if (dragX == 0 && dragY == 0) {
|
||||||
|
SetCursor(wxCURSOR_SIZING);
|
||||||
|
}
|
||||||
|
CaptureMouse();
|
||||||
|
}
|
||||||
|
void ImageSliceSelector::onLeftUp(wxMouseEvent&) {
|
||||||
|
mouse_down = false;
|
||||||
|
if (HasCapture()) ReleaseMouse();
|
||||||
|
SetCursor(wxNullCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSliceSelector::onMotion(wxMouseEvent& ev) {
|
||||||
|
if (mouse_down) {
|
||||||
|
double deltaX = (ev.GetX() - mouseX) / scaleX;
|
||||||
|
double deltaY = (ev.GetY() - mouseY) / scaleY;
|
||||||
|
// are we on a handle?
|
||||||
|
if (dragX == 0 && dragY == 0) {
|
||||||
|
// dragging entire selection
|
||||||
|
slice.selection.x = start_selection.x + deltaX;
|
||||||
|
slice.selection.y = start_selection.y + deltaY;
|
||||||
|
} else {
|
||||||
|
// fix aspect ratio
|
||||||
|
if (slice.aspect_fixed) {
|
||||||
|
if (abs(deltaX * slice.target_size.GetWidth()) >
|
||||||
|
abs(deltaY * slice.target_size.GetHeight())) {
|
||||||
|
deltaY = dragX * dragY * deltaX * slice.target_size.GetWidth() / slice.target_size.GetHeight();
|
||||||
|
} else {
|
||||||
|
deltaX = dragX * dragY * deltaY * slice.target_size.GetHeight() / slice.target_size.GetWidth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// move
|
||||||
|
slice.selection.x = start_selection.x + deltaX * (1 - dragX) / 2;
|
||||||
|
slice.selection.y = start_selection.y + deltaY * (1 - dragY) / 2;
|
||||||
|
slice.selection.width = start_selection.width + deltaX * dragX;
|
||||||
|
slice.selection.height = start_selection.height + deltaY * dragY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh
|
||||||
|
// parent->onSelectionUpdate();
|
||||||
|
} else {
|
||||||
|
int dx, dy;
|
||||||
|
if (onAnyHandle(ev, &dx, &dy)) {
|
||||||
|
// what cursor to use?
|
||||||
|
if (dx == dy) SetCursor(wxCURSOR_SIZENWSE);
|
||||||
|
else if (dx == -dy) SetCursor(wxCURSOR_SIZENESW);
|
||||||
|
else if (dx == 0) SetCursor(wxCURSOR_SIZENS);
|
||||||
|
else if (dy == 0) SetCursor(wxCURSOR_SIZEWE);
|
||||||
|
} else {
|
||||||
|
SetCursor(*wxSTANDARD_CURSOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSliceSelector : handles
|
||||||
|
|
||||||
|
bool ImageSliceSelector::onHandle(const wxMouseEvent& ev, int dx, int dy) const {
|
||||||
|
wxPoint p = handlePos(dx, dy);
|
||||||
|
p.x = p.x - 3 + 4 * dx;
|
||||||
|
p.y = p.y - 3 + 4 * dy;
|
||||||
|
return ev.GetX() >= p.x && ev.GetX() < p.x + 6 &&
|
||||||
|
ev.GetY() >= p.y && ev.GetY() < p.y + 6;
|
||||||
|
}
|
||||||
|
bool ImageSliceSelector::onAnyHandle(const wxMouseEvent& ev, int* dxOut, int* dyOut) const {
|
||||||
|
for (int dx = -1 ; dx <= 1 ; ++dx) {
|
||||||
|
for (int dy = -1 ; dy <= 1 ; ++dy) {
|
||||||
|
if ((dx != 0 || dy != 0) && onHandle(ev, dx, dy)) { // (0,0) == center, not a handle
|
||||||
|
*dxOut = dx;
|
||||||
|
*dyOut = dy;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*dxOut = *dyOut = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
wxPoint ImageSliceSelector::handlePos(int dx, int dy) const {
|
||||||
|
return wxPoint(
|
||||||
|
scaleX * (slice.selection.x + ((dx + 1) * slice.selection.width) * 0.5) + border,
|
||||||
|
scaleY * (slice.selection.y + ((dy + 1) * slice.selection.height) * 0.5) + border
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSliceSelector : Event table
|
||||||
|
|
||||||
|
BEGIN_EVENT_TABLE(ImageSliceSelector, wxControl)
|
||||||
|
EVT_PAINT (ImageSliceSelector::onPaint)
|
||||||
|
EVT_LEFT_DOWN (ImageSliceSelector::onLeftDown)
|
||||||
|
EVT_LEFT_UP (ImageSliceSelector::onLeftUp)
|
||||||
|
EVT_MOTION (ImageSliceSelector::onMotion)
|
||||||
|
EVT_SIZE (ImageSliceSelector::onSize)
|
||||||
|
END_EVENT_TABLE ()
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||||
|
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||||
|
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#ifndef HEADER_GUI_IMAGE_SLICE_WINDOW
|
||||||
|
#define HEADER_GUI_IMAGE_SLICE_WINDOW
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
|
#include <util/prec.hpp>
|
||||||
|
|
||||||
|
class ImageSlicePreview;
|
||||||
|
class ImageSliceSelector;
|
||||||
|
class wxSpinEvent;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSlice
|
||||||
|
|
||||||
|
/// A slice of an image, i.e. a selected rectangle
|
||||||
|
class ImageSlice {
|
||||||
|
public:
|
||||||
|
ImageSlice(const Image& source, const wxSize& target_size);
|
||||||
|
|
||||||
|
Image source; ///< The source image
|
||||||
|
wxSize target_size; ///< Size of the target image
|
||||||
|
Color background; ///< Color for areas outside the source image
|
||||||
|
wxRect selection; ///< Area to slect from source
|
||||||
|
bool allow_outside;
|
||||||
|
bool aspect_fixed; ///< Aspect ratio lock?
|
||||||
|
// Filters
|
||||||
|
bool sharpen;
|
||||||
|
int sharpen_amount;
|
||||||
|
|
||||||
|
/// Enforce relations between values
|
||||||
|
void constrain();
|
||||||
|
/// Get the sliced image
|
||||||
|
Image getSlice() const;
|
||||||
|
|
||||||
|
// Zoom factor
|
||||||
|
inline double zoomX() const { return target_size.GetWidth() / (double)selection.width; }
|
||||||
|
inline double zoomY() const { return target_size.GetHeight() / (double)selection.height; }
|
||||||
|
inline void zoomX(double zoom) { selection.width = target_size.GetWidth() / zoom; }
|
||||||
|
inline void zoomY(double zoom) { selection.height = target_size.GetHeight() / zoom; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSliceWindow
|
||||||
|
|
||||||
|
/// Dialog for selecting a slice of an image
|
||||||
|
class ImageSliceWindow : public wxDialog {
|
||||||
|
public:
|
||||||
|
ImageSliceWindow(Window* parent, const Image& source, const wxSize& target_size);
|
||||||
|
|
||||||
|
/// Return the sliced image
|
||||||
|
Image getImage() const;
|
||||||
|
|
||||||
|
// --------------------------------------------------- : Data
|
||||||
|
private:
|
||||||
|
// The slice we are extracting
|
||||||
|
ImageSlice slice;
|
||||||
|
// Gui items
|
||||||
|
ImageSlicePreview* preview;
|
||||||
|
ImageSliceSelector* selector;
|
||||||
|
wxRadioBox* size;
|
||||||
|
wxSpinCtrl* top, *left, *width, *height;
|
||||||
|
wxCheckBox* fix_aspect;
|
||||||
|
wxSpinCtrl* zoom, *zoom_x, *zoom_y;
|
||||||
|
wxSizer* zoom_sizer, *zoom_fixed, *zoom_free;
|
||||||
|
wxCheckBox* sharpen;
|
||||||
|
wxSlider* sharpen_amount;
|
||||||
|
|
||||||
|
// --------------------------------------------------- : Events
|
||||||
|
DECLARE_EVENT_TABLE();
|
||||||
|
|
||||||
|
void onOk (wxCommandEvent&);
|
||||||
|
|
||||||
|
void onSize (wxSizeEvent&);
|
||||||
|
|
||||||
|
void onChangeSize (wxCommandEvent&);
|
||||||
|
void onChangeLeft (wxCommandEvent&);
|
||||||
|
void onChangeTop (wxCommandEvent&);
|
||||||
|
void onChangeWidth (wxCommandEvent&);
|
||||||
|
void onChangeHeight (wxCommandEvent&);
|
||||||
|
void onChangeFixAspect (wxCommandEvent&);
|
||||||
|
void onChangeZoom (wxSpinEvent&);
|
||||||
|
void onChangeZoomX (wxSpinEvent&);
|
||||||
|
void onChangeZoomY (wxSpinEvent&);
|
||||||
|
void onChangeSharpen (wxCommandEvent&);
|
||||||
|
void onChangeSharpenAmount(wxScrollEvent&);
|
||||||
|
|
||||||
|
// --------------------------------------------------- : Updating
|
||||||
|
|
||||||
|
// Something changed in the selector control, update controls and selection displays
|
||||||
|
void onSelectionUpdate();
|
||||||
|
// The manual controls were changed
|
||||||
|
void onUpdateFromControl();
|
||||||
|
// Update the values in the controls
|
||||||
|
void updateControls();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSlicePreview
|
||||||
|
|
||||||
|
/// A preview of the sliced image
|
||||||
|
class ImageSlicePreview : public wxControl {
|
||||||
|
public:
|
||||||
|
ImageSlicePreview(Window* parent, int id, ImageSlice& slice);
|
||||||
|
|
||||||
|
/// Notify that the slice was updated
|
||||||
|
void update();
|
||||||
|
|
||||||
|
// --------------------------------------------------- : Data
|
||||||
|
private:
|
||||||
|
Bitmap bitmap;
|
||||||
|
ImageSlice& slice;
|
||||||
|
|
||||||
|
bool mouse_down;
|
||||||
|
int mouseX, mouseY; ///< starting mouse position
|
||||||
|
wxRect start_selection; ///< selection in slice at start of dragging
|
||||||
|
|
||||||
|
// --------------------------------------------------- : Events
|
||||||
|
DECLARE_EVENT_TABLE();
|
||||||
|
|
||||||
|
wxSize DoGetBestSize() const;
|
||||||
|
|
||||||
|
void onLeftDown(wxMouseEvent&);
|
||||||
|
void onLeftUp (wxMouseEvent&);
|
||||||
|
void onMotion (wxMouseEvent&);
|
||||||
|
|
||||||
|
void onPaint(wxPaintEvent&);
|
||||||
|
void draw(DC& dc);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : ImageSliceSelector
|
||||||
|
|
||||||
|
// A overview of the slicing of the image, allows to select the sliced area
|
||||||
|
class ImageSliceSelector : public wxControl {
|
||||||
|
public:
|
||||||
|
ImageSliceSelector(Window* parent, int id, ImageSlice& slice);
|
||||||
|
|
||||||
|
/// Notify that the slice was updated
|
||||||
|
void update();
|
||||||
|
|
||||||
|
// --------------------------------------------------- : Data
|
||||||
|
private:
|
||||||
|
ImageSlice& slice;
|
||||||
|
Bitmap bitmap, bitmap_no_sel; ///< Bitmaps showing selection
|
||||||
|
|
||||||
|
bool mouse_down;
|
||||||
|
int mouseX, mouseY; ///< starting mouse position
|
||||||
|
int dragX, dragY; ///< corner that is being dragged
|
||||||
|
wxRect start_selection; ///< selection in slice at start of dragging
|
||||||
|
double scaleX, scaleY; ///< Amount the source image is scaled to fit in this control
|
||||||
|
static const int border = 8;
|
||||||
|
|
||||||
|
// --------------------------------------------------- : Events
|
||||||
|
DECLARE_EVENT_TABLE();
|
||||||
|
|
||||||
|
void onLeftDown(wxMouseEvent&);
|
||||||
|
void onLeftUp (wxMouseEvent&);
|
||||||
|
void onMotion (wxMouseEvent&);
|
||||||
|
|
||||||
|
void onPaint(wxPaintEvent&);
|
||||||
|
void onSize(wxSizeEvent&);
|
||||||
|
|
||||||
|
// Is the mouse on a (scale) handle?
|
||||||
|
bool onHandle(const wxMouseEvent& ev, int dx, int dy) const;
|
||||||
|
// Is the mouse on any handle?
|
||||||
|
bool onAnyHandle(const wxMouseEvent& ev, int* dxOut, int* dyOut) const;
|
||||||
|
// Return the position of a handle, dx,dy in {-1,0,1}
|
||||||
|
wxPoint handlePos(int dx, int dy) const;
|
||||||
|
|
||||||
|
void draw(DC& dc);
|
||||||
|
// Draw a handle, dx and dy indicate the side, can be {-1,0,1}
|
||||||
|
void drawHandle(DC& dc, int dx, int dy);
|
||||||
|
void createBitmap();
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : EOF
|
||||||
|
#endif
|
||||||
@@ -69,7 +69,7 @@ class ValueEditor {
|
|||||||
// Deletes the selection from this field editor, cut = copy + delete, returns success
|
// Deletes the selection from this field editor, cut = copy + delete, returns success
|
||||||
virtual bool doDelete() { return false; }
|
virtual bool doDelete() { return false; }
|
||||||
// Cuts the selection from this field editor
|
// Cuts the selection from this field editor
|
||||||
bool doCut() { return doCopy() && doDelete(); }
|
bool doCut() { return doCopy() && doDelete(); }
|
||||||
/// Initiate pasting in this field editor,
|
/// Initiate pasting in this field editor,
|
||||||
/** should again check if pasting is possible and fail silently if not, returns success */
|
/** should again check if pasting is possible and fail silently if not, returns success */
|
||||||
virtual bool doPaste() { return false; }
|
virtual bool doPaste() { return false; }
|
||||||
|
|||||||
+63
-1
@@ -7,7 +7,69 @@
|
|||||||
// ----------------------------------------------------------------------------- : Includes
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
#include <gui/value/image.hpp>
|
#include <gui/value/image.hpp>
|
||||||
|
#include <gui/image_slice_window.hpp>
|
||||||
|
#include <data/format/clipboard.hpp>
|
||||||
|
#include <data/action/value.hpp>
|
||||||
|
#include <wx/clipbrd.h>
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- :
|
// ----------------------------------------------------------------------------- : ImageValueEditor
|
||||||
|
|
||||||
IMPLEMENT_VALUE_EDITOR(Image) {}
|
IMPLEMENT_VALUE_EDITOR(Image) {}
|
||||||
|
|
||||||
|
void ImageValueEditor::onLeftDClick(const RealPoint&, wxMouseEvent&) {
|
||||||
|
String filename = wxFileSelector(_("Open image file"), _(""), _(""), _(""),
|
||||||
|
_("All images|*.bmp;*.jpg;*.png;*.gif|Windows bitmaps (*.bmp)|*.bmp|JPEG images (*.jpg;*.jpeg)|*.jpg;*.jpeg|PNG images (*.png)|*.png|GIF images (*.gif)|*.gif|TIFF images (*.tif;*.tiff)|*.tif;*.tiff"),
|
||||||
|
wxOPEN);
|
||||||
|
if (filename.empty()) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
sliceImage(wxImage(filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageValueEditor::sliceImage(const Image& image) {
|
||||||
|
if (!image.Ok()) return;
|
||||||
|
// slice
|
||||||
|
ImageSliceWindow s(wxGetTopLevelParent(&editor()), image, style().getSize());
|
||||||
|
if (s.ShowModal() == wxID_OK) {
|
||||||
|
// store the image into the set
|
||||||
|
FileName new_image_file = getSet().newFileName(field().name,_("")); // a new unique name in the package
|
||||||
|
s.getImage().SaveFile(getSet().nameOut(new_image_file), wxBITMAP_TYPE_JPEG);
|
||||||
|
getSet().actions.add(value_action(valueP(), new_image_file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Clipboard
|
||||||
|
|
||||||
|
bool ImageValueEditor::canCopy() const {
|
||||||
|
return !value().filename.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImageValueEditor::canPaste() const {
|
||||||
|
return wxTheClipboard->IsSupported(wxDF_BITMAP) &&
|
||||||
|
!wxTheClipboard->IsSupported(CardDataObject::format); // we don't want to (accidentally) paste card images
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImageValueEditor::doCopy() {
|
||||||
|
// load image
|
||||||
|
InputStreamP image_file = getSet().openIn(value().filename);
|
||||||
|
Image image;
|
||||||
|
if (!image.LoadFile(*image_file)) return false;
|
||||||
|
// set data
|
||||||
|
if (!wxTheClipboard->Open()) return false;
|
||||||
|
bool ok = wxTheClipboard->SetData(new wxBitmapDataObject(image));
|
||||||
|
wxTheClipboard->Close();
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImageValueEditor::doPaste() {
|
||||||
|
// get bitmap
|
||||||
|
if (!wxTheClipboard->Open()) return false;
|
||||||
|
wxBitmapDataObject data;
|
||||||
|
bool ok = wxTheClipboard->GetData(data);
|
||||||
|
wxTheClipboard->Close();
|
||||||
|
if (!ok) return false;
|
||||||
|
// slice
|
||||||
|
sliceImage(data.GetBitmap().ConvertToImage());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,6 +19,20 @@
|
|||||||
class ImageValueEditor : public ImageValueViewer, public ValueEditor {
|
class ImageValueEditor : public ImageValueViewer, public ValueEditor {
|
||||||
public:
|
public:
|
||||||
DECLARE_VALUE_EDITOR(Image);
|
DECLARE_VALUE_EDITOR(Image);
|
||||||
|
|
||||||
|
virtual void onLeftDClick(const RealPoint&, wxMouseEvent&);
|
||||||
|
|
||||||
|
// --------------------------------------------------- : Clipboard
|
||||||
|
|
||||||
|
virtual bool canCopy() const;
|
||||||
|
virtual bool canCut() const { return false; }
|
||||||
|
virtual bool canPaste() const;
|
||||||
|
virtual bool doCopy();
|
||||||
|
virtual bool doPaste();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Open the image slice window showing the give image
|
||||||
|
void sliceImage(const Image&);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : EOF
|
// ----------------------------------------------------------------------------- : EOF
|
||||||
|
|||||||
Reference in New Issue
Block a user