1
|
#include "IconDes.h"
|
2
|
|
3
|
NAMESPACE_UPP
|
4
|
|
5
|
static String sFormatImageName(const String& name, const Image& img, bool exp)
|
6
|
{
|
7
|
Size sz = img.GetSize();
|
8
|
String r;
|
9
|
r << name << " (" << sz.cx << " x " << sz.cy << ')';
|
10
|
if(exp)
|
11
|
r << " ex.";
|
12
|
return r;
|
13
|
}
|
14
|
|
15
|
void IconDes::SyncList()
|
16
|
{
|
17
|
int a = list.GetCursorSc();
|
18
|
int ii = list.GetCursor();
|
19
|
list.Clear();
|
20
|
for(int i = 0; i < slot.GetCount(); i++) {
|
21
|
Slot& c = slot[i];
|
22
|
list.Add(sFormatImageName(c.name, c.image, c.exp), c.image);
|
23
|
}
|
24
|
if(ii >= 0) {
|
25
|
list.SetCursor(ii);
|
26
|
list.ScCursor(a);
|
27
|
}
|
28
|
}
|
29
|
|
30
|
static int sCharFilterCid(int c)
|
31
|
{
|
32
|
return IsAlNum(c) || c == '_' ? c : 0;
|
33
|
}
|
34
|
|
35
|
void IconDes::PlaceDlg(TopWindow& dlg)
|
36
|
{
|
37
|
Rect r = list.GetScreenRect();
|
38
|
Size sz = dlg.GetSize();
|
39
|
dlg.NoCenter().SetRect(max(0, r.left + (r.Width() - sz.cx) / 2), r.bottom + 32, sz.cx, sz.cy);
|
40
|
}
|
41
|
|
42
|
void IconDes::PrepareImageDlg(WithImageLayout<TopWindow>& dlg)
|
43
|
{
|
44
|
CtrlLayoutOKCancel(dlg, "New image");
|
45
|
dlg.cx <<= 16;
|
46
|
dlg.cy <<= 16;
|
47
|
if(IsCurrent()) {
|
48
|
Size sz = GetImageSize();
|
49
|
dlg.cx <<= sz.cx;
|
50
|
dlg.cy <<= sz.cy;
|
51
|
}
|
52
|
dlg.name.SetFilter(sCharFilterCid);
|
53
|
}
|
54
|
|
55
|
void IconDes::PrepareImageSizeDlg(WithImageSizeLayout<TopWindow>& dlg)
|
56
|
{
|
57
|
CtrlLayoutOKCancel(dlg, "New image");
|
58
|
dlg.cx <<= 16;
|
59
|
dlg.cy <<= 16;
|
60
|
if(IsCurrent()) {
|
61
|
Size sz = GetImageSize();
|
62
|
dlg.cx <<= sz.cx;
|
63
|
dlg.cy <<= sz.cy;
|
64
|
}
|
65
|
}
|
66
|
|
67
|
bool CheckName(WithImageLayout<TopWindow>& dlg)
|
68
|
{
|
69
|
String n = dlg.name;
|
70
|
CParser p(n);
|
71
|
if(p.IsId()) return true;
|
72
|
Exclamation("Invalid name!");
|
73
|
return false;
|
74
|
}
|
75
|
|
76
|
void IconDes::InsertRemoved(int q)
|
77
|
{
|
78
|
if(q >= 0 && q < removed.GetCount()) {
|
79
|
int ii = list.IsCursor() ? list.GetCursor() : 0;
|
80
|
slot.Insert(ii) = removed[q];
|
81
|
removed.Remove(q);
|
82
|
SyncList();
|
83
|
list.SetCursor(ii);
|
84
|
}
|
85
|
}
|
86
|
|
87
|
void IconDes::ImageInsert(const String& name, const Image& m, bool exp)
|
88
|
{
|
89
|
int ii = list.IsCursor() ? list.GetCursor() : 0;
|
90
|
if(ii == list.GetCount() - 1)
|
91
|
ii = list.GetCount();
|
92
|
Slot& c = slot.Insert(ii);
|
93
|
c.name = name;
|
94
|
c.image = m;
|
95
|
c.exp = exp;
|
96
|
SyncList();
|
97
|
list.SetCursor(ii);
|
98
|
}
|
99
|
|
100
|
void IconDes::InsertImage()
|
101
|
{
|
102
|
WithImageLayout<TopWindow> dlg;
|
103
|
PrepareImageDlg(dlg);
|
104
|
do {
|
105
|
if(dlg.Run() != IDOK)
|
106
|
return;
|
107
|
}
|
108
|
while(!CheckName(dlg));
|
109
|
ImageInsert(~dlg.name, CreateImage(Size(~dlg.cx, ~dlg.cy), Null), dlg.exp);
|
110
|
}
|
111
|
|
112
|
void IconDes::Duplicate()
|
113
|
{
|
114
|
if(!IsCurrent())
|
115
|
return;
|
116
|
Slot& c = Current();
|
117
|
ImageInsert(c.name, c.image);
|
118
|
EditImage();
|
119
|
}
|
120
|
|
121
|
void IconDes::InsertPaste()
|
122
|
{
|
123
|
Image m = ReadClipboardImage();
|
124
|
if(IsNull(m)) {
|
125
|
Exclamation("Clipboard does not contain an image.");
|
126
|
return;
|
127
|
}
|
128
|
ImageInsert("", m);
|
129
|
EditImage();
|
130
|
}
|
131
|
|
132
|
struct FileImage : ImageMaker {
|
133
|
String filename;
|
134
|
Size size;
|
135
|
|
136
|
virtual String Key() const { return filename + '/' + AsString(size); }
|
137
|
virtual Image Make() const {
|
138
|
if(GetFileLength(filename) > 1024 * 1024 * 20)
|
139
|
return Null;
|
140
|
Image m = StreamRaster::LoadFileAny(filename);
|
141
|
Size sz = m.GetSize();
|
142
|
if(sz.cx > size.cx || sz.cy > size.cy) {
|
143
|
if(sz.cx * size.cy > sz.cy * size.cx)
|
144
|
sz = GetRatioSize(sz, size.cx, 0);
|
145
|
else
|
146
|
sz = GetRatioSize(sz, 0, size.cy);
|
147
|
return Rescale(m, sz);
|
148
|
}
|
149
|
return m;
|
150
|
}
|
151
|
};
|
152
|
|
153
|
struct ImgPreview : Display {
|
154
|
virtual void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const {
|
155
|
if(!IsNull(q)) {
|
156
|
FileImage im;
|
157
|
im.size = r.GetSize();
|
158
|
im.filename = q;
|
159
|
w.DrawRect(r, SColorPaper);
|
160
|
Image m = MakeImage(im);
|
161
|
Point p = r.CenterPos(m.GetSize());
|
162
|
w.DrawImage(p.x, p.y, m);
|
163
|
}
|
164
|
}
|
165
|
};
|
166
|
|
167
|
FileSel& IconDes::ImgFile()
|
168
|
{
|
169
|
static FileSel sel;
|
170
|
ONCELOCK {
|
171
|
sel.Type("Image files", "*.png *.bmp *.jpg *.jpeg *.gif");
|
172
|
sel.AllFilesType();
|
173
|
sel.Multi();
|
174
|
sel.Preview(Single<ImgPreview>());
|
175
|
}
|
176
|
return sel;
|
177
|
}
|
178
|
|
179
|
int CharFilterImageId(int c)
|
180
|
{
|
181
|
return IsAlNum(c) ? c : '_';
|
182
|
}
|
183
|
|
184
|
void IconDes::InsertFile()
|
185
|
{
|
186
|
if(!ImgFile().ExecuteOpen()) return;
|
187
|
for(int i = 0; i < ImgFile().GetCount(); i++) {
|
188
|
String fn = ImgFile()[i];
|
189
|
Image m = StreamRaster::LoadFileAny(fn);
|
190
|
if(IsNull(m))
|
191
|
Exclamation(DeQtf(fn) + " not an image.");
|
192
|
String id = Filter(GetFileTitle(fn), CharFilterImageId);
|
193
|
if(!IsAlpha(*id) && *id != '_')
|
194
|
id = '_' + id;
|
195
|
ImageInsert(id, m);
|
196
|
}
|
197
|
}
|
198
|
|
199
|
void IconDes::ExportPngs()
|
200
|
{
|
201
|
String dir = SelectDirectory();
|
202
|
if(!dir.IsEmpty())
|
203
|
for(int i = 0; i < GetCount(); i++)
|
204
|
PNGEncoder().SaveFile(AppendFileName(dir, GetName(i) + ".png"), GetImage(i));
|
205
|
}
|
206
|
|
207
|
void IconDes::InsertIml()
|
208
|
{
|
209
|
Array<ImlImage> m;
|
210
|
int f;
|
211
|
if(LoadIml(SelectLoadFile("Iml files\t*.iml"), m, f))
|
212
|
for(int i = 0; i < m.GetCount(); i++) {
|
213
|
ImageInsert(m[i].name, m[i].image, m[i].exp);
|
214
|
list.SetCursor(list.GetCursor() + 1);
|
215
|
}
|
216
|
}
|
217
|
|
218
|
void IconDes::ListCursor()
|
219
|
{
|
220
|
SyncImage();
|
221
|
}
|
222
|
|
223
|
void IconDes::EditImageSize()
|
224
|
{
|
225
|
Slot& c = Current();
|
226
|
WithImageSizeLayout<TopWindow> dlg;
|
227
|
PrepareImageSizeDlg(dlg);
|
228
|
dlg.Breaker(dlg.cx);
|
229
|
dlg.Breaker(dlg.cy);
|
230
|
Image img = c.image;
|
231
|
dlg.cx <<= img.GetWidth();
|
232
|
dlg.cy <<= img.GetHeight();
|
233
|
for(;;) {
|
234
|
switch(dlg.Run()) {
|
235
|
case IDCANCEL:
|
236
|
c.image = img;
|
237
|
Reset();
|
238
|
return;
|
239
|
case IDOK:
|
240
|
Reset();
|
241
|
return;
|
242
|
}
|
243
|
c.image = CreateImage(Size(minmax((int)~dlg.cx, 1, 8192), minmax((int)~dlg.cy, 1, 8192)), Null);
|
244
|
UPP::Copy(c.image, Point(0, 0), img, img.GetSize());
|
245
|
Reset();
|
246
|
}
|
247
|
}
|
248
|
|
249
|
void IconDes::EditImage()
|
250
|
{
|
251
|
if(!IsCurrent())
|
252
|
return;
|
253
|
if(single_mode) {
|
254
|
EditImageSize();
|
255
|
return;
|
256
|
}
|
257
|
Slot& c = Current();
|
258
|
WithImageLayout<TopWindow> dlg;
|
259
|
PrepareImageDlg(dlg);
|
260
|
dlg.Breaker(dlg.cx);
|
261
|
dlg.Breaker(dlg.cy);
|
262
|
Image img = c.image;
|
263
|
dlg.cx <<= img.GetWidth();
|
264
|
dlg.cy <<= img.GetHeight();
|
265
|
dlg.name <<= c.name;
|
266
|
dlg.exp <<= c.exp;
|
267
|
for(;;) {
|
268
|
switch(dlg.Run()) {
|
269
|
case IDCANCEL:
|
270
|
c.image = img;
|
271
|
Reset();
|
272
|
return;
|
273
|
case IDOK:
|
274
|
if(!CheckName(dlg)) break;
|
275
|
c.name = ~dlg.name;
|
276
|
c.exp = ~dlg.exp;
|
277
|
list.Set(0, sFormatImageName(c.name, c.image, c.exp));
|
278
|
Reset();
|
279
|
return;
|
280
|
}
|
281
|
c.image = CreateImage(Size(minmax((int)~dlg.cx, 1, 8192), minmax((int)~dlg.cy, 1, 8192)), Null);
|
282
|
UPP::Copy(c.image, Point(0, 0), img, img.GetSize());
|
283
|
Reset();
|
284
|
}
|
285
|
}
|
286
|
|
287
|
void IconDes::RemoveImage()
|
288
|
{
|
289
|
if(!IsCurrent() || !PromptYesNo("Remove current image?"))
|
290
|
return;
|
291
|
int ii = list.GetCursor();
|
292
|
while(removed.GetCount() > 12)
|
293
|
removed.Remove(0);
|
294
|
Slot& r = removed.Add();
|
295
|
r = slot[ii];
|
296
|
if(r.image.GetWidth() <= 128 && r.image.GetHeight() <= 128)
|
297
|
r.base_image = Rescale(r.image, Size(16, 16));
|
298
|
else
|
299
|
r.base_image = IconDesImg::LargeImage();
|
300
|
slot.Remove(ii);
|
301
|
list.KillCursor();
|
302
|
SyncList();
|
303
|
if(ii < slot.GetCount())
|
304
|
list.SetCursor(ii);
|
305
|
else
|
306
|
list.GoEnd();
|
307
|
}
|
308
|
|
309
|
void IconDes::MoveSlot(int d)
|
310
|
{
|
311
|
if(!IsCurrent())
|
312
|
return;
|
313
|
int c = list.GetCursor();
|
314
|
d = c + d;
|
315
|
if(d >= 0 && d < slot.GetCount()) {
|
316
|
slot.Swap(c, d);
|
317
|
SyncList();
|
318
|
list.SetCursor(d);
|
319
|
}
|
320
|
}
|
321
|
|
322
|
void IconDes::ChangeSlot(int d)
|
323
|
{
|
324
|
if(!IsCurrent())
|
325
|
return;
|
326
|
int c = list.GetCursor();
|
327
|
d = c + d;
|
328
|
if(d >= 0 && d < slot.GetCount())
|
329
|
list.SetCursor(d);
|
330
|
}
|
331
|
|
332
|
void IconDes::ListMenu(Bar& bar)
|
333
|
{
|
334
|
using namespace IconDesKeys;
|
335
|
if(single_mode)
|
336
|
bar.Add(IsCurrent(), AK_RESIZE_SINGLE, IconDesImg::Edit(), THISBACK(EditImage));
|
337
|
else {
|
338
|
bar.Add(AK_INSERT_IMAGE, IconDesImg::Insert(), THISBACK(InsertImage));
|
339
|
bar.Add(IsCurrent(), AK_IMAGE, IconDesImg::Edit(), THISBACK(EditImage));
|
340
|
bar.Add(IsCurrent(), AK_REMOVE_IMAGE, IconDesImg::Remove(), THISBACK(RemoveImage));
|
341
|
bar.Add(IsCurrent(), AK_DUPLICATE, IconDesImg::Duplicate(), THISBACK(Duplicate));
|
342
|
bar.Add(AK_INSERT_CLIP, IconDesImg::InsertPaste(), THISBACK(InsertPaste));
|
343
|
bar.Add(AK_INSERT_FILE, IconDesImg::InsertFile(), THISBACK(InsertFile));
|
344
|
bar.Add(AK_INSERT_IML, IconDesImg::InsertIml(), THISBACK(InsertIml));
|
345
|
bar.Add(AK_EXPORT_PNGS, IconDesImg::ExportPngs(), THISBACK(ExportPngs));
|
346
|
bar.Separator();
|
347
|
bar.Add(IsCurrent() && list.GetCursor() > 0, AK_MOVE_UP, IconDesImg::MoveUp(),
|
348
|
THISBACK1(MoveSlot, -1));
|
349
|
bar.Add(IsCurrent() && list.GetCursor() < slot.GetCount() - 1, AK_MOVE_DOWN, IconDesImg::MoveDown(),
|
350
|
THISBACK1(MoveSlot, 1));
|
351
|
if(removed.GetCount()) {
|
352
|
bar.Separator();
|
353
|
for(int i = removed.GetCount() - 1; i >= 0; i--) {
|
354
|
Slot& r = removed[i];
|
355
|
bar.Add("Insert " + sFormatImageName(r.name, r.image, r.exp), r.base_image,
|
356
|
THISBACK1(InsertRemoved, i));
|
357
|
}
|
358
|
}
|
359
|
}
|
360
|
bar.Separator();
|
361
|
EditBar(bar);
|
362
|
ListMenuEx(bar);
|
363
|
}
|
364
|
|
365
|
void IconDes::ListMenuEx(Bar& bar) {}
|
366
|
|
367
|
|
368
|
void IconDes::Clear()
|
369
|
{
|
370
|
list.Clear();
|
371
|
slot.Clear();
|
372
|
Reset();
|
373
|
}
|
374
|
|
375
|
void IconDes::AddImage(const String& name, const Image& image, bool exp)
|
376
|
{
|
377
|
Slot& c = slot.Add();
|
378
|
c.name = name;
|
379
|
c.image = image;
|
380
|
c.exp = exp;
|
381
|
list.Add(sFormatImageName(c.name, c.image, c.exp), c.image);
|
382
|
list.GoBegin();
|
383
|
}
|
384
|
|
385
|
int IconDes::GetCount() const
|
386
|
{
|
387
|
return slot.GetCount();
|
388
|
}
|
389
|
|
390
|
Image IconDes::GetImage(int ii) const
|
391
|
{
|
392
|
const Slot& c = slot[ii];
|
393
|
Image m = slot[ii].image;
|
394
|
return c.supersampling ? DownSample3x(m) : m;
|
395
|
}
|
396
|
|
397
|
String IconDes::GetName(int ii) const
|
398
|
{
|
399
|
return slot[ii].name;
|
400
|
}
|
401
|
|
402
|
String IconDes::GetCurrentName() const
|
403
|
{
|
404
|
if(list.IsCursor())
|
405
|
return slot[list.GetCursor()].name;
|
406
|
return String();
|
407
|
}
|
408
|
|
409
|
bool IconDes::GetExport(int ii) const
|
410
|
{
|
411
|
return slot[ii].exp;
|
412
|
}
|
413
|
|
414
|
END_UPP_NAMESPACE
|