Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
202 andreas 1
/*
258 andreas 2
 * Copyright (C) 2022, 2023 by Andreas Theofilu <andreas@theosys.at>
202 andreas 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
 
19
#include <string>
20
 
203 andreas 21
#include <include/core/SkFont.h>
22
#include <include/core/SkFontMetrics.h>
23
#include <include/core/SkTextBlob.h>
258 andreas 24
#include <include/core/SkRegion.h>
25
#include <include/core/SkImageFilter.h>
26
#include <include/effects/SkImageFilters.h>
203 andreas 27
 
202 andreas 28
#include "tpageinterface.h"
205 andreas 29
#include "tsystemsound.h"
206 andreas 30
#include "ttpinit.h"
204 andreas 31
#include "tconfig.h"
203 andreas 32
#include "tresources.h"
206 andreas 33
#include "tpagemanager.h"
203 andreas 34
#include "terror.h"
202 andreas 35
 
36
using std::string;
37
using std::vector;
38
 
39
bool TPageInterface::drawText(PAGE_T& pinfo, SkBitmap *img)
40
{
41
    MSG_TRACE("TPageInterface::drawText(PAGE_T& pinfo, SkImage& img)");
42
 
43
    if (pinfo.sr[0].te.empty())
44
        return true;
45
 
46
    MSG_DEBUG("Searching for font number " << pinfo.sr[0].fi << " with text " << pinfo.sr[0].te);
47
    FONT_T font = mFonts->getFont(pinfo.sr[0].fi);
48
 
258 andreas 49
    if (font.file.empty())
202 andreas 50
    {
258 andreas 51
        MSG_WARNING("No font file name found for font " << pinfo.sr[0].fi);
52
        return false;
53
    }
202 andreas 54
 
258 andreas 55
    SkCanvas canvas(*img, SkSurfaceProps(1, kUnknown_SkPixelGeometry));
56
    sk_sp<SkTypeface> typeFace = mFonts->getTypeFace(pinfo.sr[0].fi);
202 andreas 57
 
258 andreas 58
    if (!typeFace)
59
    {
60
        MSG_ERROR("Error creating type face " << font.fullName);
61
        TError::setError();
62
        return false;
63
    }
202 andreas 64
 
258 andreas 65
    SkScalar fontSizePt = ((SkScalar)font.size * 1.322);    // Calculate points from pixels (close up)
66
    SkFont skFont(typeFace, fontSizePt);                    // Skia require the font size in points
202 andreas 67
 
258 andreas 68
    SkPaint paint;
69
    paint.setAntiAlias(true);
70
    SkColor color = TColor::getSkiaColor(pinfo.sr[0].ct);
71
    paint.setColor(color);
72
    paint.setStyle(SkPaint::kFill_Style);
202 andreas 73
 
258 andreas 74
    SkFontMetrics metrics;
75
    skFont.getMetrics(&metrics);
76
    int lines = numberLines(pinfo.sr[0].te);
202 andreas 77
 
258 andreas 78
    if (lines > 1 || pinfo.sr[0].ww)
79
    {
80
        vector<string> textLines;
202 andreas 81
 
258 andreas 82
        if (!pinfo.sr[0].ww)
83
            textLines = splitLine(pinfo.sr[0].te);
84
        else
85
        {
86
            textLines = splitLine(pinfo.sr[0].te, pinfo.width, pinfo.height, skFont, paint);
300 andreas 87
            lines = (int)textLines.size();
258 andreas 88
        }
202 andreas 89
 
258 andreas 90
        MSG_DEBUG("Calculated number of lines: " << textLines.size());
91
        int lineHeight = calcLineHeight(pinfo.sr[0].te, skFont);
92
        int totalHeight = lineHeight * lines;
202 andreas 93
 
258 andreas 94
        if (totalHeight > pinfo.height)
95
        {
96
            lines = pinfo.height / lineHeight;
97
            totalHeight = lineHeight * lines;
98
        }
202 andreas 99
 
258 andreas 100
        MSG_DEBUG("Line height: " << lineHeight << ", total height: " << totalHeight);
101
        Button::POSITION_t position = calcImagePosition(&pinfo, pinfo.width, totalHeight, Button::SC_TEXT, 0);
102
        MSG_DEBUG("Position frame: l: " << position.left << ", t: " << position.top << ", w: " << position.width << ", h: " << position.height);
202 andreas 103
 
258 andreas 104
        if (!position.valid)
105
        {
106
            MSG_ERROR("Error calculating the text position!");
107
            TError::setError();
108
            return false;
109
        }
202 andreas 110
 
258 andreas 111
        vector<string>::iterator iter;
112
        int line = 0;
202 andreas 113
 
258 andreas 114
        for (iter = textLines.begin(); iter != textLines.end(); iter++)
202 andreas 115
        {
258 andreas 116
            sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromString(iter->c_str(), skFont);
202 andreas 117
            SkRect rect;
258 andreas 118
            skFont.measureText(iter->c_str(), iter->length(), SkTextEncoding::kUTF8, &rect, &paint);
119
            Button::POSITION_t pos = calcImagePosition(&pinfo, rect.width(), lineHeight, Button::SC_TEXT, 1);
202 andreas 120
 
258 andreas 121
            if (!pos.valid)
202 andreas 122
            {
123
                MSG_ERROR("Error calculating the text position!");
124
                TError::setError();
125
                return false;
126
            }
258 andreas 127
            MSG_DEBUG("Triing to print line: " << *iter);
202 andreas 128
 
258 andreas 129
            SkScalar startX = (SkScalar)pos.left;
130
            SkScalar startY = (SkScalar)position.top + lineHeight * line;
131
            MSG_DEBUG("x=" << startX << ", y=" << startY);
132
            canvas.drawTextBlob(blob, startX, startY + lineHeight / 2 + 4, paint);
133
            line++;
134
 
135
            if (line > lines)
136
                break;
202 andreas 137
        }
138
    }
258 andreas 139
    else    // single line
202 andreas 140
    {
258 andreas 141
        sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromString(pinfo.sr[0].te.c_str(), skFont);
142
        SkRect rect;
143
        skFont.measureText(pinfo.sr[0].te.c_str(), pinfo.sr[0].te.length(), SkTextEncoding::kUTF8, &rect, &paint);
144
        Button::POSITION_t position = calcImagePosition(&pinfo, rect.width(), (rect.height() * (float)lines), Button::SC_TEXT, 0);
145
 
146
        if (!position.valid)
147
        {
148
            MSG_ERROR("Error calculating the text position!");
149
            TError::setError();
150
            return false;
151
        }
152
 
153
        MSG_DEBUG("Printing line " << pinfo.sr[0].te);
154
        SkScalar startX = (SkScalar)position.left;
155
        SkScalar startY = (SkScalar)position.top + metrics.fCapHeight; // + metrics.fLeading; // (metrics.fAscent * -1.0);
156
        canvas.drawTextBlob(blob, startX, startY, paint);
202 andreas 157
    }
158
 
159
    return true;
160
}
161
 
258 andreas 162
bool TPageInterface::drawFrame(PAGE_T& pinfo, SkBitmap* bm)
163
{
164
    DECL_TRACER("TPageInterface::drawFrame(PAGE_T& pinfo, SkBitmap* bm)");
165
 
166
    int instance = 0;
167
 
168
    if (pinfo.sr[instance].bs.empty())
169
    {
170
        MSG_DEBUG("No border defined.");
171
        return false;
172
    }
173
 
174
    // Try to find the border in the system table
175
    BORDER_t bd, bda;
176
    bool classExist = (gPageManager && gPageManager->getSystemDraw());
177
 
178
    if (!classExist)
179
        return false;
180
 
181
    string borderName = pinfo.sr[0].bs;
182
 
183
    if (!gPageManager->getSystemDraw()->getBorder(borderName, TSystemDraw::LT_OFF, &bd, borderName))
184
        return false;
185
 
186
    MSG_DEBUG("System border \"" << borderName << "\" found.");
187
    SkColor color = TColor::getSkiaColor(pinfo.sr[instance].cb);      // border color
188
    SkColor bgColor = TColor::getSkiaColor(pinfo.sr[instance].cf);    // fill color
189
    MSG_DEBUG("Button color: #" << std::setw(6) << std::setfill('0') << std::hex << color << std::dec);
190
    // Load images
191
    SkBitmap imgB, imgBR, imgR, imgTR, imgT, imgTL, imgL, imgBL;
192
 
193
    imgB = retrieveBorderImage(bd.b, bda.b, color, bgColor);
194
 
195
    if (imgB.empty())
196
        return false;
197
 
198
    MSG_DEBUG("Got images " << bd.b << " and " << bda.b << " with size " << imgB.info().width() << " x " << imgB.info().height());
199
    imgBR = retrieveBorderImage(bd.br, bda.br, color, bgColor);
200
 
201
    if (imgBR.empty())
202
        return false;
203
 
204
    MSG_DEBUG("Got images " << bd.br << " and " << bda.br << " with size " << imgBR.info().width() << " x " << imgBR.info().height());
205
    imgR = retrieveBorderImage(bd.r, bda.r, color, bgColor);
206
 
207
    if (imgR.empty())
208
        return false;
209
 
210
    MSG_DEBUG("Got images " << bd.r << " and " << bda.r << " with size " << imgR.info().width() << " x " << imgR.info().height());
211
    imgTR = retrieveBorderImage(bd.tr, bda.tr, color, bgColor);
212
 
213
    if (imgTR.empty())
214
        return false;
215
 
216
    MSG_DEBUG("Got images " << bd.tr << " and " << bda.tr << " with size " << imgTR.info().width() << " x " << imgTR.info().height());
217
    imgT = retrieveBorderImage(bd.t, bda.t, color, bgColor);
218
 
219
    if (imgT.empty())
220
        return false;
221
 
222
    MSG_DEBUG("Got images " << bd.t << " and " << bda.t << " with size " << imgT.info().width() << " x " << imgT.info().height());
223
    imgTL = retrieveBorderImage(bd.tl, bda.tl, color, bgColor);
224
 
225
    if (imgTL.empty())
226
        return false;
227
 
228
    MSG_DEBUG("Got images " << bd.tl << " and " << bda.tl << " with size " << imgTL.info().width() << " x " << imgTL.info().height());
229
    imgL = retrieveBorderImage(bd.l, bda.l, color, bgColor);
230
 
231
    if (imgL.empty())
232
        return false;
233
 
234
    MSG_DEBUG("Got images " << bd.l << " and " << bda.l << " with size " << imgL.info().width() << " x " << imgL.info().height());
235
    imgBL = retrieveBorderImage(bd.bl, bda.bl, color, bgColor);
236
 
237
    if (imgBL.empty())
238
        return false;
239
 
240
    MSG_DEBUG("Got images " << bd.bl << " and " << bda.bl << " with size " << imgBL.info().width() << " x " << imgBL.info().height());
241
    MSG_DEBUG("Button image size: " << (imgTL.info().width() + imgT.info().width() + imgTR.info().width()) << " x " << (imgTL.info().height() + imgL.info().height() + imgBL.info().height()));
242
    MSG_DEBUG("Total size: " << pinfo.width << " x " << pinfo.height);
243
    stretchImageWidth(&imgB, pinfo.width - imgBL.info().width() - imgBR.info().width());
244
    stretchImageWidth(&imgT, pinfo.width - imgTL.info().width() - imgTR.info().width());
245
    stretchImageHeight(&imgL, pinfo.height - imgTL.info().height() - imgBL.info().height());
246
    stretchImageHeight(&imgR, pinfo.height - imgTR.info().height() - imgBR.info().height());
247
    MSG_DEBUG("Stretched button image size: " << (imgTL.info().width() + imgT.info().width() + imgTR.info().width()) << " x " << (imgTL.info().height() + imgL.info().height() + imgBL.info().height()));
248
    // Draw the frame
249
    SkPaint paint;
250
    SkCanvas canvas(*bm, SkSurfaceProps());
251
 
262 andreas 252
    paint.setBlendMode(SkBlendMode::kSrc);
258 andreas 253
    paint.setColor(color);
254
    sk_sp<SkImage> _image = SkImage::MakeFromBitmap(imgB);                                                                              // Bottom
255
    canvas.drawImage(_image, imgBL.info().width(), pinfo.height - imgB.info().height(), SkSamplingOptions(), &paint);
256
    _image = SkImage::MakeFromBitmap(imgBR);                                                                                            // Corner bottom right
257
    canvas.drawImage(_image, pinfo.width - imgBR.info().width(), pinfo.height - imgBR.info().height(), SkSamplingOptions(), &paint);
258
    _image = SkImage::MakeFromBitmap(imgR);                                                                                             // Right
259
    canvas.drawImage(_image, pinfo.width - imgR.info().width(), imgTR.info().height(), SkSamplingOptions(), &paint);
260
    _image = SkImage::MakeFromBitmap(imgTR);                                                                                            // Corner top right
261
    canvas.drawImage(_image, pinfo.width - imgTR.info().width(), 0, SkSamplingOptions(), &paint);
262
    _image = SkImage::MakeFromBitmap(imgT);                                                                                             // Top
263
    canvas.drawImage(_image, imgTL.info().width(), 0, SkSamplingOptions(), &paint);
264
    _image = SkImage::MakeFromBitmap(imgTL);                                                                                            // Corner top left
265
    canvas.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
266
    _image = SkImage::MakeFromBitmap(imgL);                                                                                             // Left
267
    canvas.drawImage(_image, 0, imgTL.info().height(), SkSamplingOptions(), &paint);
268
    _image = SkImage::MakeFromBitmap(imgBL);                                                                                            // Corner bottom left
269
    canvas.drawImage(_image, 0, pinfo.height - imgBL.info().height(), SkSamplingOptions(), &paint);
270
    return true;
271
}
272
 
203 andreas 273
Button::POSITION_t TPageInterface::calcImagePosition(PAGE_T *page, int width, int height, Button::CENTER_CODE cc, int line)
202 andreas 274
{
203 andreas 275
    DECL_TRACER("TPageInterface::calcImagePosition(PAGE_T *page, int with, int height, CENTER_CODE code, int number)");
202 andreas 276
 
258 andreas 277
    if (!page)
278
        return Button::POSITION_t();
279
 
203 andreas 280
    Button::SR_T act_sr;
281
    Button::POSITION_t position;
202 andreas 282
    int ix, iy;
283
 
258 andreas 284
    if (page->sr.size() == 0)
285
    {
286
        if (sr.size() == 0)
287
            return position;
202 andreas 288
 
258 andreas 289
        act_sr = sr.at(0);
290
    }
291
    else
292
        act_sr = page->sr.at(0);
293
 
202 andreas 294
    //    int border_size = getBorderSize(act_sr.bs);
295
    int border_size = 0;
296
    int code, border = border_size;
297
    string dbgCC;
298
    int rwt = 0, rht = 0;
299
 
300
    switch (cc)
301
    {
203 andreas 302
        case Button::SC_ICON:
202 andreas 303
            code = act_sr.ji;
304
            ix = act_sr.ix;
305
            iy = act_sr.iy;
306
            border = border_size = 0;
307
            dbgCC = "ICON";
308
            rwt = width;
309
            rht = height;
310
            break;
311
 
203 andreas 312
        case Button::SC_BITMAP:
202 andreas 313
            code = act_sr.jb;
314
            ix = act_sr.bx;
315
            iy = act_sr.by;
316
            dbgCC = "BITMAP";
203 andreas 317
            rwt = std::min(page->width - border * 2, width);
318
            rht = std::min(page->height - border_size * 2, height);
202 andreas 319
            break;
320
 
203 andreas 321
        case Button::SC_TEXT:
202 andreas 322
            code = act_sr.jt;
323
            ix = act_sr.tx;
324
            iy = act_sr.ty;
325
            dbgCC = "TEXT";
326
            border += 4;
203 andreas 327
            rwt = std::min(page->width - border * 2, width);
328
            rht = std::min(page->height - border_size * 2, height);
202 andreas 329
            break;
330
    }
331
 
332
    if (width > rwt || height > rht)
333
        position.overflow = true;
334
 
335
    switch (code)
336
    {
337
        case 0: // absolute position
338
            position.left = ix;
339
 
258 andreas 340
            if (cc == Button::SC_TEXT && line > 0)
202 andreas 341
                position.top = iy + height * line;
258 andreas 342
            else
343
                position.top = iy;
202 andreas 344
 
258 andreas 345
            if (cc == Button::SC_BITMAP && ix < 0 && rwt < width)
346
                position.left *= -1;
202 andreas 347
 
258 andreas 348
            if (cc == Button::SC_BITMAP && iy < 0 && rht < height)
349
                position.top += -1;
202 andreas 350
 
258 andreas 351
            position.width = rwt;
352
            position.height = rht;
202 andreas 353
        break;
354
 
355
        case 1: // top, left
203 andreas 356
            if (cc == Button::SC_TEXT)
202 andreas 357
            {
358
                position.left = border;
258 andreas 359
 
360
                if (line > 0)
361
                    position.top = height * line;
362
                else
363
                    position.top = border;
202 andreas 364
            }
365
 
366
            position.width = rwt;
367
            position.height = rht;
258 andreas 368
        break;
202 andreas 369
 
370
        case 2: // center, top
203 andreas 371
            if (cc == Button::SC_TEXT)
258 andreas 372
            {
373
                if (line > 0)
374
                    position.top = height * line;
375
                else
376
                    position.top = border;
377
            }
202 andreas 378
 
258 andreas 379
            position.left = (page->width - rwt) / 2;
380
            position.height = rht;
381
            position.width = rwt;
202 andreas 382
        break;
383
 
384
        case 3: // right, top
203 andreas 385
            position.left = page->width - rwt;
202 andreas 386
 
203 andreas 387
            if (cc == Button::SC_TEXT)
202 andreas 388
            {
389
                position.left = (((position.left - border) < 0) ? 0 : position.left - border);
258 andreas 390
 
391
                if (line > 0)
392
                    position.top = height * line;
393
                else
394
                    position.top = border;
202 andreas 395
            }
396
 
397
            position.width = rwt;
398
            position.height = rht;
258 andreas 399
        break;
202 andreas 400
 
401
        case 4: // left, middle
203 andreas 402
            if (cc == Button::SC_TEXT)
202 andreas 403
            {
404
                position.left = border;
258 andreas 405
 
406
                if (line > 0)
407
                    position.top = ((page->height - rht) / 2) + (height / 2 * line);
408
                else
409
                    position.top = (page->height - rht) / 2;
202 andreas 410
            }
411
            else
203 andreas 412
                position.top = (page->height - rht) / 2;
202 andreas 413
 
258 andreas 414
            position.width = rwt;
415
            position.height = rht;
202 andreas 416
        break;
417
 
418
        case 6: // right, middle
203 andreas 419
            position.left = page->width - rwt;
202 andreas 420
 
203 andreas 421
            if (cc == Button::SC_TEXT)
202 andreas 422
            {
423
                position.left = (((position.left - border) < 0) ? 0 : position.left - border);
258 andreas 424
 
425
                if (line > 0)
426
                    position.top = ((page->height - rht) / 2) + (height / 2 * line);
427
                else
428
                    position.top = (page->height - rht) / 2;
202 andreas 429
            }
430
            else
203 andreas 431
                position.top = (page->height - rht) / 2;
202 andreas 432
 
258 andreas 433
            position.width = rwt;
434
            position.height = rht;
202 andreas 435
        break;
436
 
437
        case 7: // left, bottom
203 andreas 438
            if (cc == Button::SC_TEXT)
202 andreas 439
            {
440
                position.left = border_size;
258 andreas 441
 
442
                if (line > 0)
443
                    position.top = (page->height - rht) - height * line;
444
                else
445
                    position.top = page->height - rht;
202 andreas 446
            }
447
            else
203 andreas 448
                position.top = page->height - rht;
202 andreas 449
 
258 andreas 450
            position.width = rwt;
451
            position.height = rht;
202 andreas 452
        break;
453
 
454
        case 8: // center, bottom
203 andreas 455
            position.left = (page->width - rwt) / 2;
202 andreas 456
 
203 andreas 457
            if (cc == Button::SC_TEXT)
258 andreas 458
            {
459
                if (line > 0)
460
                    position.top = (page->height - rht) - height * line;
461
                else
462
                    position.top = page->height - rht;
463
            }
464
            else
465
                position.top = page->height - rht;
202 andreas 466
 
258 andreas 467
            position.width = rwt;
468
            position.height = rht;
202 andreas 469
        break;
470
 
471
        case 9: // right, bottom
203 andreas 472
            position.left = page->width - rwt;
202 andreas 473
 
203 andreas 474
            if (cc == Button::SC_TEXT)
202 andreas 475
            {
476
                position.left = (((position.left - border) < 0) ? 0 : position.left - border);
258 andreas 477
 
478
                if (line > 0)
479
                    position.top = (page->height - rht) - height * line;
480
                else
481
                    position.top = page->height - rht;
202 andreas 482
            }
483
            else
203 andreas 484
                position.top = page->height - rht;
202 andreas 485
        break;
486
 
487
        default: // center, middle
203 andreas 488
            position.left = (page->width - rwt) / 2;
202 andreas 489
 
203 andreas 490
            if (cc == Button::SC_TEXT)
258 andreas 491
            {
492
                if (line > 0)
493
                    position.top = ((page->height - rht) / 2) + (height / 2 * line);
494
                else
495
                    position.top = (page->height - rht) / 2;
496
            }
497
            else
498
                position.top = (page->height - rht) / 2;
202 andreas 499
 
258 andreas 500
            position.width = rwt;
501
            position.height = rht;
202 andreas 502
    }
503
 
504
    MSG_DEBUG("Type: " << dbgCC << ", PosType=" << code << ", Position: x=" << position.left << ", y=" << position.top << ", w=" << position.width << ", h=" << position.height << ", Overflow: " << (position.overflow ? "YES" : "NO"));
505
    position.valid = true;
506
    return position;
507
}
508
 
509
int TPageInterface::calcLineHeight(const string& text, SkFont& font)
510
{
511
    DECL_TRACER("TPageInterface::calcLineHeight(const string& text, SkFont& font)");
512
 
513
    sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromString(text.c_str(), font);
514
    SkRect rect = blob.get()->bounds();
515
    return rect.height();
516
}
517
 
518
int TPageInterface::numberLines(const string& str)
519
{
520
    DECL_TRACER("TPageInterface::numberLines(const string& str)");
521
 
522
    int lines = 1;
523
 
524
    for (size_t i = 0; i < str.length(); i++)
525
    {
526
        if (str.at(i) == '\n')
527
            lines++;
528
    }
529
 
258 andreas 530
    MSG_DEBUG("Detected " << lines << " lines.");
202 andreas 531
    return lines;
532
}
203 andreas 533
 
534
Button::BUTTONS_T *TPageInterface::addButton(Button::TButton* button)
535
{
536
    DECL_TRACER("*TPageInterface::addButton(TButton* button)");
537
 
538
    if (!button)
539
    {
540
        MSG_ERROR("Parameter is NULL!");
541
        TError::setError();
542
        return nullptr;
543
    }
544
 
266 andreas 545
    // We try to add this button to the list of system buttons which will
546
    // succeed only if it is one of the supported system buttons.
547
    addSysButton(button);
271 andreas 548
 
203 andreas 549
    try
550
    {
551
        Button::BUTTONS_T *chain = new Button::BUTTONS_T;
552
        chain->button = button;
553
        chain->next = nullptr;
554
        chain->previous = nullptr;
555
        Button::BUTTONS_T *bts = mButtons;
556
 
557
        if (bts)
558
        {
559
            Button::BUTTONS_T *p = bts;
560
 
561
            while (p && p->next)
562
                p = p->next;
563
 
564
            p->next = chain;
565
            chain->previous = p;
566
        }
567
        else
568
            mButtons = chain;
569
 
570
        return chain;
571
    }
572
    catch (std::exception& e)
573
    {
574
        MSG_ERROR("Memory error: " << e.what());
575
        TError::setError();
576
    }
577
 
578
    return nullptr;
579
}
580
 
581
bool TPageInterface::hasButton(int id)
582
{
583
    DECL_TRACER("TPageInterface::hasButton(int id)");
584
 
585
    Button::BUTTONS_T *bt = mButtons;
586
 
587
    while (bt)
588
    {
589
        if (bt->button && bt->button->getButtonIndex() == id)
590
            return true;
591
 
592
        bt = bt->next;
593
    }
594
 
595
    return false;
596
}
597
 
598
Button::TButton *TPageInterface::getButton(int id)
599
{
600
    DECL_TRACER("TPageInterface::getButton(int id)");
601
 
602
    Button::BUTTONS_T *bt = mButtons;
603
 
604
    while (bt)
605
    {
606
        if (bt->button && bt->button->getButtonIndex() == id)
607
            return bt->button;
608
 
609
        bt = bt->next;
610
    }
611
 
612
    return nullptr;
613
}
614
 
615
vector<Button::TButton *> TPageInterface::getButtons(int ap, int ad)
616
{
617
    DECL_TRACER("TPageInterface::getButtons(int ap, int ad)");
618
 
619
    vector<Button::TButton *> list;
620
    Button::BUTTONS_T *bt = mButtons;
621
 
622
    while (bt)
623
    {
624
        if (bt->button->getAddressPort() == ap && bt->button->getAddressChannel() == ad)
625
            list.push_back(bt->button);
626
 
627
        bt = bt->next;
628
    }
629
 
630
    return list;
631
}
632
 
633
vector<Button::TButton *> TPageInterface::getAllButtons()
634
{
635
    DECL_TRACER("TPageInterface::getAllButtons()");
636
 
637
    vector<Button::TButton *> list;
638
    Button::BUTTONS_T *bt = mButtons;
639
 
640
    while(bt)
641
    {
642
        list.push_back(bt->button);
643
        bt = bt->next;
644
    }
645
 
646
    return list;
647
}
648
 
649
Button::TButton *TPageInterface::getFirstButton()
650
{
651
    DECL_TRACER("TPageInterface::getFirstButton()");
652
 
653
    mLastButton = 0;
654
 
655
    if (mButtons)
656
        return mButtons->button;
657
 
658
    return nullptr;
659
}
660
 
661
Button::TButton *TPageInterface::getNextButton()
662
{
663
    DECL_TRACER("TPageInterface::getNextButton()");
664
 
665
    Button::BUTTONS_T *but = mButtons;
666
    int count = 0;
667
    mLastButton++;
668
 
669
    while (but)
670
    {
671
        if (but->button && count == mLastButton)
672
            return but->button;
673
 
674
        but = but->next;
675
        count++;
676
    }
677
 
678
    return nullptr;
679
}
680
 
681
Button::TButton *TPageInterface::getLastButton()
682
{
683
    DECL_TRACER("TPageInterface::getLastButton()");
684
 
685
    Button::BUTTONS_T *but = mButtons;
686
    mLastButton = 0;
687
 
688
    while (but && but->next)
689
    {
690
        mLastButton++;
691
        but = but->next;
692
    }
693
 
694
    if (!but)
695
        return nullptr;
696
 
697
    return but->button;
698
}
699
 
700
Button::TButton *TPageInterface::getPreviousButton()
701
{
702
    DECL_TRACER("TPageInterface::getPreviousButton()");
703
 
704
    Button::BUTTONS_T *but = mButtons;
705
    int count = 0;
706
 
707
    if (mLastButton)
708
        mLastButton--;
709
    else
710
        return nullptr;
711
 
712
    while (but)
713
    {
714
        if (but->button && count == mLastButton)
715
            return but->button;
716
 
717
        but = but->next;
718
        count++;
719
    }
720
 
721
    return nullptr;
722
}
723
 
724
/*
725
 * Sort the button according to their Z-order.
726
 * The button with the highest Z-order will be the last button in the chain.
727
 * The algorithm is a bubble sort algorithm.
728
 */
729
bool TPageInterface::sortButtons()
730
{
731
    DECL_TRACER("TPageInterface::sortButtons()");
732
 
733
    bool turned = true;
734
 
735
    while (turned)
736
    {
737
        Button::BUTTONS_T *button = mButtons;
738
        turned = false;
739
 
740
        while (button)
741
        {
742
            int zo = button->button->getZOrder();
743
 
744
            if (button->previous)
745
            {
746
                if (zo < button->previous->button->getZOrder())
747
                {
748
                    Button::BUTTONS_T *pprev = button->previous->previous;
749
                    Button::BUTTONS_T *prev = button->previous;
750
                    Button::BUTTONS_T *next = button->next;
751
 
752
                    if (pprev)
753
                        pprev->next = button;
754
 
755
                    prev->next = next;
756
                    prev->previous = button;
757
                    button->next = prev;
758
                    button->previous = pprev;
759
 
760
                    if (!pprev)
761
                        setButtons(button);
762
 
763
                    button = next;
764
 
765
                    if (next)
766
                        next->previous = prev;
767
 
768
                    turned = true;
769
                    continue;
770
                }
771
            }
772
 
773
            button = button->next;
774
        }
775
    }
776
 
777
    return true;
778
}
204 andreas 779
 
289 andreas 780
void TPageInterface::setFonts(TFont *font)
781
{
782
    DECL_TRACER("TPageInterface::setFonts(TFont *font)");
783
 
784
    if (!font)
785
        return;
786
 
787
    mFonts = font;
788
 
789
    Button::BUTTONS_T *button = mButtons;
790
 
791
    while (button)
792
    {
793
        button->button->setFonts(font);
794
        button = button->next;
795
    }
796
}
797
 
204 andreas 798
vector<string> TPageInterface::getListContent(ulong handle, int ap, int ta, int ti, int rows, int columns)
799
{
800
    DECL_TRACER("TPageInterface::getListContent(ulong handle, int ap, int ta, int ti, int rows, int columns)");
801
 
802
    if (ap == 0 && ta == 0 && ti == 0)
803
    {
804
        vector<LIST_t>::iterator iter;
805
 
806
        for (iter = mLists.begin(); iter != mLists.end(); ++iter)
807
        {
808
            if (iter->handle == handle)
809
            {
810
                return iter->list;
811
            }
812
        }
813
 
814
        return vector<string>();
815
    }
816
 
206 andreas 817
    if (ap == 0 && (ta == SYSTEM_LIST_SYSTEMSOUND || ta == SYSTEM_LIST_SINGLEBEEP)) // System listbox: system sounds and system single beeps
204 andreas 818
    {
205 andreas 819
        vector<LIST_t>::iterator iter;
204 andreas 820
 
205 andreas 821
        for (iter = mLists.begin(); iter != mLists.end(); ++iter)
204 andreas 822
        {
205 andreas 823
            if (iter->handle == handle)
824
            {
825
                iter->ap = ap;
826
                iter->ta = ta;
827
                iter->ti = ti;
828
                iter->rows = rows;
829
                iter->columns = columns;
204 andreas 830
 
205 andreas 831
                if (iter->selected < 0 && !iter->list.empty())
832
                {
833
                    int row = getSystemSelection(ta, iter->list);
204 andreas 834
 
205 andreas 835
                    if (row > 0)
836
                        iter->selected = row;
837
                }
204 andreas 838
 
205 andreas 839
                return iter->list;
840
            }
204 andreas 841
        }
842
 
205 andreas 843
        TSystemSound sysSound(TConfig::getSystemProjectPath() + "/graphics/sounds");
844
        vector<string> tmpFiles = sysSound.getAllSingleBeep();
845
        LIST_t list;
846
        list.handle = handle;
847
        list.ap = ap;
848
        list.ta = ta;
849
        list.ti = ti;
850
        list.rows = rows;
851
        list.columns = columns;
852
        list.list = tmpFiles;
853
        list.selected = getSystemSelection(ta, tmpFiles);
854
        mLists.push_back(list);
855
        return tmpFiles;
856
    }
206 andreas 857
    else if (ap == 0 && ta == SYSTEM_LIST_DOUBLEBEEP)   // System listbox: double beeps
205 andreas 858
    {
204 andreas 859
        vector<LIST_t>::iterator iter;
860
 
861
        for (iter = mLists.begin(); iter != mLists.end(); ++iter)
862
        {
863
            if (iter->handle == handle)
864
            {
865
                iter->ap = ap;
866
                iter->ta = ta;
867
                iter->ti = ti;
868
                iter->rows = rows;
869
                iter->columns = columns;
205 andreas 870
 
871
                if (iter->selected < 0 && !iter->list.empty())
872
                {
873
                    int row = getSystemSelection(ta, iter->list);
874
 
875
                    if (row > 0)
876
                        iter->selected = row;
877
                }
878
 
879
                return iter->list;
204 andreas 880
            }
881
        }
882
 
205 andreas 883
        TSystemSound sysSound(TConfig::getSystemProjectPath() + "/graphics/sounds");
884
        vector<string> tmpFiles = sysSound.getAllDoubleBeep();
204 andreas 885
        LIST_t list;
886
        list.handle = handle;
887
        list.ap = ap;
888
        list.ta = ta;
889
        list.ti = ti;
890
        list.rows = rows;
891
        list.columns = columns;
892
        list.list = tmpFiles;
205 andreas 893
        list.selected = getSystemSelection(ta, tmpFiles);
204 andreas 894
        mLists.push_back(list);
895
        return tmpFiles;
896
    }
206 andreas 897
    else if (ap == 0 && ta == SYSTEM_LIST_SURFACE)  // System listbox: TP4 file (surface file)
898
    {
899
        vector<LIST_t>::iterator iter;
204 andreas 900
 
206 andreas 901
        for (iter = mLists.begin(); iter != mLists.end(); ++iter)
902
        {
903
            if (iter->handle == handle)
904
            {
905
                iter->ap = ap;
906
                iter->ta = ta;
907
                iter->ti = ti;
908
                iter->rows = rows;
909
                iter->columns = columns;
910
 
911
                if (iter->selected < 0 && !iter->list.empty())
912
                {
913
                    int row = getSystemSelection(ta, iter->list);
914
 
915
                    if (row > 0)
916
                        iter->selected = row;
917
                }
918
 
919
                return iter->list;
920
            }
921
        }
922
 
923
        // Load surface file names from NetLinx over FTP
924
        TTPInit tt;
925
        vector<TTPInit::FILELIST_t> fileList = tt.getFileList(".tp4");
926
        vector<string> tmpFiles;
927
 
928
        if (!fileList.empty())
929
        {
930
            vector<TTPInit::FILELIST_t>::iterator iter;
931
 
932
            if (gPageManager)
933
                gPageManager->clearFtpSurface();
934
 
935
            for (iter = fileList.begin(); iter != fileList.end(); ++iter)
936
            {
937
                tmpFiles.push_back(iter->fname);
938
 
939
                if (gPageManager)
940
                    gPageManager->addFtpSurface(iter->fname, iter->size);
941
            }
942
        }
943
 
944
        LIST_t list;
945
        list.handle = handle;
946
        list.ap = ap;
947
        list.ta = ta;
948
        list.ti = ti;
949
        list.rows = rows;
950
        list.columns = columns;
951
        list.list = tmpFiles;
952
        list.selected = getSystemSelection(ta, tmpFiles);
953
        mLists.push_back(list);
954
        return tmpFiles;
955
    }
956
 
204 andreas 957
    return vector<string>();
958
}
959
 
205 andreas 960
int TPageInterface::getSystemSelection(int ta, vector<string>& list)
961
{
962
    DECL_TRACER("TPageInterface::setSystemSelection(int ta, vector<string>* list)");
963
 
964
    vector<string>::iterator iterSel;
965
    string sel;
966
 
206 andreas 967
    if (ta == SYSTEM_LIST_SURFACE)
968
        sel = TConfig::getFtpSurface();
969
    if (ta == SYSTEM_LIST_SYSTEMSOUND)
205 andreas 970
        sel = TConfig::getSystemSound();
206 andreas 971
    else if (ta == SYSTEM_LIST_SINGLEBEEP)
205 andreas 972
        sel = TConfig::getSingleBeepSound();
206 andreas 973
    else if (ta == SYSTEM_LIST_DOUBLEBEEP)
205 andreas 974
        sel = TConfig::getDoubleBeepSound();
975
    else
976
        return -1;
977
 
978
    int row = 1;
979
 
980
    for (iterSel = list.begin(); iterSel != list.end(); ++iterSel)
981
    {
982
        if (iterSel->compare(sel) == 0)
983
            return row;
984
 
985
        row++;
986
    }
987
 
988
    return -1;
989
}
990
 
204 andreas 991
string TPageInterface::getListRow(int ti, int row)
992
{
993
    DECL_TRACER("TPageInterface::getListRow(ulong handle, int ti, int row)");
994
 
995
    vector<LIST_t>::iterator iter;
996
 
997
    for (iter = mLists.begin(); iter != mLists.end(); ++iter)
998
    {
999
        if (iter->ti == ti)
1000
        {
1001
            if (row < 1 || (size_t)row > iter->list.size())
1002
                return string();
1003
 
1004
            return iter->list[row-1];
1005
        }
1006
    }
1007
 
1008
    return string();
1009
}
1010
 
1011
void TPageInterface::setGlobalSettings(Button::TButton* button)
1012
{
1013
    DECL_TRACER("TPageInterface::setGlobalSettings(TButton* button)");
1014
 
1015
    if (!button)
1016
        return;
1017
 
205 andreas 1018
    button->setFontOnly(sr[0].fi, 0);
1019
    button->setTextColorOnly(sr[0].ct, 0);
1020
    button->setTextEffectColorOnly(sr[0].ec, 0);
204 andreas 1021
 
206 andreas 1022
    if (button->getListAp() == 0 && button->getListTi() >= SYSTEM_PAGE_START)
205 andreas 1023
        button->setTextJustificationOnly(4, 0, 0, 0);
204 andreas 1024
}
205 andreas 1025
 
1026
void TPageInterface::setSelectedRow(ulong handle, int row)
1027
{
1028
    DECL_TRACER("TPageInterface::setSelectedRow(ulong handle, int row)");
1029
 
1030
    if (row < 1)
1031
        return;
1032
 
1033
    vector<LIST_t>::iterator iter;
1034
 
1035
    for (iter = mLists.begin(); iter != mLists.end(); ++iter)
1036
    {
1037
        if (iter->handle == handle)
1038
        {
1039
            if ((size_t)row <= iter->list.size())
1040
                iter->selected = row;
1041
 
271 andreas 1042
            MSG_DEBUG("Row was set to " << row << " for item " << handleToString(handle));
205 andreas 1043
            return;
1044
        }
1045
    }
1046
}
1047
 
1048
int TPageInterface::getSelectedRow(ulong handle)
1049
{
1050
    DECL_TRACER("TPageInterface::getSelectedRow(ulong handle)");
1051
 
1052
    vector<LIST_t>::iterator iter;
1053
 
1054
    for (iter = mLists.begin(); iter != mLists.end(); ++iter)
1055
    {
1056
        if (iter->handle == handle)
1057
            return iter->selected;
1058
    }
1059
 
1060
    return -1;
1061
}
1062
 
1063
string TPageInterface::getSelectedItem(ulong handle)
1064
{
1065
    DECL_TRACER("TPageInterface::getSelectedItem(ulong handle)");
1066
 
1067
    vector<LIST_t>::iterator iter;
1068
 
1069
    for (iter = mLists.begin(); iter != mLists.end(); ++iter)
1070
    {
1071
        if (iter->handle == handle)
1072
        {
1073
            if (iter->selected > 0 && (size_t)iter->selected <= iter->list.size())
1074
                return iter->list[iter->selected-1];
1075
 
1076
            ulong nPage = (handle >> 16) & 0x0000ffff;
1077
            ulong nButt = handle & 0x0000ffff;
1078
            string sel;
1079
 
206 andreas 1080
            if (nPage == SYSTEM_SUBPAGE_SURFACE && nButt == 1)
1081
                sel = TConfig::getFtpSurface();
1082
            if (nPage == SYSTEM_SUBPAGE_SYSTEMSOUND && nButt == 1)
205 andreas 1083
                sel = TConfig::getSystemSound();
206 andreas 1084
            else if (nPage == SYSTEM_SUBPAGE_SINGLEBEEP && nButt == 1)
205 andreas 1085
                sel = TConfig::getSingleBeepSound();
206 andreas 1086
            else if (nPage == SYSTEM_SUBPAGE_DOUBLEBEEP && nButt == 1)
205 andreas 1087
                sel = TConfig::getDoubleBeepSound();
1088
            else
1089
                return string();
1090
 
1091
            if (iter->list.empty())
1092
                return string();
1093
 
1094
            vector<string>::iterator iterSel;
1095
            int row = 1;
1096
 
1097
            for (iterSel = iter->list.begin(); iterSel != iter->list.end(); ++iterSel)
1098
            {
1099
                if (iterSel->compare(sel) == 0)
1100
                {
1101
                    iter->selected = row;
1102
                    return sel;
1103
                }
1104
 
1105
                row++;
1106
            }
1107
        }
1108
    }
1109
 
1110
    return string();
1111
}
258 andreas 1112
 
1113
SkBitmap TPageInterface::retrieveBorderImage(const string& pa, const string& pb, SkColor color, SkColor bgColor)
1114
{
1115
    DECL_TRACER("TPageInterface::retrieveBorderImage(const string& pa, const string& pb, SkColor color, SkColor bgColor)");
1116
 
1117
    SkBitmap bm, bma;
1118
 
1119
    if (!pa.empty() && !retrieveImage(pa, &bm))
1120
        return SkBitmap();
1121
 
1122
    if (!pb.empty() && !retrieveImage(pb, &bma))
1123
        return SkBitmap();
1124
 
1125
    return colorImage(bm, bma, color, bgColor, false);
1126
}
1127
 
1128
bool TPageInterface::retrieveImage(const string& path, SkBitmap* image)
1129
{
1130
    DECL_TRACER("TPageInterface::retrieveImage(const string& path, SkBitmap* image)");
1131
 
1132
    sk_sp<SkData> im;
1133
 
1134
    if (!(im = readImage(path)))
1135
        return false;
1136
 
1137
    DecodeDataToBitmap(im, image);
1138
 
1139
    if (image->empty())
1140
    {
1141
        MSG_WARNING("Could not create the image " << path);
1142
        return false;
1143
    }
1144
 
1145
    return true;
1146
}
1147
 
1148
SkBitmap TPageInterface::colorImage(SkBitmap& base, SkBitmap& alpha, SkColor col, SkColor bg, bool useBG)
1149
{
1150
    DECL_TRACER("TPageInterface::colorImage(SkBitmap *img, int width, int height, SkColor col, SkColor bg, bool useBG)");
1151
 
1152
    int width = base.info().width();
1153
    int height = base.info().height();
1154
 
1155
    if (width <= 0 || height <= 0)
1156
    {
1157
        MSG_WARNING("Got invalid width or height! (width: " << width << ", height: " << height << ")");
1158
        return SkBitmap();
1159
    }
1160
 
1161
    if (!alpha.empty())
1162
    {
1163
        if (width != alpha.info().width() || height != alpha.info().height())
1164
        {
1165
            MSG_ERROR("Base and alpha masks have different size!");
1166
            return SkBitmap();
1167
        }
1168
    }
1169
 
1170
    SkBitmap maskBm;
1171
 
1172
    if (!allocPixels(width, height, &maskBm))
1173
        return SkBitmap();
1174
 
1175
    maskBm.eraseColor(SK_ColorTRANSPARENT);
1176
 
1177
    for (int ix = 0; ix < width; ix++)
1178
    {
1179
        for (int iy = 0; iy < height; iy++)
1180
        {
1181
            SkColor pixelAlpha = 0;
1182
 
1183
            if (!alpha.empty())
1184
                pixelAlpha = alpha.getColor(ix, iy);
1185
            else
1186
                pixelAlpha = base.getColor(ix, iy);
1187
 
1188
            uint32_t *wpix = maskBm.getAddr32(ix, iy);
1189
 
1190
            if (!wpix)
1191
            {
1192
                MSG_ERROR("No pixel buffer!");
1193
                break;
1194
            }
1195
 
1196
            uint32_t ala = SkColorGetA(pixelAlpha);
1197
 
1198
            if (ala == 0 && !useBG)
1199
                pixelAlpha = col;
1200
            else if (ala == 0)
1201
                pixelAlpha = bg;
1202
            else
1203
            {
1204
                // We've to change the red and the blue color channel because
1205
                // of an error in the Skia library.
1206
                uint32_t red = SkColorGetR(col);
1207
                uint32_t green = SkColorGetG(col);
1208
                uint32_t blue = SkColorGetB(col);
1209
 
1210
                if (alpha.empty())
1211
                {
1212
                    uint32_t pred = SkColorGetR(pixelAlpha);
1213
                    uint32_t pgreen = SkColorGetG(pixelAlpha);
1214
                    uint32_t pblue = SkColorGetB(pixelAlpha);
1215
                    uint32_t maxChan = SkColorGetG(SK_ColorWHITE);
1216
 
1217
                    red   = ((pred == maxChan) ? pred : red);
1218
                    green = ((pgreen == maxChan) ? pgreen : green);
1219
                    blue  = ((pblue == maxChan) ? pblue : blue);
1220
                }
1221
                else if (ala == 0)
1222
                    red = green = blue = 0;
1223
 
1224
                pixelAlpha = SkColorSetARGB(ala, red, green, blue);
1225
            }
1226
 
1227
            *wpix = pixelAlpha;
1228
        }
1229
    }
1230
 
1231
    if (!alpha.empty())
1232
    {
1233
        SkPaint paint;
1234
        paint.setBlendMode(SkBlendMode::kSrcOver);
1235
        SkCanvas can(maskBm);
1236
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(base);
1237
        can.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
1238
    }
1239
 
1240
    return maskBm;
1241
}
1242
 
1243
bool TPageInterface::stretchImageWidth(SkBitmap *bm, int width)
1244
{
1245
    DECL_TRACER("TPageInterface::stretchImageWidth(SkBitmap *bm, int width)");
1246
 
1247
    if (!bm)
1248
        return false;
1249
 
1250
    int rwidth = width;
1251
    SkPaint paint;
1252
    paint.setBlendMode(SkBlendMode::kSrc);
1253
 
1254
    SkImageInfo info = bm->info();
1255
    sk_sp<SkImage> im = SkImage::MakeFromBitmap(*bm);
1256
 
1257
    if (width <= 0)
1258
        rwidth = info.width() + width;
1259
 
1260
    if (rwidth <= 0)
1261
        rwidth = 1;
1262
 
1263
    MSG_DEBUG("Width: " << rwidth << ", Height: " << info.height());
1264
 
1265
    if (!allocPixels(rwidth, info.height(), bm))
1266
        return false;
1267
 
1268
    bm->eraseColor(SK_ColorTRANSPARENT);
1269
    SkCanvas can(*bm, SkSurfaceProps());
1270
    SkRect rect = SkRect::MakeXYWH(0, 0, rwidth, info.height());
1271
    can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
1272
    return true;
1273
}
1274
 
1275
bool TPageInterface::stretchImageHeight(SkBitmap *bm, int height)
1276
{
1277
    DECL_TRACER("TPageInterface::stretchImageHeight(SkBitmap *bm, int height)");
1278
 
1279
    if (!bm)
1280
        return false;
1281
 
1282
    int rheight = height;
1283
    SkPaint paint;
1284
    paint.setBlendMode(SkBlendMode::kSrc);
1285
 
1286
    SkImageInfo info = bm->info();
1287
 
1288
    if (height <= 0)
1289
        rheight = info.height() + height;
1290
 
1291
    if (rheight <= 0)
1292
        rheight = 1;
1293
 
1294
    sk_sp<SkImage> im = SkImage::MakeFromBitmap(*bm);
1295
    MSG_DEBUG("Width: " << info.width() << ", Height: " << rheight);
1296
 
1297
    if (!allocPixels(info.width(), rheight, bm))
1298
        return false;
1299
 
1300
    bm->eraseColor(SK_ColorTRANSPARENT);
1301
    SkCanvas can(*bm, SkSurfaceProps());
1302
    SkRect rect = SkRect::MakeXYWH(0, 0, info.width(), rheight);
1303
    can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
1304
    return true;
1305
}
1306
 
262 andreas 1307
#ifdef _OPAQUE_SKIA_
258 andreas 1308
bool TPageInterface::setOpacity(SkBitmap *bm, int oo)
1309
{
1310
    DECL_TRACER("TPageInterface::setOpacity(SkBitmap *bm, int oo)");
1311
 
1312
    if (oo < 0 || oo > 255 || !bm)
1313
        return false;
1314
 
1315
    SkBitmap ooButton;
1316
    int w = bm->info().width();
1317
    int h = bm->info().height();
1318
 
1319
    if (!allocPixels(w, h, &ooButton))
1320
        return false;
1321
 
1322
    SkCanvas canvas(ooButton);
1323
    SkIRect irect = SkIRect::MakeXYWH(0, 0, w, h);
1324
    SkRegion region;
1325
    region.setRect(irect);
1326
    SkScalar opaque = (SkScalar)oo;
1327
 
1328
    SkScalar alpha = 1.0 / 255.0 * opaque;
1329
    MSG_DEBUG("Calculated alpha value: " << alpha << " (oo=" << oo << ")");
1330
    SkPaint paint;
1331
    paint.setAlphaf(alpha);
1332
    sk_sp<SkImage> _image = SkImage::MakeFromBitmap(*bm);
1333
    canvas.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
1334
    bm->erase(SK_ColorTRANSPARENT, {0, 0, w, h});
1335
    *bm = ooButton;
1336
    return true;
262 andreas 1337
}
1338
#endif