1 /** @file Decoration.cxx
2  ** Visual elements added over text.
3  **/
4 // Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
5 // The License.txt file describes the conditions under which this software may be distributed.
6 
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11 
12 #include "Platform.h"
13 
14 #include "Scintilla.h"
15 #include "SplitVector.h"
16 #include "Partitioning.h"
17 #include "RunStyles.h"
18 #include "Decoration.h"
19 
20 #ifdef SCI_NAMESPACE
21 using namespace Scintilla;
22 #endif
23 
Decoration(int indicator_)24 Decoration::Decoration(int indicator_) : next(0), indicator(indicator_) {
25 }
26 
~Decoration()27 Decoration::~Decoration() {
28 }
29 
Empty()30 bool Decoration::Empty() {
31 	return (rs.Runs() == 1) && (rs.AllSameAs(0));
32 }
33 
DecorationList()34 DecorationList::DecorationList() : currentIndicator(0), currentValue(1), current(0),
35 	lengthDocument(0), root(0), clickNotified(false) {
36 }
37 
~DecorationList()38 DecorationList::~DecorationList() {
39 	Decoration *deco = root;
40 	while (deco) {
41 		Decoration *decoNext = deco->next;
42 		delete deco;
43 		deco = decoNext;
44 	}
45 	root = 0;
46 	current = 0;
47 }
48 
DecorationFromIndicator(int indicator)49 Decoration *DecorationList::DecorationFromIndicator(int indicator) {
50 	for (Decoration *deco=root; deco; deco = deco->next) {
51 		if (deco->indicator == indicator) {
52 			return deco;
53 		}
54 	}
55 	return 0;
56 }
57 
Create(int indicator,int length)58 Decoration *DecorationList::Create(int indicator, int length) {
59 	currentIndicator = indicator;
60 	Decoration *decoNew = new Decoration(indicator);
61 	decoNew->rs.InsertSpace(0, length);
62 
63 	Decoration *decoPrev = 0;
64 	Decoration *deco = root;
65 
66 	while (deco && (deco->indicator < indicator)) {
67 		decoPrev = deco;
68 		deco = deco->next;
69 	}
70 	if (decoPrev == 0) {
71 		decoNew->next = root;
72 		root = decoNew;
73 	} else {
74 		decoNew->next = deco;
75 		decoPrev->next = decoNew;
76 	}
77 	return decoNew;
78 }
79 
Delete(int indicator)80 void DecorationList::Delete(int indicator) {
81 	Decoration *decoToDelete = 0;
82 	if (root) {
83 		if (root->indicator == indicator) {
84 			decoToDelete = root;
85 			root = root->next;
86 		} else {
87 			Decoration *deco=root;
88 			while (deco->next && !decoToDelete) {
89 				if (deco->next && deco->next->indicator == indicator) {
90 					decoToDelete = deco->next;
91 					deco->next = decoToDelete->next;
92 				} else {
93 					deco = deco->next;
94 				}
95 			}
96 		}
97 	}
98 	if (decoToDelete) {
99 		delete decoToDelete;
100 		current = 0;
101 	}
102 }
103 
SetCurrentIndicator(int indicator)104 void DecorationList::SetCurrentIndicator(int indicator) {
105 	currentIndicator = indicator;
106 	current = DecorationFromIndicator(indicator);
107 	currentValue = 1;
108 }
109 
SetCurrentValue(int value)110 void DecorationList::SetCurrentValue(int value) {
111 	currentValue = value ? value : 1;
112 }
113 
FillRange(int & position,int value,int & fillLength)114 bool DecorationList::FillRange(int &position, int value, int &fillLength) {
115 	if (!current) {
116 		current = DecorationFromIndicator(currentIndicator);
117 		if (!current) {
118 			current = Create(currentIndicator, lengthDocument);
119 		}
120 	}
121 	bool changed = current->rs.FillRange(position, value, fillLength);
122 	if (current->Empty()) {
123 		Delete(currentIndicator);
124 	}
125 	return changed;
126 }
127 
InsertSpace(int position,int insertLength)128 void DecorationList::InsertSpace(int position, int insertLength) {
129 	const bool atEnd = position == lengthDocument;
130 	lengthDocument += insertLength;
131 	for (Decoration *deco=root; deco; deco = deco->next) {
132 		deco->rs.InsertSpace(position, insertLength);
133 		if (atEnd) {
134 			deco->rs.FillRange(position, 0, insertLength);
135 		}
136 	}
137 }
138 
DeleteRange(int position,int deleteLength)139 void DecorationList::DeleteRange(int position, int deleteLength) {
140 	lengthDocument -= deleteLength;
141 	Decoration *deco;
142 	for (deco=root; deco; deco = deco->next) {
143 		deco->rs.DeleteRange(position, deleteLength);
144 	}
145 	DeleteAnyEmpty();
146 }
147 
DeleteAnyEmpty()148 void DecorationList::DeleteAnyEmpty() {
149 	Decoration *deco = root;
150 	while (deco) {
151 		if ((lengthDocument == 0) || deco->Empty()) {
152 			Delete(deco->indicator);
153 			deco = root;
154 		} else {
155 			deco = deco->next;
156 		}
157 	}
158 }
159 
AllOnFor(int position)160 int DecorationList::AllOnFor(int position) {
161 	int mask = 0;
162 	for (Decoration *deco=root; deco; deco = deco->next) {
163 		if (deco->rs.ValueAt(position)) {
164 			mask |= 1 << deco->indicator;
165 		}
166 	}
167 	return mask;
168 }
169 
ValueAt(int indicator,int position)170 int DecorationList::ValueAt(int indicator, int position) {
171 	Decoration *deco = DecorationFromIndicator(indicator);
172 	if (deco) {
173 		return deco->rs.ValueAt(position);
174 	}
175 	return 0;
176 }
177 
Start(int indicator,int position)178 int DecorationList::Start(int indicator, int position) {
179 	Decoration *deco = DecorationFromIndicator(indicator);
180 	if (deco) {
181 		return deco->rs.StartRun(position);
182 	}
183 	return 0;
184 }
185 
End(int indicator,int position)186 int DecorationList::End(int indicator, int position) {
187 	Decoration *deco = DecorationFromIndicator(indicator);
188 	if (deco) {
189 		return deco->rs.EndRun(position);
190 	}
191 	return 0;
192 }
193