Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
306 andreas 1
/*
2
 * Copyright (C) 2023 by Andreas Theofilu <andreas@theosys.at>
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
#include <string>
19
#include <vector>
20
 
21
#include <include/core/SkImage.h>
22
#include <include/core/SkCanvas.h>
23
#include <include/core/SkPixmap.h>
24
#include <include/core/SkBitmap.h>
25
#include <include/core/SkSize.h>
26
#include <include/core/SkColor.h>
27
#include <include/core/SkSurfaceProps.h>
28
#include <include/core/SkRRect.h>
29
 
30
#include "tintborder.h"
31
#include "tcolor.h"
32
#include "tresources.h"
33
#include "terror.h"
34
 
35
using namespace Border;
36
using std::string;
37
using std::vector;
38
 
39
/**
40
 * The following table defines some of the system borders. It is mostly a
41
 * fallback table but defines whether a border should be calculated internaly
42
 * or constructed out of the images in the system border folder. The later is
43
 * only possible if this folder exist and contains the system images from AMX.
44
 * This images could be retrieved by sending a full surface with the system
45
 * files included from TPDesign4.
46
 * All borders not listed in this table are constructed out of the system
47
 * border images, if they exist.
48
 */
49
SYSBORDER_t sysBorders[] = {
50
//   ID   Name                  AMX number  Style          width radius calc
51
    {  1, (char *)"Single Line",         0, (char *)"solid",   1,   0, true },
52
    {  2, (char *)"Double Line",         0, (char *)"solid",   2,   0, true },
53
    {  3, (char *)"Quad Line",           0, (char *)"solid",   4,   0, true },
54
    {  4, (char *)"Picture Frame",       0, (char *)"double",  0,   0, false },
55
    {  5, (char *)"Circle 15",           8, (char *)"solid",   2,   7, true },
56
    {  6, (char *)"Circle 25",           9, (char *)"solid",   2,  14, true },
57
    {  7, (char *)"Circle 35",          10, (char *)"solid",   2,  21, true },
58
    {  8, (char *)"Circle 45",          11, (char *)"solid",   2,  28, true },
59
    {  9, (char *)"Circle 55",          12, (char *)"solid",   2,  35, true },
60
    { 10, (char *)"Circle 65",          13, (char *)"solid",   2,  42, true },
61
    { 11, (char *)"Circle 75",          14, (char *)"solid",   2,  49, true },
62
    { 12, (char *)"Circle 85",          15, (char *)"solid",   2,  56, true },
63
    { 13, (char *)"Circle 95",          16, (char *)"solid",   2,  63, true },
64
    { 14, (char *)"Circle 105",         17, (char *)"solid",   2,  70, true },
65
    { 15, (char *)"Circle 115",         18, (char *)"solid",   2,  77, true },
66
    { 16, (char *)"Circle 125",         19, (char *)"solid",   2,  84, true },
67
    { 17, (char *)"Circle 135",         20, (char *)"solid",   2,  91, true },
68
    { 18, (char *)"Circle 145",         21, (char *)"solid",   2,  98, true },
69
    { 19, (char *)"Circle 155",         22, (char *)"solid",   2, 105, true },
70
    { 20, (char *)"Circle 165",         23, (char *)"solid",   2, 112, true },
71
    { 21, (char *)"Circle 175",         24, (char *)"solid",   2, 119, true },
72
    { 22, (char *)"Circle 185",         25, (char *)"solid",   2, 126, true },
73
    { 23, (char *)"Circle 195",         26, (char *)"solid",   2, 133, true },
74
    { 24, (char *)"AMX Elite Inset -L",  0, (char *)"groove", 20,   0, false },
75
    { 25, (char *)"AMX Elite Raised -L", 0, (char *)"ridge",  20,   0, false },
76
    { 26, (char *)"AMX Elite Inset -M",  0, (char *)"groove", 10,   0, false },
77
    { 27, (char *)"AMX Elite Raised -M", 0, (char *)"ridge",  10,   0, false },
78
    { 28, (char *)"AMX Elite Inset -S",  0, (char *)"groove",  4,   0, false },
79
    { 29, (char *)"AMX Elite Raised -S", 0, (char *)"ridge",   4,   0, false },
80
    { 30, (char *)"Bevel Inset -L",      0, (char *)"inset",  20,   0, false },
81
    { 31, (char *)"Bevel Raised -L",     0, (char *)"outset", 20,   0, false },
82
    { 32, (char *)"Bevel Inset -M",      0, (char *)"inset",  10,   0, false },
83
    { 33, (char *)"Bevel Raised -M",     0, (char *)"outset", 10,   0, false },
84
    { 34, (char *)"Bevel Inset -S",      0, (char *)"inset",   4,   0, false },
85
    { 35, (char *)"Bevel Raised -S",     0, (char *)"outset",  4,   0, false },
86
    {  0, nullptr, 0, nullptr, 0, 0 }
87
};
88
 
336 andreas 89
TP4BORDERS_t tp4Borders[] = {
90
    { 0, "None", {0, 0, 0, 0} },
91
    { 1, "None", {0, 0, 0, 0} },
92
    { 2, "AMX Elite -L", {0, 0, 0, 0} },
93
    { 3, "AMX Elite -M", {0, 0, 0, 0} },
94
    { 4, "AMX Elite -S", {0, 0, 0, 0} },
95
    { 5, "Bevel -L", {0, 0, 0, 0} },
96
    { 6, "Bevel -M", {21, 0, 0, 0} },
97
    { 7, "Bevel -S", {20, 0, 0, 0} },
98
    { 8, "Circle 15", {5, 22, 0, 0} },
99
    { 9, "Circle 25", {6, 23, 0, 0} },
100
    { 10, "Circle 35", {0, 0, 0, 0} },
101
    { 11, "Circle 45", {0, 0, 0, 0} },
102
    { 12, "Circle 55", {0, 0, 0, 0} },
103
    { 13, "Circle 65", {0, 0, 0, 0} },
104
    { 14, "Circle 75", {0, 0, 0, 0} },
105
    { 15, "Circle 85", {0, 0, 0, 0} },
106
    { 16, "Circle 95", {0, 0, 0, 0} },
107
    { 17, "Circle 105", {0, 0, 0, 0} },
108
    { 18, "Circle 115", {0, 0, 0, 0} },
109
    { 19, "Circle 125", {0, 0, 0, 0} },
110
    { 20, "Circle 135", {0, 0, 0, 0} },
111
    { 21, "Circle 145", {0, 0, 0, 0} },
112
    { 22, "Circle 155", {0, 0, 0, 0} },
113
    { 23, "Circle 165", {0, 0, 0, 0} },
114
    { 24, "Circle 175", {0, 0, 0, 0} },
115
    { 25, "Circle 185", {0, 0, 0, 0} },
116
    { 26, "Circle 195", {0, 0, 0, 0} },
117
    { 27, "Cursor Bottom", {0, 0, 0, 0} },
118
    { 28, "Cursor Bottom with Hole", {0, 0, 0, 0} },
119
    { 29, "Cursor Top", {0, 0, 0, 0} },
120
    { 30, "Cursor Top with Hole", {0, 0, 0, 0} },
121
    { 31, "Cursor Left", {0, 0, 0, 0} },
122
    { 32, "Cursor Left with Hole", {0, 0, 0, 0} },
123
    { 33, "Cursor Right", {0, 0, 0, 0} },
124
    { 34, "Cursor Right with Hole", {0, 0, 0, 0} },
125
    { 35, "Custom Frame", {0, 0, 0, 0} },
126
    { 36, "Diamond 15", {0, 0, 0, 0} },
127
    { 37, "Diamond 25", {0, 0, 0, 0} },
128
    { 38, "Diamond 35", {0, 0, 0, 0} },
129
    { 39, "Diamond 45", {0, 0, 0, 0} },
130
    { 40, "Diamond 55", {40, 0, 0, 0} },
131
    { 41, "Diamond 65", {41, 0, 0, 0} },
132
    { 42, "Diamond 75", {0, 0, 0, 0} },
133
    { 43, "Diamond 85", {0, 0, 0, 0} },
134
    { 44, "Diamond 95", {0, 0, 0, 0} },
135
    { 45, "Diamond 105", {0, 0, 0, 0} },
136
    { 46, "Diamond 115", {0, 0, 0, 0} },
137
    { 47, "Diamond 125", {0, 0, 0, 0} },
138
    { 48, "Diamond 135", {0, 0, 0, 0} },
139
    { 49, "Diamond 145", {0, 0, 0, 0} },
140
    { 50, "Diamond 155", {0, 0, 0, 0} },
141
    { 51, "Diamond 165", {0, 0, 0, 0} },
142
    { 52, "Diamond 175", {0, 0, 0, 0} },
143
    { 53, "Diamond 185", {0, 0, 0, 0} },
144
    { 54, "Diamond 195", {0, 0, 0, 0} },
145
    { 55, "Double Bevel -L", {0, 0, 0, 0} },
146
    { 56, "Double Bevel -M", {0, 0, 0, 0} },
147
    { 57, "Double Bevel -S", {0, 0, 0, 0} },
148
    { 58, "Double Line", {3, 8, 12, 0} },
149
    { 59, "Fuzzy", {0, 0, 0, 0} },
150
    { 60, "Glow-L", {0, 0, 0, 0} },
151
    { 61, "Glow-S", {0, 0, 0, 0} },
152
    { 62, "Help Down", {0, 0, 0, 0} },
153
    { 63, "Neon Active -L", {27, 0, 0, 0} },
154
    { 64, "Neon Active -S", {26, 0, 0, 0} },
155
    { 65, "Neon Inactive -L", {25, 0, 0, 0} },
156
    { 66, "Neon Inactive -S", {24, 0, 0, 0} },
157
    { 67, "Oval H 60x30", {0, 0, 0, 0} },
158
    { 68, "Oval H 100x50", {0, 0, 0, 0} },
159
    { 69, "Oval H 150x75", {0, 0, 0, 0} },
160
    { 70, "Oval H 200x100", {0, 0, 0, 0} },
161
    { 71, "Oval V 30x60", {0, 0, 0, 0} },
162
    { 72, "Oval V 50x100", {0, 0, 0, 0} },
163
    { 73, "Oval V 75x150", {0, 0, 0, 0} },
164
    { 74, "Oval V 100x200", {0, 0, 0, 0} },
165
    { 75, "Picture Frame", {10, 11, 0, 0} },
166
    { 76, "Quad Line", {4, 9, 0, 0} },
167
    { 77, "Single Line", {2, 7, 0, 0} },
168
    { 78, "Windows Style Popup", {0, 0, 0, 0} },
169
    { 79, "Windows Style Popup (Status Bar)", {0, 0, 0, 0} },
170
    { 80, "Menu Bottom Rounded 15", {0, 0, 0, 0} },
171
    { 81, "Menu Bottom Rounded 25", {0, 0, 0, 0} },
172
    { 82, "Menu Bottom Rounded 35", {0, 0, 0, 0} },
173
    { 83, "Menu Bottom Rounded 45", {0, 0, 0, 0} },
174
    { 84, "Menu Bottom Rounded 55", {0, 0, 0, 0} },
175
    { 85, "Menu Bottom Rounded 65", {0, 0, 0, 0} },
176
    { 86, "Menu Bottom Rounded 75", {0, 0, 0, 0} },
177
    { 87, "Menu Bottom Rounded 85", {0, 0, 0, 0} },
178
    { 88, "Menu Bottom Rounded 95", {0, 0, 0, 0} },
179
    { 89, "Menu Bottom Rounded 105", {0, 0, 0, 0} },
180
    { 90, "Menu Bottom Rounded 115", {0, 0, 0, 0} },
181
    { 91, "Menu Bottom Rounded 125", {0, 0, 0, 0} },
182
    { 92, "Menu Bottom Rounded 135", {0, 0, 0, 0} },
183
    { 93, "Menu Bottom Rounded 145", {0, 0, 0, 0} },
184
    { 94, "Menu Bottom Rounded 155", {0, 0, 0, 0} },
185
    { 95, "Menu Bottom Rounded 165", {0, 0, 0, 0} },
186
    { 96, "Menu Bottom Rounded 175", {0, 0, 0, 0} },
187
    { 97, "Menu Bottom Rounded 185", {0, 0, 0, 0} },
188
    { 98, "Menu Bottom Rounded 195", {0, 0, 0, 0} },
189
    { 99, "Menu Top Rounded 15", {0, 0, 0, 0} },
190
    { 100, "Menu Top Rounded 25", {0, 0, 0, 0} },
191
    { 101, "Menu Top Rounded 35", {0, 0, 0, 0} },
192
    { 102, "Menu Top Rounded 45", {0, 0, 0, 0} },
193
    { 103, "Menu Top Rounded 55", {0, 0, 0, 0} },
194
    { 104, "Menu Top Rounded 65", {0, 0, 0, 0} },
195
    { 105, "Menu Top Rounded 75", {0, 0, 0, 0} },
196
    { 106, "Menu Top Rounded 85", {0, 0, 0, 0} },
197
    { 107, "Menu Top Rounded 95", {0, 0, 0, 0} },
198
    { 108, "Menu Top Rounded 105", {0, 0, 0, 0} },
199
    { 109, "Menu Top Rounded 115", {0, 0, 0, 0} },
200
    { 110, "Menu Top Rounded 125", {0, 0, 0, 0} },
201
    { 111, "Menu Top Rounded 135", {0, 0, 0, 0} },
202
    { 112, "Menu Top Rounded 145", {0, 0, 0, 0} },
203
    { 113, "Menu Top Rounded 155", {0, 0, 0, 0} },
204
    { 114, "Menu Top Rounded 165", {0, 0, 0, 0} },
205
    { 115, "Menu Top Rounded 175", {0, 0, 0, 0} },
206
    { 116, "Menu Top Rounded 185", {0, 0, 0, 0} },
207
    { 117, "Menu Top Rounded 195", {0, 0, 0, 0} },
208
    { 118, "Menu Right Rounded 15", {0, 0, 0, 0} },
209
    { 119, "Menu Right Rounded 25", {0, 0, 0, 0} },
210
    { 120, "Menu Right Rounded 35", {0, 0, 0, 0} },
211
    { 121, "Menu Right Rounded 45", {0, 0, 0, 0} },
212
    { 122, "Menu Right Rounded 55", {0, 0, 0, 0} },
213
    { 123, "Menu Right Rounded 65", {0, 0, 0, 0} },
214
    { 124, "Menu Right Rounded 75", {0, 0, 0, 0} },
215
    { 125, "Menu Right Rounded 85", {0, 0, 0, 0} },
216
    { 126, "Menu Right Rounded 95", {0, 0, 0, 0} },
217
    { 127, "Menu Right Rounded 105", {0, 0, 0, 0} },
218
    { 128, "Menu Right Rounded 115", {0, 0, 0, 0} },
219
    { 129, "Menu Right Rounded 125", {0, 0, 0, 0} },
220
    { 130, "Menu Right Rounded 135", {0, 0, 0, 0} },
221
    { 131, "Menu Right Rounded 145", {0, 0, 0, 0} },
222
    { 132, "Menu Right Rounded 155", {0, 0, 0, 0} },
223
    { 133, "Menu Right Rounded 165", {0, 0, 0, 0} },
224
    { 134, "Menu Right Rounded 175", {0, 0, 0, 0} },
225
    { 135, "Menu Right Rounded 185", {0, 0, 0, 0} },
226
    { 136, "Menu Right Rounded 195", {0, 0, 0, 0} },
227
    { 137, "Menu Left Rounded 15", {0, 0, 0, 0} },
228
    { 138, "Menu Left Rounded 25", {0, 0, 0, 0} },
229
    { 139, "Menu Left Rounded 35", {0, 0, 0, 0} },
230
    { 140, "Menu Left Rounded 45", {0, 0, 0, 0} },
231
    { 141, "Menu Left Rounded 55", {0, 0, 0, 0} },
232
    { 142, "Menu Left Rounded 65", {0, 0, 0, 0} },
233
    { 143, "Menu Left Rounded 75", {0, 0, 0, 0} },
234
    { 144, "Menu Left Rounded 85", {0, 0, 0, 0} },
235
    { 145, "Menu Left Rounded 95", {0, 0, 0, 0} },
236
    { 146, "Menu Left Rounded 105", {0, 0, 0, 0} },
237
    { 147, "Menu Left Rounded 115", {0, 0, 0, 0} },
238
    { 148, "Menu Left Rounded 125", {0, 0, 0, 0} },
239
    { 149, "Menu Left Rounded 135", {0, 0, 0, 0} },
240
    { 150, "Menu Left Rounded 145", {0, 0, 0, 0} },
241
    { 151, "Menu Left Rounded 155", {0, 0, 0, 0} },
242
    { 152, "Menu Left Rounded 165", {0, 0, 0, 0} },
243
    { 153, "Menu Left Rounded 175", {0, 0, 0, 0} },
244
    { 154, "Menu Left Rounded 185", {0, 0, 0, 0} },
245
    { 155, "Menu Left Rounded 195", {0, 0, 0, 0} },
246
    { -1, "", {0, 0, 0, 0}}
247
};
248
 
306 andreas 249
TIntBorder::TIntBorder()
250
{
251
    DECL_TRACER("TIntBorder::TIntBorder()");
252
}
253
 
254
bool TIntBorder::drawBorder(SkBitmap* bm, const string& bname, int wt, int ht, const string& cb, bool force)
255
{
256
    DECL_TRACER("TIntBorder::drawBorder(SkBitmap* bm, string& bname, int wt, int ht, string& cb, bool force)");
257
 
258
    if (!bm || wt <= 0 || ht <= 0)
259
        return false;
260
 
261
    if (bname.empty())
262
    {
263
        MSG_DEBUG("No border name defined.");
264
        return false;
265
    }
266
 
267
    // Try to find the border in the system table
268
    int borderIndex = -1;
269
    int i = 0;
270
 
271
    while (sysBorders[i].id)
272
    {
308 andreas 273
        if (strCaseCompare(bname, sysBorders[i].name) == 0)
306 andreas 274
        {
275
            if (!force && !sysBorders[i].calc)
307 andreas 276
            {
277
                MSG_DEBUG("Ignoring border " << bname << " because it was not forced.");
306 andreas 278
                return false;
307 andreas 279
            }
306 andreas 280
 
281
            borderIndex = i;
282
            MSG_DEBUG("Found internal system border [" << i << "]: " << sysBorders[i].name);
283
            break;
284
        }
285
 
286
        i++;
287
    }
288
 
289
    if (borderIndex < 0)
307 andreas 290
    {
291
        MSG_DEBUG(bname << " is not an internal border.");
306 andreas 292
        return false;
307 andreas 293
    }
306 andreas 294
 
295
    MSG_DEBUG("Border " << sysBorders[borderIndex].name << " found.");
296
    SkCanvas canvas(*bm, SkSurfaceProps());
297
    SkPaint paint;
298
    SkColor color = TColor::getSkiaColor(cb);
299
 
300
    paint.setColor(color);
317 andreas 301
    paint.setBlendMode(SkBlendMode::kSrc);
306 andreas 302
    paint.setStyle(SkPaint::kStroke_Style);
303
    SkRRect outher, inner;
304
    SkScalar radius = (SkScalar)sysBorders[borderIndex].radius;
305
    int red, green, blue;
306
    SkColor borderColor, bcLight, bcDark;
307
    int lineWidth = 0;
308
 
309
    switch (sysBorders[borderIndex].id)
310
    {
311
        case 1: // Single Frame
312
        case 2: // Double Frame
313
        case 3: // Quad Frame
314
            paint.setStrokeWidth(sysBorders[borderIndex].width);
315
            canvas.drawRect(calcRect(wt, ht, sysBorders[borderIndex].width), paint);
316
        break;
317
 
318
        case 4: // Picture Frame
319
            {
320
                paint.setStrokeWidth(2);
321
                SkRect rect = SkRect::MakeXYWH(0, 0, wt, ht);
322
                canvas.drawRect(rect, paint);
323
                rect = SkRect::MakeXYWH(4, 4, wt - 4, ht - 4);
324
                canvas.drawRect(rect, paint);
325
            }
326
        break;
327
 
328
        case 5: // Circle 15
329
        case 6: // Circle 25
330
        case 7: // Circle 35
331
        case 8: // Circle 45
332
        case 9: // Circle 55
333
        case 10: // Circle 65
334
        case 11: // Circle 75
335
        case 12: // Circle 85
336
        case 13: // Circle 95
337
        case 14: // Circle 105
338
        case 15: // Circle 115
339
        case 16: // Circle 125
340
        case 17: // Circle 135
341
        case 18: // Circle 145
342
        case 19: // Circle 155
343
        case 20: // Circle 165
344
        case 21: // Circle 175
345
        case 22: // Circle 185
346
        case 23: // Circle 195
347
            lineWidth = sysBorders[borderIndex].width;
337 andreas 348
            paint.setStrokeWidth(0.1);
306 andreas 349
            paint.setStyle(SkPaint::kFill_Style);
350
            MSG_DEBUG("Line width: " << lineWidth << ", radius: " << radius);
351
            // We draw a rounded rectangle to "clip" the corners. To do this
352
            // in a way to not miss any pixel, we draw a rectangle followed
353
            // by a rounded rectangle as an inner one. The space between
354
            // them will be filled transparent.
355
            outher = SkRRect::MakeRect({0, 0, (SkScalar)wt, (SkScalar)ht});
356
            inner = SkRRect::MakeRectXY(calcRect(wt, ht, 1), radius, radius);
357
            paint.setColor(SK_ColorTRANSPARENT);
358
            canvas.drawDRRect(outher, inner, paint);
359
            // Here we draw the rounded rectangle.
360
            paint.setStyle(SkPaint::kStroke_Style);
361
            paint.setStrokeWidth(lineWidth);
362
            paint.setColor(color);
363
            paint.setStrokeJoin(SkPaint::kRound_Join);
364
            canvas.drawRoundRect(calcRect(wt, ht, lineWidth), radius, radius, paint);
365
        break;
366
 
367
        case 24:    // AMX Elite Inset -L
368
        case 26:    // AMX Elite Inset -M
369
        case 28:    // AMX Elite Inset -S
370
            {
371
                borderColor = TColor::getSkiaColor(cb);
372
                vector<SkColor> cols = TColor::colorRange(borderColor, sysBorders[borderIndex].width, 40, TColor::DIR_LIGHT_DARK_LIGHT);
373
                vector<SkColor>::iterator iter;
374
                i = 0;
375
 
376
                for (iter = cols.begin(); iter != cols.end(); ++iter)
377
                {
378
                    paint.setStrokeWidth(1);
379
                    paint.setColor(*iter);
380
                    SkRect rect = SkRect::MakeXYWH(i, i, wt - i, ht - i);
381
                    canvas.drawRect(rect, paint);
382
                    i++;
383
                }
384
            }
385
        break;
386
 
387
        case 25:    // AMX Elite Raised -L
388
        case 27:    // AMX Elite Raised -M
389
        case 29:    // AMX Elite Raised -S
390
        {
391
            borderColor = TColor::getSkiaColor(cb);
392
            vector<SkColor> cols = TColor::colorRange(borderColor, sysBorders[borderIndex].width, 40, TColor::DIR_DARK_LIGHT_DARK);
393
            vector<SkColor>::iterator iter;
394
            i = 0;
395
 
396
            for (iter = cols.begin(); iter != cols.end(); ++iter)
397
            {
398
                paint.setStrokeWidth(1);
399
                paint.setColor(*iter);
400
                SkRect rect = SkRect::MakeXYWH(i, i, wt - i, ht - i);
401
                canvas.drawRect(rect, paint);
402
                i++;
403
            }
404
        }
405
        break;
406
 
336 andreas 407
        case 30:    // Bevel Inset -L
306 andreas 408
        case 32:    // Bevel Inset -M
409
        case 34:    // Bevel Inset -S
410
            borderColor = TColor::getSkiaColor(cb);
411
            red = std::min((int)SkColorGetR(borderColor) + 20, 255);
412
            green = std::min((int)SkColorGetG(borderColor) + 20, 255);
413
            blue = std::min((int)SkColorGetB(borderColor) + 20, 255);
414
            bcLight = SkColorSetARGB(SkColorGetA(borderColor), red, green, blue);
415
            red = std::max((int)SkColorGetR(borderColor) - 20, 0);
416
            green = std::max((int)SkColorGetG(borderColor) - 20, 0);
417
            blue = std::max((int)SkColorGetB(borderColor) - 20, 0);
418
            bcDark = SkColorSetARGB(SkColorGetA(borderColor), red, green, blue);
419
            paint.setStrokeWidth(1);
420
            paint.setColor(bcDark);
421
            // Lines on the left
422
            for (i = 0; i < sysBorders[borderIndex].width; i++)
423
            {
424
                int yt = i;
425
                int yb = ht - i;
426
                canvas.drawLine(i, yt, i, yb, paint);
427
            }
428
            // Lines on the top
429
            for (i = 0; i < sysBorders[borderIndex].width; i++)
430
            {
431
                int xl = i;
432
                int xr = wt - i;
433
                canvas.drawLine(xl, i, xr, i, paint);
434
            }
435
            // Lines on right side
436
            paint.setColor(bcLight);
437
 
438
            for (i = 0; i < sysBorders[borderIndex].width; i++)
439
            {
440
                int yt = i;
441
                int yb = ht - i;
442
                canvas.drawLine(wt - i, yt, wt - i, yb, paint);
443
            }
444
            // Lines on bottom
445
            for (i = 0; i < sysBorders[borderIndex].width; i++)
446
            {
447
                int xl = i;
448
                int xr = wt - i;
449
                canvas.drawLine(xl, ht - i, xr, ht - i, paint);
450
            }
451
        break;
452
 
453
        case 31:    // Bevel Raised _L
454
        case 33:    // Bevel Raised _M
455
        case 35:    // Bevel Raised _S
456
            borderColor = TColor::getSkiaColor(cb);
457
            red = std::min((int)SkColorGetR(borderColor) + 10, 255);
458
            green = std::min((int)SkColorGetG(borderColor) + 10, 255);
459
            blue = std::min((int)SkColorGetB(borderColor) + 10, 255);
460
            bcLight = SkColorSetARGB(SkColorGetA(borderColor), red, green, blue);
461
            red = std::max((int)SkColorGetR(borderColor) - 10, 0);
462
            green = std::max((int)SkColorGetG(borderColor) - 10, 0);
463
            blue = std::max((int)SkColorGetB(borderColor) - 10, 0);
464
            bcDark = SkColorSetARGB(SkColorGetA(borderColor), red, green, blue);
465
            paint.setStrokeWidth(1);
466
            paint.setColor(bcLight);
467
            // Lines on the left
468
            for (i = 0; i < sysBorders[borderIndex].width; i++)
469
            {
470
                int yt = i;
471
                int yb = ht - i;
472
                canvas.drawLine(i, yt, i, yb, paint);
473
            }
474
            // Lines on the top
475
            for (i = 0; i < sysBorders[borderIndex].width; i++)
476
            {
477
                int xl = i;
478
                int xr = wt - i;
479
                canvas.drawLine(xl, i, xr, i, paint);
480
            }
481
            // Lines on right side
482
            paint.setColor(bcDark);
483
 
484
            for (i = 0; i < sysBorders[borderIndex].width; i++)
485
            {
486
                int yt = i;
487
                int yb = ht - i;
488
                canvas.drawLine(wt - i, yt, wt - i, yb, paint);
489
            }
490
            // Lines on bottom
491
            for (i = 0; i < sysBorders[borderIndex].width; i++)
492
            {
493
                int xl = i;
494
                int xr = wt - borderIndex;
495
                canvas.drawLine(xl, ht - i, xr, ht - i, paint);
496
            }
497
        break;
498
 
499
        default:
500
            return false;
501
    }
502
 
503
    return true;
504
}
505
 
506
int TIntBorder::getBorderWidth(const string& bname, bool force)
507
{
508
    DECL_TRACER("TIntBorder::getBorderWidth(const string& bname, bool force)");
509
 
510
    for (int i = 0; sysBorders[i].id > 0; ++i)
511
    {
512
        if (strCaseCompare(bname, sysBorders[i].name) == 0)
513
        {
514
            if (!force && !sysBorders[i].calc)
515
                return 0;
516
 
517
            return sysBorders[i].width;
518
        }
519
    }
520
 
521
    return 0;
522
}
523
 
524
bool TIntBorder::borderExist(const string& name)
525
{
526
    DECL_TRACER("TIntBorder::borderExist(const string& name)");
527
 
528
    for (int i = 0; sysBorders[i].id > 0; ++i)
529
    {
530
        if (strCaseCompare(name, sysBorders[i].name) == 0)
531
            return true;
532
    }
533
 
534
    return false;
535
}
536
 
332 andreas 537
bool TIntBorder::borderExist(int index)
538
{
539
    DECL_TRACER("TIntBorder::borderExist(int index)");
540
 
541
    for (int i = 0; sysBorders[i].id > 0; ++i)
542
    {
543
        if (index == sysBorders[i].id)
544
            return true;
545
    }
546
 
547
    return false;
548
}
549
 
550
string TIntBorder::getBorderName(int index)
551
{
552
    DECL_TRACER("TIntBorder::getBorderName(int index)");
553
 
554
    for (int i = 0; sysBorders[i].id > 0; ++i)
555
    {
556
        if (sysBorders[i].id == index)
557
            return sysBorders[i].name;
558
    }
559
 
560
    return string();
561
}
562
 
306 andreas 563
string TIntBorder::getCorrectName(const string& name)
564
{
565
    DECL_TRACER("TIntBorder::getCorrectName(const string& name)");
566
 
567
    for (int i = 0; sysBorders[i].id > 0; ++i)
568
    {
569
        if (strCaseCompare(name, sysBorders[i].name) == 0)
570
            return sysBorders[i].name;
571
    }
572
 
573
    return string();
574
}
575
 
576
bool TIntBorder::isForcedBorder(const string& name)
577
{
578
    DECL_TRACER("TIntBorder::isForcedBorder(const string& name)");
579
 
580
    for (int i = 0; sysBorders[i].id > 0; ++i)
581
    {
582
        if (strCaseCompare(name, sysBorders[i].name) == 0)
583
            return sysBorders[i].calc;
584
    }
585
 
586
    return false;
587
}
588
 
336 andreas 589
bool TIntBorder::isTP4BorderValid(const string &name)
590
{
591
    DECL_TRACER("TIntBorder::isTP4BorderValid(const string &name)");
592
 
593
    if (name.empty())
594
        return false;
595
 
596
    int i = 0;
597
 
598
    while (tp4Borders[i].id >= 0)
599
    {
600
        if (strCaseCompare(tp4Borders[i].name, name) == 0)
601
            return true;
602
 
603
        i++;
604
    }
605
 
606
    return false;
607
}
608
 
609
string TIntBorder::getTP4BorderName(int id)
610
{
611
    DECL_TRACER("TIntBorder::getTP4BorderName(int id)");
612
 
613
    if (id < 1 || id > 41)
614
        return "None";
615
 
616
    int i = 0;
617
 
618
    while (tp4Borders[i].id >= 0)
619
    {
620
        int j = 0;
621
 
622
        while (j < 4)
623
        {
624
            if (tp4Borders[i].prgNum[j] == id)
625
                return tp4Borders[i].name;
626
 
627
            j++;
628
        }
629
 
630
        i++;
631
    }
632
 
633
    return "None";
634
}
635
 
339 andreas 636
/**
637
 * @brief erasePart - Erases the parts of a button who are not coverered by a border.
638
 * The method starts from left, right, top or bottom and erases avery pixel
639
 * who has an alpha value grater 0. It stops if it finds a visible pixel.
640
 * So every pixel outside of the border is removed (transparent).
641
 *
642
 * @param bm        A pointer to a bitmap containing the button image. This
643
 *                  must not be null or empty.
644
 * @param mask      A bitmap containg the border image. This must be of the
645
 *                  same size as \b bm.
646
 * @param ep        The side (left, right, top, bottom, outside) who should be
647
 *                  filtered. The option "outside" filters all four sides.
648
 */
307 andreas 649
void TIntBorder::erasePart(SkBitmap *bm, const SkBitmap& mask, ERASE_PART_t ep)
650
{
651
    DECL_TRACER("TIntBorder::erasePart(SkBitmap *bm, const SkBitmap& mask, ERASE_PART_t ep)");
652
 
653
    if (!bm || bm->empty() || ep == ERASE_NONE)
654
        return;
655
 
656
    int x, y;
657
    int width = bm->info().width();
658
    int height = bm->info().height();
659
 
660
    switch(ep)
661
    {
662
        case ERASE_LEFT_RIGHT:
663
            for (y = 0; y < height; ++y)
664
            {
665
                for (x = 0; x < width; ++x)
666
                {
339 andreas 667
                    SkColor *wpix = bm->getAddr32(x, y);
668
                    SkColor alpha = SkColorGetA(mask.getColor(x, y));
669
 
670
                    if (alpha == 0)
671
                        *wpix = SK_ColorTRANSPARENT;
672
                    else
673
                        break;
307 andreas 674
                }
675
            }
676
        break;
677
 
678
        case ERASE_RIGHT_LEFT:
679
            for (y = 0; y < height; ++y)
680
            {
339 andreas 681
                for (x = width - 1; x >= 0; --x)
682
                {
683
                    SkColor *wpix = bm->getAddr32(x, y);;
684
                    SkColor alpha = SkColorGetA(mask.getColor(x, y));
307 andreas 685
 
339 andreas 686
                    if (alpha == 0)
687
                        *wpix = SK_ColorTRANSPARENT;
688
                    else
689
                        break;
307 andreas 690
                }
691
            }
692
        break;
693
 
694
        case ERASE_TOP_DOWN:
695
            for (x = 0; x < width; ++x)
696
            {
697
                for (y = 0; y < height; ++y)
698
                {
339 andreas 699
                    SkColor *wpix = bm->getAddr32(x, y);;
700
                    SkColor alpha = SkColorGetA(mask.getColor(x, y));
701
 
702
                    if (alpha == 0)
703
                        *wpix = SK_ColorTRANSPARENT;
704
                    else
705
                        break;
307 andreas 706
                }
707
            }
708
        break;
709
 
710
        case ERASE_BOTTOM_UP:
711
            for (x = 0; x < width; ++x)
712
            {
339 andreas 713
                for (y = height - 1; y >= 0; --y)
714
                {
715
                    SkColor *wpix = bm->getAddr32(x, y);;
716
                    SkColor alpha = SkColorGetA(mask.getColor(x, y));
307 andreas 717
 
339 andreas 718
                    if (alpha == 0)
719
                        *wpix = SK_ColorTRANSPARENT;
720
                    else
721
                        break;
307 andreas 722
                }
723
            }
724
        break;
725
 
726
        case ERASE_OUTSIDE:
727
            for (y = 0; y < height; ++y)
728
            {
339 andreas 729
                for (x = 0; x < width; ++x)         // from left
307 andreas 730
                {
338 andreas 731
                    SkColor *wpix = bm->getAddr32(x, y);
732
                    SkColor alpha = SkColorGetA(mask.getColor(x, y));
733
 
734
                    if (alpha == 0)
339 andreas 735
                        *wpix = SK_ColorTRANSPARENT;
338 andreas 736
                    else
737
                        break;
339 andreas 738
                }
338 andreas 739
 
339 andreas 740
                for (x = width - 1; x >= 0; --x)    // from right
741
                {
742
                    SkColor *wpix = bm->getAddr32(x, y);;
743
                    SkColor alpha = SkColorGetA(mask.getColor(x, y));
744
 
745
                    if (alpha == 0)
746
                        *wpix = SK_ColorTRANSPARENT;
747
                    else
748
                        break;
308 andreas 749
                }
338 andreas 750
 
339 andreas 751
                for (y = 0; y < height; ++y)        // from top
338 andreas 752
                {
753
                    SkColor *wpix = bm->getAddr32(x, y);;
754
                    SkColor alpha = SkColorGetA(mask.getColor(x, y));
755
 
756
                    if (alpha == 0)
339 andreas 757
                        *wpix = SK_ColorTRANSPARENT;
338 andreas 758
                    else
759
                        break;
339 andreas 760
                }
338 andreas 761
 
339 andreas 762
                for (y = height - 1; y >= 0; --y)   // from bottom
763
                {
764
                    SkColor *wpix = bm->getAddr32(x, y);;
765
                    SkColor alpha = SkColorGetA(mask.getColor(x, y));
766
 
767
                    if (alpha == 0)
768
                        *wpix = SK_ColorTRANSPARENT;
769
                    else
770
                        break;
338 andreas 771
                }
307 andreas 772
            }
773
        break;
774
 
775
        default:
776
            return;
777
    }
778
}
779
 
339 andreas 780
/**
781
 * @brief colorizeFrame - changes the basic color of frame.
782
 * This method replaces the color of every pixel of the \b frame with \b color.
783
 * Only real black pixels are not replaced. The alpha value remains as it is.
784
 *
785
 * @param frame     A pointer to bitmap containing the frame. This must not NULL
786
 *                  and it must not be empty.
787
 * @param color     The color to replace the pixels with.
788
 */
338 andreas 789
void TIntBorder::colorizeFrame(SkBitmap *frame, SkColor color)
790
{
791
    DECL_TRACER("TIntBorder::colorizeFrame(SkBitmap *frame, SkColor color)");
792
 
793
    if (!frame || frame->empty())
794
        return;
795
 
796
    int red   = SkColorGetR(color);
797
    int green = SkColorGetG(color);
798
    int blue  = SkColorGetB(color);
799
 
800
    for (int y = 0; y < frame->info().height(); ++y)
801
    {
802
        for (int x = 0; x < frame->info().width(); ++x)
803
        {
804
            SkColor *wpix = frame->getAddr32(x, y);
805
            int alpha = SkColorGetA(*wpix);
806
 
807
            if (alpha > 0)
808
            {
809
                int wpred = SkColorGetR(*wpix);
810
                int wpgreen = SkColorGetG(*wpix);
811
                int wpblue = SkColorGetB(*wpix);
812
 
813
                if (wpred == 0 && wpgreen == 0 && wpblue == 0)  // black?
814
                    continue;
815
                else
816
                    *wpix = SkColorSetARGB(alpha, red, green, blue);
817
 
818
            }
819
            else
820
                *wpix = SK_ColorTRANSPARENT;
821
        }
822
    }
823
}
824
 
339 andreas 825
/**
826
 * @brief backgroudFrame - Draws a solid underground for a border.
827
 * The method draw a pixel with color \b color at each point (pixel) where
828
 * the alpha value of the bitmap containing the border is not 0.
829
 *
830
 * @param bm        The bitmap containg the button image without the frame.
831
 * @param frame     The bitmap containg the frame.
832
 * @param color     The color to draw for each visible pixel in \b frame.
833
 */
834
void TIntBorder::backgroundFrame(SkBitmap* bm, SkBitmap& frame, SkColor color)
835
{
836
    DECL_TRACER("TIntBorder::backgroundFrame(SkBitmap* bm, SkBitmap& frame, SkColor color)");
837
 
838
    if (!bm || bm->empty() || frame.empty())
839
        return;
840
 
841
    int width = bm->info().width();
842
    int height = bm->info().height();
843
 
844
    if (width != frame.info().width() || height != frame.info().height())
845
    {
846
        MSG_WARNING("Size of bitmap and frame is different!");
847
        return;
848
    }
849
 
850
    for (int y = 0; y < height; ++y)
851
    {
852
        for (int x = 0; x < width; ++x)
853
        {
854
            SkColor *wpix = bm->getAddr32(x, y);
855
            SkColor fpix = frame.getColor(x, y);
856
 
857
            if (SkColorGetA(fpix) > 0)
858
                *wpix = color;
859
        }
860
    }
861
}
862
 
306 andreas 863
SkRect TIntBorder::calcRect(int width, int height, int pen)
864
{
865
    DECL_TRACER("TIntBorder::calcRect(int width, int height, int pen)");
866
    SkRect rect;
867
 
868
    SkScalar left = (SkScalar)pen / 2.0;
869
    SkScalar top = (SkScalar)pen / 2.0;
870
    SkScalar w = (SkScalar)width - (SkScalar)pen;
871
    SkScalar h = (SkScalar)height - (SkScalar)pen;
872
    rect.setXYWH(left, top, w, h);
873
    return rect;
874
}
875