libkdcraw from trunk : update internal LibRaw to 0.7.0-alpha4
[kdegraphics.git] / kolourpaint / views / kpView_Selections.cpp
blob5df23866ca31b3b9079ab69a36b18d03d7cebc71
2 /*
3 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #define DEBUG_KP_VIEW 0
30 #define DEBUG_KP_VIEW_RENDERER ((DEBUG_KP_VIEW && 1) || 0)
33 #include <kpView.h>
34 #include <kpViewPrivate.h>
36 #include <kpAbstractSelection.h>
37 #include <kpTextSelection.h>
38 #include <kpTool.h>
41 // public
42 QRect kpView::selectionViewRect () const
44 return selection () ?
45 transformDocToView (selection ()->boundingRect ()) :
46 QRect ();
51 // public
52 QPoint kpView::mouseViewPointRelativeToSelection (const QPoint &viewPoint) const
54 if (!selection ())
55 return KP_INVALID_POINT;
57 return mouseViewPoint (viewPoint) - transformDocToView (selection ()->topLeft ());
60 // public
61 bool kpView::mouseOnSelection (const QPoint &viewPoint) const
63 const QRect selViewRect = selectionViewRect ();
64 if (!selViewRect.isValid ())
65 return false;
67 return selViewRect.contains (mouseViewPoint (viewPoint));
71 // public
72 int kpView::textSelectionMoveBorderAtomicSize () const
74 if (!textSelection ())
75 return 0;
77 return qMax (4, zoomLevelX () / 100);
80 // public
81 bool kpView::mouseOnSelectionToMove (const QPoint &viewPoint) const
83 if (!mouseOnSelection (viewPoint))
84 return false;
86 if (!textSelection ())
87 return true;
89 if (mouseOnSelectionResizeHandle (viewPoint))
90 return false;
93 const QPoint viewPointRelSel = mouseViewPointRelativeToSelection (viewPoint);
95 // Middle point should always be selectable
96 const QPoint selCenterDocPoint = selection ()->boundingRect ().center ();
97 if (tool () &&
98 tool ()->calculateCurrentPoint () == selCenterDocPoint)
100 return false;
104 const int atomicSize = textSelectionMoveBorderAtomicSize ();
105 const QRect selViewRect = selectionViewRect ();
107 return (viewPointRelSel.x () < atomicSize ||
108 viewPointRelSel.x () >= selViewRect.width () - atomicSize ||
109 viewPointRelSel.y () < atomicSize ||
110 viewPointRelSel.y () >= selViewRect.height () - atomicSize);
114 // protected
115 bool kpView::selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (int atomicSize) const
117 if (!selection ())
118 return false;
120 const QRect selViewRect = selectionViewRect ();
122 return (selViewRect.width () >= atomicSize * 5 ||
123 selViewRect.height () >= atomicSize * 5);
126 // public
127 int kpView::selectionResizeHandleAtomicSize () const
129 int atomicSize = qMin (7, qMax (4, zoomLevelX () / 100));
130 while (atomicSize > 0 &&
131 !selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (atomicSize))
133 atomicSize--;
136 return atomicSize;
139 // public
140 bool kpView::selectionLargeEnoughToHaveResizeHandles () const
142 return (selectionResizeHandleAtomicSize () > 0);
145 // public
146 QRegion kpView::selectionResizeHandlesViewRegion (bool forRenderer) const
148 QRegion ret;
150 const int atomicLength = selectionResizeHandleAtomicSize ();
151 if (atomicLength <= 0)
152 return QRegion ();
155 // HACK: At low zoom (e.g. 100%), resize handles will probably be too
156 // big and overlap text / cursor / too much of selection.
158 // So limit the _visual_ size of handles at low zoom. The
159 // handles' grab area remains the same for usability; so yes,
160 // there are a few pixels that don't look grabable but they are.
162 // The real solution is to be able to partially render the
163 // handles outside of the selection view rect. If not possible,
164 // at least for text boxes, render text on top of handles.
165 int normalAtomicLength = atomicLength;
166 int vertEdgeAtomicLength = atomicLength;
167 if (forRenderer && selection ())
169 if (zoomLevelX () <= 150)
171 if (normalAtomicLength > 1)
172 normalAtomicLength--;
174 if (vertEdgeAtomicLength > 1)
175 vertEdgeAtomicLength--;
178 // 1 line of text?
179 if (textSelection () && textSelection ()->textLines ().size () == 1)
181 if (zoomLevelX () <= 150)
182 vertEdgeAtomicLength = qMin (vertEdgeAtomicLength, qMax (2, zoomLevelX () / 100));
183 else if (zoomLevelX () <= 250)
184 vertEdgeAtomicLength = qMin (vertEdgeAtomicLength, qMax (3, zoomLevelX () / 100));
189 const QRect selViewRect = selectionViewRect ();
191 #define ADD_BOX_RELATIVE_TO_SELECTION(type,x,y) \
192 ret += QRect ((x), (y), type##AtomicLength, type##AtomicLength)
194 ADD_BOX_RELATIVE_TO_SELECTION (normal,
195 selViewRect.width () - normalAtomicLength,
196 selViewRect.height () - normalAtomicLength);
197 ADD_BOX_RELATIVE_TO_SELECTION (normal,
198 selViewRect.width () - normalAtomicLength,
200 ADD_BOX_RELATIVE_TO_SELECTION (normal,
202 selViewRect.height () - normalAtomicLength);
203 ADD_BOX_RELATIVE_TO_SELECTION (normal,
207 ADD_BOX_RELATIVE_TO_SELECTION (vertEdge,
208 selViewRect.width () - vertEdgeAtomicLength,
209 (selViewRect.height () - vertEdgeAtomicLength) / 2);
210 ADD_BOX_RELATIVE_TO_SELECTION (normal,
211 (selViewRect.width () - normalAtomicLength) / 2,
212 selViewRect.height () - normalAtomicLength);
213 ADD_BOX_RELATIVE_TO_SELECTION (normal,
214 (selViewRect.width () - normalAtomicLength) / 2,
216 ADD_BOX_RELATIVE_TO_SELECTION (vertEdge,
218 (selViewRect.height () - vertEdgeAtomicLength) / 2);
220 #undef ADD_BOX_RELATIVE_TO_SELECTION
222 ret.translate (selViewRect.x (), selViewRect.y ());
223 ret = ret.intersect (selViewRect);
225 return ret;
228 // public
229 // REFACTOR: use QFlags as the return type for better type safety.
230 int kpView::mouseOnSelectionResizeHandle (const QPoint &viewPoint) const
232 #if DEBUG_KP_VIEW
233 kDebug () << "kpView::mouseOnSelectionResizeHandle(viewPoint="
234 << viewPoint << ")" << endl;
235 #endif
237 if (!mouseOnSelection (viewPoint))
239 #if DEBUG_KP_VIEW
240 kDebug () << "\tmouse not on sel";
241 #endif
242 return 0;
246 const QRect selViewRect = selectionViewRect ();
247 #if DEBUG_KP_VIEW
248 kDebug () << "\tselViewRect=" << selViewRect;
249 #endif
252 const int atomicLength = selectionResizeHandleAtomicSize ();
253 #if DEBUG_KP_VIEW
254 kDebug () << "\tatomicLength=" << atomicLength;
255 #endif
257 if (atomicLength <= 0)
259 #if DEBUG_KP_VIEW
260 kDebug () << "\tsel not large enough to have resize handles";
261 #endif
262 // Want to make it possible to move a small selection
263 return 0;
267 const QPoint viewPointRelSel = mouseViewPointRelativeToSelection (viewPoint);
268 #if DEBUG_KP_VIEW
269 kDebug () << "\tviewPointRelSel=" << viewPointRelSel;
270 #endif
273 #define LOCAL_POINT_IN_BOX_AT(x,y) \
274 QRect ((x), (y), atomicLength, atomicLength).contains (viewPointRelSel)
276 // Favour the bottom & right and the corners.
277 if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength,
278 selViewRect.height () - atomicLength))
280 return kpView::Bottom | kpView::Right;
282 else if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength, 0))
284 return kpView::Top | kpView::Right;
286 else if (LOCAL_POINT_IN_BOX_AT (0, selViewRect.height () - atomicLength))
288 return kpView::Bottom | kpView::Left;
290 else if (LOCAL_POINT_IN_BOX_AT (0, 0))
292 return kpView::Top | kpView::Left;
294 else if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength,
295 (selViewRect.height () - atomicLength) / 2))
297 return kpView::Right;
299 else if (LOCAL_POINT_IN_BOX_AT ((selViewRect.width () - atomicLength) / 2,
300 selViewRect.height () - atomicLength))
302 return kpView::Bottom;
304 else if (LOCAL_POINT_IN_BOX_AT ((selViewRect.width () - atomicLength) / 2, 0))
306 return kpView::Top;
308 else if (LOCAL_POINT_IN_BOX_AT (0, (selViewRect.height () - atomicLength) / 2))
310 return kpView::Left;
312 else
314 #if DEBUG_KP_VIEW
315 kDebug () << "\tnot on sel resize handle";
316 #endif
317 return 0;
319 #undef LOCAL_POINT_IN_BOX_AT
322 // public
323 bool kpView::mouseOnSelectionToSelectText (const QPoint &viewPoint) const
325 #if DEBUG_KP_VIEW
326 kDebug () << "kpView::mouseOnSelectionToSelectText(viewPoint="
327 << viewPoint << ")" << endl;
328 #endif
330 if (!mouseOnSelection (viewPoint))
332 #if DEBUG_KP_VIEW
333 kDebug () << "\tmouse non on sel";
334 #endif
335 return false;
338 if (!textSelection ())
340 #if DEBUG_KP_VIEW
341 kDebug () << "\tsel not text";
342 #endif
343 return false;
346 #if DEBUG_KP_VIEW
347 kDebug () << "\tmouse on sel: to move=" << mouseOnSelectionToMove ()
348 << " to resize=" << mouseOnSelectionResizeHandle ()
349 << endl;
350 #endif
352 return (!mouseOnSelectionToMove (viewPoint) &&
353 !mouseOnSelectionResizeHandle (viewPoint));