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