/** @file
* Affine transform handles component
*/
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
* Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2009 Authors
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <math.h>
#include <algorithm>
#include "control-point.h"
#include "desktop.h"
#include "sp-namedview.h"
#include "display/sodipodi-ctrlrect.h"
#include "preferences.h"
#include "pure-transform.h"
#include "snap.h"
#include "snap-candidate.h"
#include "sp-namedview.h"
#include "ui/tool/commit-events.h"
#include "ui/tool/control-point-selection.h"
#include "ui/tool/selectable-control-point.h"
#include "ui/tool/event-utils.h"
#include "ui/tool/transform-handle-set.h"
#include "ui/tools/node-tool.h"
#include "seltrans.h"
// FIXME BRAIN DAMAGE WARNING: this is a global variable in select-context.cpp
// It should be moved to a header
namespace Inkscape {
namespace UI {
namespace {
switch (c % 4) {
case 0: return SP_ANCHOR_NE;
case 1: return SP_ANCHOR_NW;
case 2: return SP_ANCHOR_SW;
default: return SP_ANCHOR_SE;
}
}
switch (s % 4) {
case 0: return SP_ANCHOR_N;
case 1: return SP_ANCHOR_W;
case 2: return SP_ANCHOR_S;
default: return SP_ANCHOR_E;
}
}
// TODO move those two functions into a common place
double snap_angle(double a) {
}
double snap_increment_degrees() {
return 180.0 / snaps;
}
} // anonymous namespace
{0x000000ff, 0x000000ff},
{0x00ff6600, 0x000000ff},
{0x00ff6600, 0x000000ff},
//
{0x000000ff, 0x000000ff},
{0x00ff6600, 0x000000ff},
{0x00ff6600, 0x000000ff}
};
TransformHandle::TransformHandle(TransformHandleSet &th, SPAnchorType anchor, Glib::RefPtr<Gdk::Pixbuf> pb) :
pb,
{
setVisible(false);
}
// TODO: This code is duplicated in seltrans.cpp; fix this!
{
if (!_all_snap_sources_sorted.empty()) {
if (reverse) { // Shift-tab will find a closer point
}
} else { // Tab will find a point further away
}
}
// Show the updated snap source now; otherwise it won't be shown until the selection is being moved again
m.unSetup();
}
}
}
{
_th._setActiveHandle(this);
_setLurking(true);
// Collect the snap-candidates, one for each selected node. These will be stored in the _snap_points vector.
//ControlPointSelection *selection = nt->_selected_nodes.get();
// Find the closest snap source candidate
// Calculate and store the distance to the reference point for each snap candidate point
for(std::vector<Inkscape::SnapCandidatePoint>::iterator i = _all_snap_sources_sorted.begin(); i != _all_snap_sources_sorted.end(); ++i) {
}
// Sort them ascending, using the distance calculated above as the single criteria
// Now get the closest snap source
if (!_all_snap_sources_sorted.empty()) {
}
}
return false;
}
{
// protect against degeneracies
if (t.isSingular()) return;
if (incr.isSingular()) return;
_last_transform = t;
}
{
_setLurking(false);
endTransform();
}
public:
{}
protected:
if (state_held_control(state)) {
if (state_held_shift(state)) {
return C_("Transform handle tip",
"<b>Shift+Ctrl</b>: scale uniformly about the rotation center");
}
}
if (state_held_shift(state)) {
if (state_held_alt(state)) {
return C_("Transform handle tip",
"<b>Shift+Alt</b>: scale using an integer ratio about the rotation center");
}
}
if (state_held_alt(state)) {
}
}
}
virtual bool _hasDragTips() const { return true; }
};
/**
* Corner scaling handle for node transforms.
*/
public:
{}
protected:
virtual void startTransform() {
}
// avoid exploding the selection
for (unsigned i = 0; i < 2; ++i) {
} else {
}
}
} else {
if (held_control(*event)) {
} else {
}
m.unSetup();
}
delete ptr;
}
_last_scale_x = scale[0];
return t;
}
return _last_transform.isUniformScale()
}
private:
//sp_select_context_get_type();
switch (c % 2) {
case 0:
break;
default:
break;
}
}
unsigned _corner;
};
/**
* Side scaling handle for node transforms.
*/
public:
{}
protected:
virtual void startTransform() {
}
// avoid exploding the selection
} else {
}
} else {
m.unSetup();
} else {
// on ctrl, apply uniform scaling instead of stretching
// Preserve aspect ratio, but never flip in the dimension not being edited (by using fabs())
}
}
return t;
}
return _last_transform.isUniformScale()
}
private:
//sp_select_context_get_type();
switch (c % 2) {
}
}
unsigned _side;
};
/**
* Rotation handle for node transforms.
*/
public:
{}
protected:
virtual void startTransform() {
_last_angle = 0;
}
{
if (held_control(*event)) {
} else {
m.unSetup();
}
}
_last_angle = angle;
return t;
}
if (state_held_shift(state)) {
if (state_held_control(state)) {
"<b>Shift+Ctrl</b>: rotate around the opposite corner and snap "
"angle to %f° increments"), snap_increment_degrees());
}
}
if (state_held_control(state)) {
"<b>Ctrl</b>: snap angle to %f° increments"), snap_increment_degrees());
}
"the selection around the rotation center");
}
}
virtual bool _hasDragTips() const { return true; }
private:
//sp_select_context_get_type();
switch (c % 4) {
}
}
unsigned _corner;
static double _last_angle;
};
public:
{}
protected:
virtual void startTransform() {
_last_angle = 0;
}
{
}
// Calculate the scale factors, which can be either visual or geometric
// depending on which type of bbox is currently being used (see preferences -> selector tool)
// Skew handles allow scaling up to integer multiples of the original size
// in the second direction; prevent explosions
// Prevent shrinking of the selected object, while allowing mirroring
} else {
// Allow expanding of the selected object by integer multiples
}
if (held_control(*event)) {
} else {
m.unSetup();
}
}
_last_angle = angle;
// Update the handle position
// Calculate the relative affine
for (int i = 0; i < 2; i++) {
}
}
return t;
}
return (_side % 2)
}
if (state_held_shift(state)) {
if (state_held_control(state)) {
"<b>Shift+Ctrl</b>: skew about the rotation center with snapping "
"to %f° increments"), snap_increment_degrees());
}
}
if (state_held_control(state)) {
"<b>Ctrl</b>: snap skew angle to %f° increments"), snap_increment_degrees());
}
return C_("Transform handle tip",
"<b>Skew handle</b>: drag to skew (shear) selection about "
"the opposite handle");
}
if (_last_horizontal) {
_last_angle * 360.0);
} else {
_last_angle * 360.0);
}
}
virtual bool _hasDragTips() const { return true; }
private:
//sp_select_context_get_type();
switch (s % 4) {
}
}
unsigned _side;
static bool _last_horizontal;
static double _last_angle;
};
public:
_get_pixbuf(),
{
setVisible(false);
}
protected:
if (held_control(*event)) {
// constrain to axes
} else if (snap) {
}
}
return C_("Transform handle tip",
"<b>Rotation center</b>: drag to change the origin of transforms");
}
private:
//sp_select_context_get_type();
}
};
{0x00000000, 0x000000ff},
{0x00000000, 0xff0000b0},
{0x00000000, 0xff0000b0},
//
{0x00000000, 0x000000ff},
{0x00000000, 0xff0000b0},
{0x00000000, 0xff0000b0}
};
: Manipulator(d)
, _active(0)
, _mode(MODE_SCALE)
, _in_transform(false)
, _visible(true)
{
SP_TYPE_CTRLRECT, NULL));
_trans_outline->setDashed(true);
for (unsigned i = 0; i < 4; ++i) {
_scale_corners[i] = new ScaleCornerHandle(*this, i);
_scale_sides[i] = new ScaleSideHandle(*this, i);
_rot_corners[i] = new RotateHandle(*this, i);
_skew_sides[i] = new SkewHandle(*this, i);
}
_center = new RotationCenter(*this);
// when transforming, update rotation center position
}
{
for (unsigned i = 0; i < 17; ++i) {
delete _handles[i];
}
}
{
_mode = m;
}
{
}
{
return *_center;
}
{
return *_center;
}
{
if (_visible != v) {
_visible = v;
}
}
{
if (_in_transform) {
} else {
for (unsigned i = 0; i < 4; ++i) {
}
if (_visible) _updateVisibility(true);
}
}
{
return false;
}
{
signal_transform.emit(t);
}
{
if (_in_transform)
_in_transform = true;
// hide all handles except the active one
_updateVisibility(false);
}
{
// This can only be called from handles, so they had to be visible before _setActiveHandle
_active = 0;
_in_transform = false;
}
{
if (v) {
// do not scale when the bounding rectangle has zero width or height
// do not rotate if the bounding rectangle is degenerate
// show sides if:
// a) there is enough space between corner handles, or
// b) corner handles are not shown, but side handles make sense
// this affects horizontal and vertical scale handles; skew handles never
// make sense if rotate handles are not shown
for (unsigned i = 0; i < 2; ++i) {
}
for (unsigned i = 0; i < 4; ++i) {
}
// show rotation center if there is enough space (?)
&& bp[Geom::Y] > handle_size[Geom::Y]*/);
} else {
for (unsigned i = 0; i < 17; ++i) {
_handles[i]->setVisible(false);
}
}
}
} // namespace UI
} // namespace Inkscape
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :