3 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
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)
34 #include <kpViewPrivate.h>
36 #include <kpAbstractSelection.h>
37 #include <kpTextSelection.h>
42 QRect
kpView::selectionViewRect () const
45 transformDocToView (selection ()->boundingRect ()) :
52 QPoint
kpView::mouseViewPointRelativeToSelection (const QPoint
&viewPoint
) const
55 return KP_INVALID_POINT
;
57 return mouseViewPoint (viewPoint
) - transformDocToView (selection ()->topLeft ());
61 bool kpView::mouseOnSelection (const QPoint
&viewPoint
) const
63 const QRect selViewRect
= selectionViewRect ();
64 if (!selViewRect
.isValid ())
67 return selViewRect
.contains (mouseViewPoint (viewPoint
));
72 int kpView::textSelectionMoveBorderAtomicSize () const
74 if (!textSelection ())
77 return qMax (4, zoomLevelX () / 100);
81 bool kpView::mouseOnSelectionToMove (const QPoint
&viewPoint
) const
83 if (!mouseOnSelection (viewPoint
))
86 if (!textSelection ())
89 if (mouseOnSelectionResizeHandle (viewPoint
))
93 const QPoint viewPointRelSel
= mouseViewPointRelativeToSelection (viewPoint
);
95 // Middle point should always be selectable
96 const QPoint selCenterDocPoint
= selection ()->boundingRect ().center ();
98 tool ()->calculateCurrentPoint () == selCenterDocPoint
)
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
);
115 bool kpView::selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (int atomicSize
) const
120 const QRect selViewRect
= selectionViewRect ();
122 return (selViewRect
.width () >= atomicSize
* 5 ||
123 selViewRect
.height () >= atomicSize
* 5);
127 int kpView::selectionResizeHandleAtomicSize () const
129 int atomicSize
= qMin (7, qMax (4, zoomLevelX () / 100));
130 while (atomicSize
> 0 &&
131 !selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (atomicSize
))
140 bool kpView::selectionLargeEnoughToHaveResizeHandles () const
142 return (selectionResizeHandleAtomicSize () > 0);
146 QRegion
kpView::selectionResizeHandlesViewRegion (bool forRenderer
) const
150 const int atomicLength
= selectionResizeHandleAtomicSize ();
151 if (atomicLength
<= 0)
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
--;
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
);
229 // REFACTOR: use QFlags as the return type for better type safety.
230 int kpView::mouseOnSelectionResizeHandle (const QPoint
&viewPoint
) const
233 kDebug () << "kpView::mouseOnSelectionResizeHandle(viewPoint="
234 << viewPoint
<< ")" << endl
;
237 if (!mouseOnSelection (viewPoint
))
240 kDebug () << "\tmouse not on sel";
246 const QRect selViewRect
= selectionViewRect ();
248 kDebug () << "\tselViewRect=" << selViewRect
;
252 const int atomicLength
= selectionResizeHandleAtomicSize ();
254 kDebug () << "\tatomicLength=" << atomicLength
;
257 if (atomicLength
<= 0)
260 kDebug () << "\tsel not large enough to have resize handles";
262 // Want to make it possible to move a small selection
267 const QPoint viewPointRelSel
= mouseViewPointRelativeToSelection (viewPoint
);
269 kDebug () << "\tviewPointRelSel=" << viewPointRelSel
;
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))
308 else if (LOCAL_POINT_IN_BOX_AT (0, (selViewRect
.height () - atomicLength
) / 2))
315 kDebug () << "\tnot on sel resize handle";
319 #undef LOCAL_POINT_IN_BOX_AT
323 bool kpView::mouseOnSelectionToSelectText (const QPoint
&viewPoint
) const
326 kDebug () << "kpView::mouseOnSelectionToSelectText(viewPoint="
327 << viewPoint
<< ")" << endl
;
330 if (!mouseOnSelection (viewPoint
))
333 kDebug () << "\tmouse non on sel";
338 if (!textSelection ())
341 kDebug () << "\tsel not text";
347 kDebug () << "\tmouse on sel: to move=" << mouseOnSelectionToMove ()
348 << " to resize=" << mouseOnSelectionResizeHandle ()
352 return (!mouseOnSelectionToMove (viewPoint
) &&
353 !mouseOnSelectionResizeHandle (viewPoint
));