]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/XPM.cxx
7fc05bb9b46cd7403cc0ba57a86ba45bfa6dd0d9
1 // Scintilla source code edit control
3 ** Define a class that holds data in the X Pixmap (XPM) format.
5 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
16 using namespace Scintilla
;
19 static const char *NextField(const char *s
) {
20 // In case there are leading spaces in the string
21 while (*s
&& *s
== ' ') {
24 while (*s
&& *s
!= ' ') {
27 while (*s
&& *s
== ' ') {
33 // Data lines in XPM can be terminated either with NUL or "
34 static size_t MeasureLength(const char *s
) {
36 while (s
[i
] && (s
[i
] != '\"'))
41 ColourAllocated
XPM::ColourFromCode(int ch
) {
42 return colourCodeTable
[ch
]->allocated
;
44 for (int i
=0; i
<nColours
; i
++) {
46 return colours
[i
].allocated
;
49 return colours
[0].allocated
;
53 void XPM::FillRun(Surface
*surface
, int code
, int startX
, int y
, int x
) {
54 if ((code
!= codeTransparent
) && (startX
!= x
)) {
55 PRectangle
rc(startX
, y
, x
, y
+1);
56 surface
->FillRectangle(rc
, ColourFromCode(code
));
60 XPM::XPM(const char *textForm
) :
61 data(0), codes(0), colours(0), lines(0) {
65 XPM::XPM(const char * const *linesForm
) :
66 data(0), codes(0), colours(0), lines(0) {
74 void XPM::Init(const char *textForm
) {
76 // Test done is two parts to avoid possibility of overstepping the memory
77 // if memcmp implemented strangely. Must be 4 bytes at least at destination.
78 if ((0 == memcmp(textForm
, "/* X", 4)) && (0 == memcmp(textForm
, "/* XPM */", 9))) {
79 // Build the lines form out of the text form
80 const char **linesForm
= LinesFormFromTextForm(textForm
);
86 // It is really in line form
87 Init(reinterpret_cast<const char * const *>(textForm
));
91 void XPM::Init(const char * const *linesForm
) {
97 codeTransparent
= ' ';
104 const char *line0
= linesForm
[0];
106 line0
= NextField(line0
);
107 height
= atoi(line0
);
108 line0
= NextField(line0
);
109 nColours
= atoi(line0
);
110 line0
= NextField(line0
);
111 if (atoi(line0
) != 1) {
112 // Only one char per pixel is supported
115 codes
= new char[nColours
];
116 colours
= new ColourPair
[nColours
];
118 int strings
= 1+height
+nColours
;
119 lines
= new char *[strings
];
120 size_t allocation
= 0;
121 for (int i
=0; i
<strings
; i
++) {
122 allocation
+= MeasureLength(linesForm
[i
]) + 1;
124 data
= new char[allocation
];
125 char *nextBit
= data
;
126 for (int j
=0; j
<strings
; j
++) {
128 size_t len
= MeasureLength(linesForm
[j
]);
129 memcpy(nextBit
, linesForm
[j
], len
);
134 for (int code
=0; code
<256; code
++) {
135 colourCodeTable
[code
] = 0;
138 for (int c
=0; c
<nColours
; c
++) {
139 const char *colourDef
= linesForm
[c
+1];
140 codes
[c
] = colourDef
[0];
142 if (*colourDef
== '#') {
143 colours
[c
].desired
.Set(colourDef
);
145 colours
[c
].desired
= ColourDesired(0xff, 0xff, 0xff);
146 codeTransparent
= codes
[c
];
148 colourCodeTable
[static_cast<unsigned char>(codes
[c
])] = &(colours
[c
]);
163 void XPM::RefreshColourPalette(Palette
&pal
, bool want
) {
164 if (!data
|| !codes
|| !colours
|| !lines
) {
167 for (int i
=0; i
<nColours
; i
++) {
168 pal
.WantFind(colours
[i
], want
);
172 void XPM::CopyDesiredColours() {
173 if (!data
|| !codes
|| !colours
|| !lines
) {
176 for (int i
=0; i
<nColours
; i
++) {
181 void XPM::Draw(Surface
*surface
, PRectangle
&rc
) {
182 if (!data
|| !codes
|| !colours
|| !lines
) {
186 int startY
= rc
.top
+ (rc
.Height() - height
) / 2;
187 int startX
= rc
.left
+ (rc
.Width() - width
) / 2;
188 for (int y
=0;y
<height
;y
++) {
191 for (int x
=0; x
<width
; x
++) {
192 int code
= lines
[y
+nColours
+1][x
];
193 if (code
!= prevCode
) {
194 FillRun(surface
, prevCode
, startX
+ xStartRun
, startY
+ y
, startX
+ x
);
199 FillRun(surface
, prevCode
, startX
+ xStartRun
, startY
+ y
, startX
+ width
);
203 const char **XPM::LinesFormFromTextForm(const char *textForm
) {
204 // Build the lines form out of the text form
205 const char **linesForm
= 0;
209 for (; countQuotes
< (2*strings
) && textForm
[j
] != '\0'; j
++) {
210 if (textForm
[j
] == '\"') {
211 if (countQuotes
== 0) {
212 // First field: width, height, number of colors, chars per pixel
213 const char *line0
= textForm
+ j
+ 1;
215 line0
= NextField(line0
);
216 // Add 1 line for each pixel of height
217 strings
+= atoi(line0
);
218 line0
= NextField(line0
);
219 // Add 1 line for each colour
220 strings
+= atoi(line0
);
221 linesForm
= new const char *[strings
];
222 if (linesForm
== 0) {
223 break; // Memory error!
226 if (countQuotes
/ 2 >= strings
) {
227 break; // Bad height or number of colors!
229 if ((countQuotes
& 1) == 0) {
230 linesForm
[countQuotes
/ 2] = textForm
+ j
+ 1;
235 if (textForm
[j
] == '\0' || countQuotes
/ 2 > strings
) {
236 // Malformed XPM! Height + number of colors too high or too low
243 // In future, may want to minimize search time by sorting and using a binary search.
245 XPMSet::XPMSet() : set(0), len(0), maximum(0), height(-1), width(-1) {
252 void XPMSet::Clear() {
253 for (int i
= 0; i
< len
; i
++) {
264 void XPMSet::Add(int id
, const char *textForm
) {
265 // Invalidate cached dimensions
269 // Replace if this id already present
270 for (int i
= 0; i
< len
; i
++) {
271 if (set
[i
]->GetId() == id
) {
272 set
[i
]->Init(textForm
);
273 set
[i
]->CopyDesiredColours();
278 // Not present, so add to end
279 XPM
*pxpm
= new XPM(textForm
);
282 pxpm
->CopyDesiredColours();
283 if (len
== maximum
) {
285 XPM
**setNew
= new XPM
*[maximum
];
286 for (int i
= 0; i
< len
; i
++) {
297 XPM
*XPMSet::Get(int id
) {
298 for (int i
= 0; i
< len
; i
++) {
299 if (set
[i
]->GetId() == id
) {
306 int XPMSet::GetHeight() {
308 for (int i
= 0; i
< len
; i
++) {
309 if (height
< set
[i
]->GetHeight()) {
310 height
= set
[i
]->GetHeight();
314 return (height
> 0) ? height
: 0;
317 int XPMSet::GetWidth() {
319 for (int i
= 0; i
< len
; i
++) {
320 if (width
< set
[i
]->GetWidth()) {
321 width
= set
[i
]->GetWidth();
325 return (width
> 0) ? width
: 0;