File indexing completed on 2024-05-12 16:34:24
0001 /* This file is part of the KDE project 0002 Copyright 2011 Silvio Heinrich <plassy@web.de> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "SelectionRect.h" 0021 0022 #include <QRectF> 0023 #include <QPointF> 0024 #include <QSizeF> 0025 #include <limits> 0026 0027 SelectionRect::SelectionRect(const QRectF &rect, qreal handleSize): 0028 m_rect(rect), 0029 m_aspectRatio(1), 0030 m_aConstr(0), 0031 m_handleSize(handleSize), 0032 m_currentHandle(0) 0033 { 0034 m_lConstr = -std::numeric_limits<qreal>::infinity(); 0035 m_rConstr = std::numeric_limits<qreal>::infinity(); 0036 m_tConstr = -std::numeric_limits<qreal>::infinity(); 0037 m_bConstr = std::numeric_limits<qreal>::infinity(); 0038 } 0039 0040 void SelectionRect::setRect(const QRectF &rect) 0041 { 0042 m_rect = rect; 0043 } 0044 0045 void SelectionRect::setHandleSize(qreal size) 0046 { 0047 m_handleSize = size; 0048 } 0049 0050 void SelectionRect::setAspectRatio(qreal aspect) 0051 { 0052 m_aspectRatio = aspect; 0053 } 0054 0055 void SelectionRect::setConstrainingRect(const QRectF &rect) 0056 { 0057 m_lConstr = rect.left(); 0058 m_rConstr = rect.right(); 0059 m_tConstr = rect.top(); 0060 m_bConstr = rect.bottom(); 0061 } 0062 0063 void SelectionRect::setConstrainingAspectRatio(qreal aspect) 0064 { 0065 m_aConstr = aspect; 0066 0067 if (m_aConstr != 0.0) { 0068 fixAspect(TOP_HANDLE); 0069 } 0070 } 0071 0072 bool SelectionRect::beginDragging(const QPointF &pos) 0073 { 0074 m_tempPos = pos; 0075 m_currentHandle = getHandleFlags(pos); 0076 return bool(m_currentHandle); 0077 } 0078 0079 void SelectionRect::doDragging(const QPointF &pos) 0080 { 0081 if (m_currentHandle & INSIDE_RECT) { 0082 m_rect.moveTo(m_rect.topLeft() + (pos - m_tempPos)); 0083 m_tempPos = pos; 0084 0085 if (m_rect.left() < m_lConstr) { 0086 m_rect.moveLeft(m_lConstr); 0087 } 0088 if (m_rect.right() > m_rConstr) { 0089 m_rect.moveRight(m_rConstr); 0090 } 0091 if (m_rect.top() < m_tConstr) { 0092 m_rect.moveTop(m_tConstr); 0093 } 0094 if (m_rect.bottom() > m_bConstr) { 0095 m_rect.moveBottom(m_bConstr); 0096 } 0097 } 0098 else { 0099 if (m_currentHandle & TOP_HANDLE) { 0100 m_rect.setTop(qBound(m_tConstr, pos.y(), m_bConstr)); 0101 } 0102 if (m_currentHandle & BOTTOM_HANDLE) { 0103 m_rect.setBottom(qBound(m_tConstr, pos.y(), m_bConstr)); 0104 } 0105 if (m_currentHandle & LEFT_HANDLE) { 0106 m_rect.setLeft(qBound(m_lConstr, pos.x(), m_rConstr)); 0107 } 0108 if (m_currentHandle & RIGHT_HANDLE) { 0109 m_rect.setRight(qBound(m_lConstr, pos.x(), m_rConstr)); 0110 } 0111 0112 if (m_aConstr != 0.0) { 0113 fixAspect(m_currentHandle); 0114 } 0115 } 0116 } 0117 0118 void SelectionRect::finishDragging() 0119 { 0120 m_currentHandle = 0; 0121 m_rect = m_rect.normalized(); 0122 } 0123 0124 SelectionRect::HandleFlags SelectionRect::getHandleFlags(const QPointF &pos) const 0125 { 0126 for(int i=0; i<getNumHandles(); ++i) { 0127 if(getHandleRect(getHandleFlags(i)).contains(pos)) 0128 return getHandleFlags(i); 0129 } 0130 0131 return m_rect.contains(pos) ? INSIDE_RECT : 0; 0132 } 0133 0134 SelectionRect::HandleFlags SelectionRect::getHandleFlags(int handleIndex) const 0135 { 0136 switch(handleIndex) 0137 { 0138 case 0: return TOP_LEFT_HANDLE; 0139 case 1: return TOP_HANDLE; 0140 case 2: return TOP_RIGHT_HANDLE; 0141 case 3: return RIGHT_HANDLE; 0142 case 4: return BOTTOM_RIGHT_HANDLE; 0143 case 5: return BOTTOM_HANDLE; 0144 case 6: return BOTTOM_LEFT_HANDLE; 0145 case 7: return LEFT_HANDLE; 0146 } 0147 0148 return 0; 0149 } 0150 0151 QRectF SelectionRect::getHandleRect(HandleFlags handle) const 0152 { 0153 qreal x = (m_rect.left() + m_rect.right()) / 2.0; 0154 qreal y = (m_rect.top() + m_rect.bottom()) / 2.0; 0155 qreal w = m_handleSize; 0156 qreal h = m_handleSize * m_aspectRatio; 0157 0158 x = (handle & LEFT_HANDLE) ? m_rect.left() : x; 0159 y = (handle & TOP_HANDLE) ? m_rect.top() : y; 0160 x = (handle & RIGHT_HANDLE) ? m_rect.right() : x; 0161 y = (handle & BOTTOM_HANDLE) ? m_rect.bottom() : y; 0162 0163 return QRectF(x-(w/2.0), y-(h/2.0), w, h); 0164 } 0165 0166 void SelectionRect::fixAspect(HandleFlags handle) 0167 { 0168 QRectF oldRect = m_rect; 0169 0170 switch (handle) 0171 { 0172 case TOP_HANDLE: 0173 case BOTTOM_HANDLE: 0174 m_rect.setWidth((m_rect.height() * m_aConstr) / m_aspectRatio); 0175 break; 0176 0177 case LEFT_HANDLE: 0178 case RIGHT_HANDLE: 0179 case BOTTOM_RIGHT_HANDLE: 0180 m_rect.setHeight((m_rect.width() / m_aConstr) * m_aspectRatio); 0181 break; 0182 0183 case TOP_RIGHT_HANDLE: 0184 m_rect.setHeight((m_rect.width() / m_aConstr) * m_aspectRatio); 0185 m_rect.moveBottomLeft(oldRect.bottomLeft()); 0186 break; 0187 0188 case BOTTOM_LEFT_HANDLE: 0189 m_rect.setHeight((m_rect.width() / m_aConstr) * m_aspectRatio); 0190 m_rect.moveTopRight(oldRect.topRight()); 0191 break; 0192 0193 case TOP_LEFT_HANDLE: 0194 m_rect.setHeight((m_rect.width() / m_aConstr) * m_aspectRatio); 0195 m_rect.moveBottomRight(oldRect.bottomRight()); 0196 break; 0197 } 0198 0199 if (m_rect.top() < m_tConstr || m_rect.top() > m_bConstr) { 0200 m_rect.setTop(qBound(m_tConstr, m_rect.top(), m_bConstr)); 0201 0202 if (!qFuzzyCompare(1.0 + (oldRect.top() - m_rect.top()), 1.0)) { 0203 fixAspect(TOP_HANDLE); 0204 } 0205 } 0206 0207 if (m_rect.bottom() < m_tConstr || m_rect.bottom() > m_bConstr) { 0208 m_rect.setBottom(qBound(m_tConstr, m_rect.bottom(), m_bConstr)); 0209 0210 if (!qFuzzyCompare(1.0 + (oldRect.bottom() - m_rect.bottom()), 1.0)) { 0211 fixAspect(BOTTOM_HANDLE); 0212 } 0213 0214 if (handle & LEFT_HANDLE) { 0215 m_rect.moveTopRight(oldRect.topRight()); 0216 } 0217 0218 if (handle & RIGHT_HANDLE) { 0219 m_rect.moveTopLeft(oldRect.topLeft()); 0220 } 0221 } 0222 0223 if (m_rect.left() < m_lConstr || m_rect.left() > m_rConstr) { 0224 m_rect.setLeft(qBound(m_lConstr, m_rect.left(), m_rConstr)); 0225 0226 if (!qFuzzyCompare(1.0 + (oldRect.left() - m_rect.left()), 1.0)) { 0227 fixAspect(LEFT_HANDLE); 0228 } 0229 } 0230 0231 if (m_rect.right() < m_lConstr || m_rect.right() > m_rConstr) { 0232 m_rect.setRight(qBound(m_lConstr, m_rect.right(), m_rConstr)); 0233 0234 if (!qFuzzyCompare(1.0 + (oldRect.right() - m_rect.right()), 1.0)) { 0235 fixAspect(RIGHT_HANDLE); 0236 } 0237 0238 m_rect.moveBottomRight(oldRect.bottomRight()); 0239 } 0240 }