1 // Scintilla source code edit control
2 /** @file ContractionState.cxx
3  ** Manages visibility of lines for folding.
4  **/
5 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
7 
8 #include "Platform.h"
9 
10 #include "ContractionState.h"
11 
OneLine()12 OneLine::OneLine() {
13 	displayLine = 0;
14 	//docLine = 0;
15 	visible = true;
16 	height = 1;
17 	expanded = true;
18 }
19 
ContractionState()20 ContractionState::ContractionState() {
21 	lines = 0;
22 	size = 0;
23 	linesInDoc = 1;
24 	linesInDisplay = 1;
25 	valid = false;
26 	docLines = 0;
27 	sizeDocLines = 0;
28 }
29 
~ContractionState()30 ContractionState::~ContractionState() {
31 	Clear();
32 }
33 
MakeValid() const34 void ContractionState::MakeValid() const {
35 	if (!valid) {
36 		// Could be cleverer by keeping the index of the last still valid entry
37 		// rather than invalidating all.
38 		linesInDisplay = 0;
39 		for (int lineInDoc=0; lineInDoc<linesInDoc; lineInDoc++) {
40 			lines[lineInDoc].displayLine = linesInDisplay;
41 			if (lines[lineInDoc].visible) {
42 				linesInDisplay += lines[lineInDoc].height;
43 			}
44 		}
45 		if (sizeDocLines < linesInDisplay) {
46 			delete []docLines;
47 			int *docLinesNew = new int[linesInDisplay + growSize];
48 			if (!docLinesNew) {
49 				docLines = 0;
50 				sizeDocLines = 0;
51 				return;
52 			}
53 			docLines = docLinesNew;
54 			sizeDocLines = linesInDisplay + growSize;
55 		}
56 
57 		int lineInDisplay=0;
58 		for (int line=0; line<linesInDoc; line++) {
59 			if (lines[line].visible) {
60 				for (int linePiece=0; linePiece<lines[line].height; linePiece++) {
61 					docLines[lineInDisplay] = line;
62 					lineInDisplay++;
63 				}
64 			}
65 		}
66 		valid = true;
67 	}
68 }
69 
Clear()70 void ContractionState::Clear() {
71 	delete []lines;
72 	lines = 0;
73 	size = 0;
74 	linesInDoc = 1;
75 	linesInDisplay = 1;
76 	delete []docLines;
77 	docLines = 0;
78 	sizeDocLines = 0;
79 }
80 
LinesInDoc() const81 int ContractionState::LinesInDoc() const {
82 	return linesInDoc;
83 }
84 
LinesDisplayed() const85 int ContractionState::LinesDisplayed() const {
86 	if (size != 0) {
87 		MakeValid();
88 	}
89 	return linesInDisplay;
90 }
91 
DisplayFromDoc(int lineDoc) const92 int ContractionState::DisplayFromDoc(int lineDoc) const {
93 	if (size == 0) {
94 		return lineDoc;
95 	}
96 	MakeValid();
97 	if ((lineDoc >= 0) && (lineDoc < linesInDoc)) {
98 		return lines[lineDoc].displayLine;
99 	}
100 	return -1;
101 }
102 
DocFromDisplay(int lineDisplay) const103 int ContractionState::DocFromDisplay(int lineDisplay) const {
104 	if (lineDisplay <= 0)
105 		return 0;
106 	if (lineDisplay >= linesInDisplay)
107 		return linesInDoc;
108 	if (size == 0)
109 		return lineDisplay;
110 	MakeValid();
111 	if (docLines) {	// Valid allocation
112 		return docLines[lineDisplay];
113 	} else {
114 		return 0;
115 	}
116 }
117 
Grow(int sizeNew)118 void ContractionState::Grow(int sizeNew) {
119 	OneLine *linesNew = new OneLine[sizeNew];
120 	if (linesNew) {
121 		int i = 0;
122 		for (; i < size; i++) {
123 			linesNew[i] = lines[i];
124 		}
125 		for (; i < sizeNew; i++) {
126 			linesNew[i].displayLine = i;
127 		}
128 		delete []lines;
129 		lines = linesNew;
130 		size = sizeNew;
131 		valid = false;
132 	} else {
133 		Platform::DebugPrintf("No memory available\n");
134 		// TODO: Blow up
135 	}
136 }
137 
InsertLines(int lineDoc,int lineCount)138 void ContractionState::InsertLines(int lineDoc, int lineCount) {
139 	if (size == 0) {
140 		linesInDoc += lineCount;
141 		linesInDisplay += lineCount;
142 		return;
143 	}
144 	//Platform::DebugPrintf("InsertLine[%d] = %d\n", lineDoc);
145 	if ((linesInDoc + lineCount + 2) >= size) {
146 		Grow(linesInDoc + lineCount + growSize);
147 	}
148 	linesInDoc += lineCount;
149 	for (int i = linesInDoc; i >= lineDoc + lineCount; i--) {
150 		lines[i].visible = lines[i - lineCount].visible;
151 		lines[i].height = lines[i - lineCount].height;
152 		linesInDisplay += lines[i].height;
153 		lines[i].expanded = lines[i - lineCount].expanded;
154 	}
155 	for (int d=0;d<lineCount;d++) {
156 		lines[lineDoc+d].visible = true;	// Should inherit visibility from context ?
157 		lines[lineDoc+d].height = 1;
158 		lines[lineDoc+d].expanded = true;
159 	}
160 	valid = false;
161 }
162 
DeleteLines(int lineDoc,int lineCount)163 void ContractionState::DeleteLines(int lineDoc, int lineCount) {
164 	if (size == 0) {
165 		linesInDoc -= lineCount;
166 		linesInDisplay -= lineCount;
167 		return;
168 	}
169 	int deltaDisplayed = 0;
170 	for (int d=0;d<lineCount;d++) {
171 		if (lines[lineDoc+d].visible)
172 			deltaDisplayed -= lines[lineDoc+d].height;
173 	}
174 	for (int i = lineDoc; i < linesInDoc-lineCount; i++) {
175 		if (i != 0) // Line zero is always visible
176 			lines[i].visible = lines[i + lineCount].visible;
177 		lines[i].expanded = lines[i + lineCount].expanded;
178 		lines[i].height = lines[i + lineCount].height;
179 	}
180 	linesInDoc -= lineCount;
181 	linesInDisplay += deltaDisplayed;
182 	valid = false;
183 }
184 
GetVisible(int lineDoc) const185 bool ContractionState::GetVisible(int lineDoc) const {
186 	if (size == 0)
187 		return true;
188 	if ((lineDoc >= 0) && (lineDoc < linesInDoc)) {
189 		return lines[lineDoc].visible;
190 	} else {
191 		return false;
192 	}
193 }
194 
SetVisible(int lineDocStart,int lineDocEnd,bool visible)195 bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible) {
196 	if (lineDocStart == 0)
197 		lineDocStart++;
198 	if (lineDocStart > lineDocEnd)
199 		return false;
200 	if (size == 0) {
201 		Grow(linesInDoc + growSize);
202 	}
203 	// TODO: modify docLine members to mirror displayLine
204 	int delta = 0;
205 	// Change lineDocs
206 	if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < linesInDoc)) {
207 		for (int line=lineDocStart; line <= lineDocEnd; line++) {
208 			if (lines[line].visible != visible) {
209 				delta += visible ? lines[line].height : -lines[line].height;
210 				lines[line].visible = visible;
211 			}
212 		}
213 	}
214 	linesInDisplay += delta;
215 	valid = false;
216 	return delta != 0;
217 }
218 
GetExpanded(int lineDoc) const219 bool ContractionState::GetExpanded(int lineDoc) const {
220 	if (size == 0)
221 		return true;
222 	if ((lineDoc >= 0) && (lineDoc < linesInDoc)) {
223 		return lines[lineDoc].expanded;
224 	} else {
225 		return false;
226 	}
227 }
228 
SetExpanded(int lineDoc,bool expanded)229 bool ContractionState::SetExpanded(int lineDoc, bool expanded) {
230 	if (size == 0) {
231 		if (expanded) {
232 			// If in completely expanded state then setting
233 			// one line to expanded has no effect.
234 			return false;
235 		}
236 		Grow(linesInDoc + growSize);
237 	}
238 	if ((lineDoc >= 0) && (lineDoc < linesInDoc)) {
239 		if (lines[lineDoc].expanded != expanded) {
240 			lines[lineDoc].expanded = expanded;
241 			return true;
242 		}
243 	}
244 	return false;
245 }
246 
GetHeight(int lineDoc) const247 int ContractionState::GetHeight(int lineDoc) const {
248 	if (size == 0)
249 		return 1;
250 	if ((lineDoc >= 0) && (lineDoc < linesInDoc)) {
251 		return lines[lineDoc].height;
252 	} else {
253 		return 1;
254 	}
255 }
256 
257 // Set the number of display lines needed for this line.
258 // Return true if this is a change.
SetHeight(int lineDoc,int height)259 bool ContractionState::SetHeight(int lineDoc, int height) {
260 	if (lineDoc > linesInDoc)
261 		return false;
262 	if (size == 0) {
263 		if (height == 1) {
264 			// If in completely expanded state then all lines
265 			// assumed to have height of one so no effect here.
266 			return false;
267 		}
268 		Grow(linesInDoc + growSize);
269 	}
270 	if (lines[lineDoc].height != height) {
271 		lines[lineDoc].height = height;
272 		valid = false;
273 		return true;
274 	} else {
275 		return false;
276 	}
277 }
278 
ShowAll()279 void ContractionState::ShowAll() {
280 	delete []lines;
281 	lines = 0;
282 	size = 0;
283 
284 	delete []docLines;
285 	docLines = 0;
286 	sizeDocLines = 0;
287 
288 	linesInDisplay = linesInDoc;
289 }
290