File indexing completed on 2024-04-21 05:53:10
0001 /* 0002 This file is part of the Okteta Gui library, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 2003, 2008-2009, 2021 Friedrich W. H. Kossebau <kossebau@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #ifndef OKTETA_SELECTION_HPP 0010 #define OKTETA_SELECTION_HPP 0011 0012 // Okteta core 0013 #include <Okteta/AddressRange> 0014 0015 namespace Okteta { 0016 0017 /** This class describes a selected range of the buffer. 0018 * As it is used as selection controlled by 0019 * mouse and keyboard commands it offers two ways to set its range: 0020 * - by giving the startposition (of the cursor) of an interactive selection 0021 * and the subsequent end positions (until selection is finished) 0022 * - direct setting (as provided by AddressRange) 0023 * 0024 * the interactive selection takes care that 0025 * 0026 * @author Friedrich W. H. Kossebau 0027 */ 0028 class Selection 0029 { 0030 public: 0031 /** creates a selection with a given start. 0032 * @param index index in front of which the selection begins 0033 */ 0034 explicit Selection(Address index); 0035 Selection(const Selection& other); 0036 /** creates an invalid selection */ 0037 Selection(); 0038 0039 ~Selection(); 0040 0041 public: 0042 Selection& operator=(const Selection& other); 0043 Selection& operator=(const AddressRange& range); 0044 0045 bool operator==(const Selection& other) const; 0046 bool operator!=(const Selection& other) const; 0047 0048 public: // modification access 0049 /** starts the selection. 0050 * For this the anchor, start and end are set to the given index, 0051 * so the initial selection is empty. 0052 * @param index index in front of which the selection begins 0053 */ 0054 void setStart(Address index); 0055 /** sets the end of the current selection. 0056 * If the end is before the start the selection will reach from the given index 0057 * @param index index in front of which the selection ends 0058 */ 0059 void setEnd(Address index); 0060 /** sets the selection to be invalid 0061 */ 0062 void cancel(); 0063 /** sets the anchor to the start or the end. 0064 * @param forward true to the start, otherwise to the end 0065 * If the selection has not started the behaviour is undefined. 0066 */ 0067 void setForward(bool forward = true); 0068 /** swaps anchor from start to end or vice versa. 0069 * If the selection has not started the behaviour is undefined. 0070 */ 0071 void reverse(); 0072 0073 void adaptToReplacement(Address pos, Size removedLength, Size insertedLength); 0074 void adaptToSwap(Address firstOffset, Address secondOffset, Size secondLength); 0075 0076 public: // value access 0077 /** 0078 * @return anchor value 0079 */ 0080 Address anchor() const; 0081 Address start() const; 0082 Address end() const; 0083 Address nextBeforeStart() const; 0084 Address nextBehindEnd() const; 0085 /** 0086 * @return range 0087 */ 0088 const AddressRange& range() const; 0089 0090 public: // logic access 0091 bool isValid() const; 0092 /** 0093 * @return @c true if the anchor has been set, otherwise @c false. 0094 */ 0095 bool started() const; 0096 /** 0097 * @return @c true if the anchor has been set and the selection is empty, otherwise @c false. 0098 */ 0099 bool justStarted() const; 0100 /** 0101 * @return @c true if the anchor is at the begin of the selection 0102 */ 0103 bool isForward() const; 0104 0105 private: 0106 /** mRange */ 0107 AddressRange mRange; 0108 /** cursor index where the selection starts */ 0109 Address mAnchor = -1; 0110 }; 0111 0112 inline Selection::Selection() = default; 0113 inline Selection::Selection(const Selection& other) = default; 0114 inline Selection::Selection(Address index) : mAnchor(index) {} 0115 inline Selection::~Selection() = default; 0116 0117 inline Selection& Selection::operator=(const Selection& other) = default; 0118 0119 inline Selection& Selection::operator=(const AddressRange& range) 0120 { 0121 mRange = range; 0122 mAnchor = range.start(); 0123 return *this; 0124 } 0125 0126 inline bool Selection::operator==(const Selection& other) const 0127 { 0128 return (mRange == other.mRange) && (mAnchor == other.mAnchor); 0129 } 0130 inline bool Selection::operator!=(const Selection& other) const 0131 { 0132 return (mRange != other.mRange) || (mAnchor != other.mAnchor); 0133 } 0134 0135 inline void Selection::setStart(Address index) 0136 { 0137 mAnchor = index; 0138 mRange.unset(); 0139 } 0140 0141 inline void Selection::setEnd(Address index) 0142 { 0143 // nothing selected? 0144 if (index == mAnchor) { 0145 mRange.unset(); 0146 } 0147 // selecting forwards? 0148 else if (index > mAnchor) { 0149 mRange.setStart(mAnchor); 0150 mRange.setEnd(index - 1); 0151 } 0152 // selecting backwards 0153 else { 0154 mRange.setStart(index); 0155 mRange.setEnd(mAnchor - 1); 0156 } 0157 } 0158 0159 inline void Selection::reverse() 0160 { 0161 mAnchor = isForward() ? mRange.nextBehindEnd() : mRange.start(); 0162 } 0163 0164 inline void Selection::setForward(bool Forward) 0165 { 0166 mAnchor = Forward ? mRange.start() : mRange.nextBehindEnd(); 0167 } 0168 0169 inline const AddressRange& Selection::range() const { return mRange; } 0170 inline Address Selection::anchor() const { return mAnchor; } 0171 inline Address Selection::start() const { return mRange.start(); } 0172 inline Address Selection::end() const { return mRange.end(); } 0173 inline Address Selection::nextBeforeStart() const { return mRange.nextBeforeStart(); } 0174 inline Address Selection::nextBehindEnd() const { return mRange.nextBehindEnd(); } 0175 0176 inline void Selection::cancel() { mAnchor = -1; mRange.unset(); } 0177 0178 inline bool Selection::isValid() const { return mRange.isValid(); } 0179 inline bool Selection::started() const { return mAnchor != -1; } 0180 inline bool Selection::justStarted() const { return mAnchor != -1 && mRange.start() == -1; } 0181 inline bool Selection::isForward() const { return mAnchor == mRange.start(); } 0182 0183 inline void Selection::adaptToReplacement(Address pos, Size removedLength, Size insertedLength) 0184 { 0185 mRange.adaptToReplacement(pos, removedLength, insertedLength); 0186 mAnchor = isForward() ? mRange.start() : mRange.nextBehindEnd(); 0187 } 0188 0189 inline void Selection::adaptToSwap(Address firstOffset, Address secondOffset, Size secondLength) 0190 { 0191 // no intersection? 0192 if (mRange.end() < firstOffset || mRange.start() > secondOffset + secondLength - 1) { 0193 return; 0194 } 0195 0196 const AddressRange firstSection(firstOffset, secondOffset - 1); 0197 if (firstSection.includes(mRange)) { 0198 mRange.moveBy(secondLength); 0199 } else { 0200 const AddressRange secondRange = AddressRange::fromWidth(secondOffset, secondLength); 0201 if (secondRange.includes(mRange)) { 0202 mRange.moveBy(-firstSection.width()); 0203 } else { 0204 mRange.unset(); 0205 } 0206 } 0207 } 0208 0209 } 0210 0211 #endif