24 #include <QStringList>
26 inline float metric(
float dx,
float dy)
29 return (dx*dx + dy*dy);
32 class KShapeGesturePrivate
35 KShapeGesturePrivate()
38 KShapeGesturePrivate(
const KShapeGesturePrivate &other)
39 : m_shape(other.m_shape),
40 m_lengthTo(other.m_lengthTo),
41 m_curveLength(other.m_curveLength)
51 : d(new KShapeGesturePrivate)
57 : d(new KShapeGesturePrivate)
64 : d(new KShapeGesturePrivate)
85 d->m_friendlyName.clear();
94 : d(new KShapeGesturePrivate(*(other.d)))
118 float xScale = bounding.
width() ? 100.0 / bounding.
width() : 1.0;
119 float yScale = bounding.
height() ? 100.0 / bounding.
height() : 1.0;
120 d->m_shape.translate(-bounding.
left(), -bounding.
top());
121 for (
int i=0; i < d->m_shape.size(); i++) {
122 d->m_shape[i].setX((
int)(xScale * (
float)d->m_shape[i].x()));
123 d->m_shape[i].setY((
int)(yScale * (
float)d->m_shape[i].y()));
127 Q_ASSERT(d->m_shape.size() > 1);
128 d->m_curveLength = 0.0;
129 d->m_lengthTo.clear();
130 d->m_lengthTo.reserve(d->m_shape.size());
131 d->m_lengthTo.append(d->m_curveLength);
133 int prevX = d->m_shape[0].x();
134 int prevY = d->m_shape[0].y();
135 for (
int i=1; i < d->m_shape.size(); i++) {
136 int curX = d->m_shape[i].x();
137 int curY = d->m_shape[i].y();
138 d->m_curveLength +=
metric(curX-prevX, curY - prevY);
139 d->m_lengthTo.append(d->m_curveLength);
148 d->m_friendlyName = friendlyName;
154 return d->m_friendlyName;
160 return !d->m_shape.isEmpty();
170 QString ret = d->m_friendlyName;
173 for (i = 0; i < d->m_shape.size(); i++) {
190 const char *prolog =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
191 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" "
192 "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
193 "<svg width=\"100\" height=\"100\" version=\"1.1\" "
194 "xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M";
195 const char *epilog1 =
"\" fill=\"none\" ";
196 const char *epilog2 =
" /></svg>";
203 for (
int i=1; i < d->m_shape.size(); i++) {
227 Q_UNUSED(abortThreshold);
228 const QPolygon &o_shape = other.d->m_shape;
242 float opositionB = 0;
247 float desiredPosition = 0;
248 float strokeLength = 0;
250 int pointIndex = 0, opointIndex = 0, opointIndexB = 0;
253 x = d->m_shape[0].x();
254 y = d->m_shape[0].y();
255 strokeLength = d->m_lengthTo[1];
256 mx = (d->m_shape[1].x() - x) / strokeLength;
257 my = (d->m_shape[1].y() - y) / strokeLength;
263 strokeLength = o_lengthTo[1];
264 omx = (o_shape[1].x() - ox) / strokeLength;
265 omy = (o_shape[1].y() - oy) / strokeLength;
267 dist =
metric(ox-x, oy-y);
269 for (
int i = 0; i <= 30; i++) {
272 desiredPosition = d->m_curveLength / 30.0001 * (float)i;
273 if (desiredPosition > d->m_lengthTo[pointIndex+1]) {
275 while (desiredPosition > d->m_lengthTo[pointIndex+1])
278 x = d->m_shape[pointIndex].x();
279 y = d->m_shape[pointIndex].y();
280 position = d->m_lengthTo[pointIndex];
281 strokeLength = d->m_lengthTo[pointIndex+1] - position;
282 mx = (d->m_shape[pointIndex+1].x() - x) / strokeLength;
283 my = (d->m_shape[pointIndex+1].y() - y) / strokeLength;
285 x += mx * (desiredPosition - position);
286 y += my * (desiredPosition - position);
287 position = desiredPosition;
290 desiredPosition = qMin(oposition + other.d->m_curveLength / 15.00005,
291 other.d->m_curveLength - 0.0001);
292 if (i == 0 || desiredPosition > o_lengthTo[opointIndexB+1]) {
294 while (desiredPosition > o_lengthTo[opointIndexB+1])
297 oxB = o_shape[opointIndexB].x();
298 oyB = o_shape[opointIndexB].y();
299 opositionB = o_lengthTo[opointIndexB];
300 strokeLength = o_lengthTo[opointIndexB+1] - opositionB;
301 omxB = (o_shape[opointIndexB+1].x() - oxB) / strokeLength;
302 omyB = (o_shape[opointIndexB+1].y() - oyB) / strokeLength;
304 oxB += omxB * (desiredPosition - opositionB);
305 oyB += omyB * (desiredPosition - opositionB);
306 opositionB = desiredPosition;
307 distB =
metric(oxB-x, oyB-y);
310 for (
int j = 0; j < 6; j++) {
311 desiredPosition = (oposition + opositionB) * 0.5;
316 omxB = omx; omyB = omy;
317 opointIndexB = opointIndex; opositionB = oposition;
319 if (desiredPosition > o_lengthTo[opointIndexB+1]) {
321 while (desiredPosition > o_lengthTo[opointIndexB+1])
324 oxB = o_shape[opointIndexB].x();
325 oyB = o_shape[opointIndexB].y();
326 opositionB = o_lengthTo[opointIndexB];
327 strokeLength = o_lengthTo[opointIndexB+1] - opositionB;
328 omxB = (o_shape[opointIndexB+1].x() - oxB) / strokeLength;
329 omyB = (o_shape[opointIndexB+1].y() - oyB) / strokeLength;
331 oxB += omxB * (desiredPosition - opositionB);
332 oyB += omyB * (desiredPosition - opositionB);
333 opositionB = desiredPosition;
334 distB =
metric(oxB-x, oyB-y);
337 if (desiredPosition > o_lengthTo[opointIndex+1]) {
339 while (desiredPosition > o_lengthTo[opointIndex+1])
342 ox = o_shape[opointIndex].x();
343 oy = o_shape[opointIndex].y();
344 oposition = o_lengthTo[opointIndex];
345 strokeLength = o_lengthTo[opointIndex+1] - oposition;
346 omx = (o_shape[opointIndex+1].x() - ox) / strokeLength;
347 omy = (o_shape[opointIndex+1].y() - oy) / strokeLength;
349 ox += omx * (desiredPosition - oposition);
350 oy += omy * (desiredPosition - oposition);
351 oposition = desiredPosition;
352 dist =
metric(ox-x, oy-y);
355 retval += qMin(dist, distB);
358 return retval / 30.0;
364 d->m_lengthTo = other.d->m_lengthTo;
365 d->m_shape = other.d->m_shape;
366 d->m_curveLength = other.d->m_curveLength;
374 if (fabs(d->m_curveLength - other.d->m_curveLength) > 0.1)
376 return d->m_shape == other.d->m_shape;
388 foreach (
const QPoint &point, d->m_shape)
399 class KRockerGesturePrivate
402 KRockerGesturePrivate()
403 : m_hold(Qt::NoButton),
404 m_thenPush(Qt::NoButton)
407 KRockerGesturePrivate(
const KRockerGesturePrivate &other)
408 : m_hold(other.m_hold),
409 m_thenPush(other.m_thenPush)
412 Qt::MouseButton m_hold;
413 Qt::MouseButton m_thenPush;
417 : d( new KRockerGesturePrivate )
423 : d( new KRockerGesturePrivate )
430 : d( new KRockerGesturePrivate )
432 if (description.
length() != 2)
435 Qt::MouseButton hold, thenPush;
436 Qt::MouseButton *current = &hold;
437 for (
int i = 0; i < 2; i++) {
438 switch (description[i].toLatin1()) {
440 *current = Qt::LeftButton;
443 *current = Qt::RightButton;
446 *current = Qt::MidButton;
449 *current = Qt::XButton1;
452 *current = Qt::XButton2;
460 d->m_thenPush = thenPush;
465 : d( new KRockerGesturePrivate(*(other.d)) )
478 if (hold == thenPush) {
479 d->m_hold = Qt::NoButton;
480 d->m_thenPush = Qt::NoButton;
485 for (
int i = 0; i < 2; i++) {
488 case Qt::RightButton:
494 d->m_hold = Qt::NoButton;
495 d->m_thenPush = Qt::NoButton;
502 d->m_thenPush = thenPush;
509 *thenPush = d->m_thenPush;
517 return i18nc(
"left mouse button",
"left button");
520 return i18nc(
"middle mouse button",
"middle button");
522 case Qt::RightButton:
523 return i18nc(
"right mouse button",
"right button");
526 return i18nc(
"a nonexistent value of mouse button",
"invalid button");
539 return i18nc(
"a kind of mouse gesture: hold down one mouse button, then press another button",
546 return (d->m_hold != Qt::NoButton);
555 int button = d->m_hold;
557 for (
int i = 0; i < 2; i++) {
562 case Qt::RightButton:
578 button = d->m_thenPush;
586 d->m_hold = other.d->m_hold;
587 d->m_thenPush = other.d->m_thenPush;
594 return d->m_hold == other.d->m_hold && d->m_thenPush == other.d->m_thenPush;
605 return qHash(d->m_hold) + d->m_thenPush;
KShapeGesture & operator=(const KShapeGesture &other)
Set this gesture to the other gesture.
QString & append(QChar ch)
float distance(const KShapeGesture &other, float abortThreshold) const
Return a difference measurement betwenn this gesture and the other gesture.
static QString mouseButtonName(Qt::MouseButton button)
Return a user-friendly name for the mouse button button.
bool isValid() const
Return true if this gesture is valid.
void append(const T &value)
bool operator==(const KRockerGesture &other) const
Return whether this gesture is equal to the other gesture.
void setShapeName(const QString &friendlyName)
set a user-visible name for this gesture's shape, like "triangle" or "line".
uint hashable() const
Return an opaque value for use in hash tables.
QRect boundingRect() const
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
KShapeGesture()
Create a new invalid shape gesture.
QString toString() const
Return a string representation of this gesture.
void getButtons(Qt::MouseButton *hold, Qt::MouseButton *thenPush) const
Write the button combination to hold and thenPush.
float metric(float dx, float dy)
QString i18nc(const char *ctxt, const char *text)
~KShapeGesture()
Destructor.
QString number(int n, int base)
bool operator==(const KShapeGesture &other) const
Return whether this gesture is equal to the other gesture.
uint hashable() const
Return an opaque value for use in hash tables.
void setShape(const QPolygon &shape)
Set the shape to draw to trigger this gesture.
QByteArray & append(char ch)
KRockerGesture & operator=(const KRockerGesture &other)
Set this gesture to the other gesture.
KGuiItem ok()
Returns the 'Ok' gui item.
bool operator!=(const KShapeGesture &other) const
Return the opposite of operator==()
QString rockerName() const
Return a user-friendly name of the button combination.
bool operator!=(const KRockerGesture &other) const
Return the opposite of operator==()
KRockerGesture()
Create a new invalid rocker gesture.
~KRockerGesture()
Destructor.
QByteArray toSvg(const QString &attributes=QString()) const
Return an idealized SVG image of this gesture.
void setHeight(int height)
bool isValid() const
Return true if this gesture is valid.
QString toString() const
Return a string representation of this gesture.
const_iterator constEnd() const
const_iterator constBegin() const
void setButtons(Qt::MouseButton hold, Qt::MouseButton thenPush)
set button combination to trigger
QString shapeName() const
Return the user-visible name for this gesture's shape, like "triangle" or "line". ...
QByteArray toUtf8() const