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