winamp/Src/Wasabi/api/wnd/paintset.cpp
2024-09-24 14:54:57 +02:00

604 lines
13 KiB
C++

#include <precomp.h>
#include <wasabicfg.h>
#include "paintset.h"
using namespace Paintset;
#include <tataki/canvas/bltcanvas.h>
#include <tataki/bitmap/autobitmap.h>
#include <tataki/color/skinclr.h>
#include <api/font/font.h>
#include <api/service/svcs/svc_font.h>
#ifndef WASABI_COMPILE_IMGLDR
#error This module requires image loading capabilities (WASABI_COMPILE_IMGLDR)
#endif
#define TITLE_PADDING 4 // SKINME
#ifdef WASABI_COMPILE_SKIN
static SkinColor title_fg(L"wasabi.component.title.foreground");
static SkinColor title_border(L"wasabi.component.title.border");
#endif
class NOVTABLE PaintSet
{
protected:
PaintSet()
{}
public:
virtual ~PaintSet()
{}
virtual void render(ifc_canvas *canvas, const RECT *r, int alpha) = 0;
};
static PaintSet *sets[NUM_PAINTSETS];
class PaintSetButtonDisabled : public PaintSet
{
public:
PaintSetButtonDisabled();
virtual void render(ifc_canvas *canvas, const RECT *r, int alpha);
private:
AutoSkinBitmap mid;
};
PaintSetButtonDisabled::PaintSetButtonDisabled()
{
mid = L"wasabi.label.middle";
}
void PaintSetButtonDisabled::render(ifc_canvas *canvasbase, const RECT *_r, int alpha)
{
BaseCloneCanvas canvas;
int ret = canvas.clone(canvasbase);
ASSERT(ret);
RECT r = *_r;
mid.stretchToRectAlpha(&canvas, &r, alpha);
}
//----
class PaintSetButtonUp : public PaintSet
{
public:
PaintSetButtonUp();
virtual void render(ifc_canvas *canvas, const RECT *r, int alpha);
protected:
AutoSkinBitmap ul, u, ur;
AutoSkinBitmap l, mid, right;
AutoSkinBitmap ll, bot, lr;
};
PaintSetButtonUp::PaintSetButtonUp()
{
ul = L"wasabi.button.top.left";
u = L"wasabi.button.top";
ur = L"wasabi.button.top.right";
l = L"wasabi.button.left";
mid = L"wasabi.button.middle";
right = L"wasabi.button.right";
ll = L"wasabi.button.bottom.left";
bot = L"wasabi.button.bottom";
lr = L"wasabi.button.bottom.right";
}
void PaintSetButtonUp::render(ifc_canvas *canvasbase, const RECT *_r, int alpha)
{
BaseCloneCanvas canvas;
int ret = canvas.clone(canvasbase);
if (!ret) return;
RECT r = *_r, br;
// upper left
br.left = r.left;
br.top = r.top;
br.right = r.left + ul.getWidth();
br.bottom = r.top + ul.getHeight();
ul.stretchToRectAlpha(&canvas, &br, alpha);
// top
br.left = br.right;
br.right = r.right - ur.getWidth();
u.stretchToRectAlpha(&canvas, &br, alpha);
// upper right
br.left = br.right;
br.right = r.right;
ur.stretchToRectAlpha(&canvas, &br, alpha);
// left
br.left = r.left;
br.right = r.left + l.getWidth();
br.top = r.top + ul.getHeight();
br.bottom = r.bottom - ll.getHeight();
l.stretchToRectAlpha(&canvas, &br, alpha);
// middle
br.top = r.top + ul.getHeight();
br.bottom = r.bottom - ll.getHeight();
br.left = r.left + ul.getWidth();
br.right = r.right - ur.getWidth();
mid.stretchToRectAlpha(&canvas, &br, alpha);
// right
br.left = r.right - right.getWidth();
br.right = r.right;
br.top = r.top + ur.getHeight();
br.bottom = r.bottom - lr.getHeight();
right.stretchToRectAlpha(&canvas, &br, alpha);
// lower left
br.left = r.left;
br.right = r.left + ll.getWidth();
br.top = r.bottom - ll.getHeight();
br.bottom = r.bottom;
ll.stretchToRectAlpha(&canvas, &br, alpha);
// bot
br.left = r.left + ll.getWidth();
br.right = r.right - lr.getWidth();
br.top = r.bottom - bot.getHeight();
br.bottom = r.bottom;
bot.stretchToRectAlpha(&canvas, &br, alpha);
// lower right
br.left = r.right - lr.getWidth();
br.right = r.right;
br.top = r.bottom - lr.getHeight();
br.bottom = r.bottom;
lr.stretchToRectAlpha(&canvas, &br, alpha);
}
class PaintSetLabel : public PaintSetButtonUp
{
public:
PaintSetLabel()
{
ul = L"wasabi.label.top.left";
u = L"wasabi.label.top";
ur = L"wasabi.label.top.right";
l = L"wasabi.label.left";
mid = L"wasabi.label.middle";
right = L"wasabi.label.right";
ll = L"wasabi.label.bottom.left";
bot = L"wasabi.label.bottom";
lr = L"wasabi.label.bottom.right";
}
};
//----
class PaintSetButtonDown : public PaintSet
{
public:
PaintSetButtonDown();
virtual void render(ifc_canvas *canvas, const RECT *r, int alpha);
private:
AutoSkinBitmap ul, u, ur;
AutoSkinBitmap l, mid, right;
AutoSkinBitmap ll, bot, lr;
};
PaintSetButtonDown::PaintSetButtonDown()
{
ul = L"wasabi.button.pressed.top.left";
u = L"wasabi.button.pressed.top";
ur = L"wasabi.button.pressed.top.right";
l = L"wasabi.button.pressed.left";
mid = L"wasabi.button.pressed.middle";
right = L"wasabi.button.pressed.right";
ll = L"wasabi.button.pressed.bottom.left";
bot = L"wasabi.button.pressed.bottom";
lr = L"wasabi.button.pressed.bottom.right";
}
void PaintSetButtonDown::render(ifc_canvas *canvasbase, const RECT *_r, int alpha)
{
BaseCloneCanvas canvas;
int ret = canvas.clone(canvasbase);
ASSERT(ret);
RECT r = *_r, br;
// upper left
br.left = r.left;
br.top = r.top;
br.right = r.left + ul.getWidth();
br.bottom = r.top + ul.getHeight();
ul.stretchToRectAlpha(&canvas, &br, alpha);
// top
br.left = br.right;
br.right = r.right - ur.getWidth();
u.stretchToRectAlpha(&canvas, &br, alpha);
// upper right
br.left = br.right;
br.right = r.right;
ur.stretchToRectAlpha(&canvas, &br, alpha);
// left
br.left = r.left;
br.right = r.left + l.getWidth();
br.top = r.top + ul.getHeight();
br.bottom = r.bottom - ll.getHeight();
l.stretchToRectAlpha(&canvas, &br, alpha);
// middle
br.top = r.top + ul.getHeight();
br.bottom = r.bottom - ll.getHeight();
br.left = r.left + ul.getWidth();
br.right = r.right - ur.getWidth();
mid.stretchToRectAlpha(&canvas, &br, alpha);
// right
br.left = r.right - right.getWidth();
br.right = r.right;
br.top = r.top + ur.getHeight();
br.bottom = r.bottom - lr.getHeight();
right.stretchToRectAlpha(&canvas, &br, alpha);
// lower left
br.left = r.left;
br.right = r.left + ll.getWidth();
br.top = r.bottom - ll.getHeight();
br.bottom = r.bottom;
ll.stretchToRectAlpha(&canvas, &br, alpha);
// bot
br.left = r.left + ll.getWidth();
br.right = r.right - lr.getWidth();
br.top = r.bottom - bot.getHeight();
br.bottom = r.bottom;
bot.stretchToRectAlpha(&canvas, &br, alpha);
// lower right
br.left = r.right - lr.getWidth();
br.right = r.right;
br.top = r.bottom - lr.getHeight();
br.bottom = r.bottom;
lr.stretchToRectAlpha(&canvas, &br, alpha);
}
//--
class PaintSetAppFrame : public PaintSet
{
public:
PaintSetAppFrame();
virtual ~PaintSetAppFrame();
virtual void render(ifc_canvas *canvas, const RECT *r, int alpha);
private:
SkinBitmap *ul, *up, *ur;
SkinBitmap *left, *right;
SkinBitmap *ll, *bot, *lr;
};
PaintSetAppFrame::PaintSetAppFrame()
{
ul = new SkinBitmap(L"studio.border.upperLeft");
up = new SkinBitmap(L"studio.border.top");
ur = new SkinBitmap(L"studio.border.upperRight");
left = new SkinBitmap(L"studio.border.left");
right = new SkinBitmap(L"studio.border.right");
ll = new SkinBitmap(L"studio.border.lowerLeft");
bot = new SkinBitmap(L"studio.border.bottom");
lr = new SkinBitmap(L"studio.border.lowerRight");
}
PaintSetAppFrame::~PaintSetAppFrame()
{
delete ul; delete up; delete ur;
delete left; delete right;
delete ll; delete bot; delete lr;
}
void PaintSetAppFrame::render(ifc_canvas *canvasbase, const RECT *_r, int alpha)
{
BaseCloneCanvas canvas;
int ret = canvas.clone(canvasbase);
ASSERT(ret);
RECT r = *_r;
RECT br;
// upper left
br = r;
br.right = br.left + 2;
br.bottom = br.top + 2;
ul->stretchToRectAlpha(&canvas, &br, alpha);
// top
br = r;
br.left += 2;
br.right -= 2;
br.bottom = br.top + 2;
up->stretchToRectAlpha(&canvas, &br, alpha);
// upper right
br = r;
br.left = br.right - 2;
br.bottom = br.top + 2;
ur->stretchToRectAlpha(&canvas, &br, alpha);
// left
br = r;
br.right = br.left + 2;
br.top += 2;
br.bottom -= 2;
left->stretchToRectAlpha(&canvas, &br, alpha);
// right
br = r;
br.left = br.right - 2;
br.top += 2;
br.bottom -= 2;
right->stretchToRectAlpha(&canvas, &br, alpha);
// lower left
br = r;
br.right = br.left + 2;
br.top = br.bottom - 2;
ll->stretchToRectAlpha(&canvas, &br, alpha);
// bottom
br = r;
br.left += 2;
br.right -= 2;
br.top = br.bottom - 2;
bot->stretchToRectAlpha(&canvas, &br, alpha);
// lower right
br = r;
br.left = br.right - 2;
br.top = br.bottom - 2;
lr->stretchToRectAlpha(&canvas, &br, alpha);
}
// -----
class PaintSetTitleStreak : public PaintSet
{
public:
PaintSetTitleStreak();
virtual void render(ifc_canvas *canvas, const RECT *r, int alpha);
private:
AutoSkinBitmap title_left, title_middle, title_right;
};
PaintSetTitleStreak::PaintSetTitleStreak()
{
title_left = L"wasabi.titlebar.left.active";
title_middle = L"wasabi.titlebar.center.active";
title_right = L"wasabi.titlebar.right.active";
}
void PaintSetTitleStreak::render(ifc_canvas *canvasbase, const RECT *_r, int alpha)
{
BaseCloneCanvas canvas;
int ret = canvas.clone(canvasbase);
if (!ret) return;
RECT r = *_r;
RECT lr = r;
lr.right = lr.left + title_left.getWidth();
lr.top += ((lr.bottom - lr.top) - title_left.getHeight()) / 2;
lr.bottom = lr.top + title_left.getHeight();
if (lr.right <= lr.left) return;
title_left.stretchToRectAlpha(&canvas, &lr, alpha);
RECT rr = r;
rr.left = rr.right - title_right.getWidth();
rr.top += ((rr.bottom - rr.top) - title_left.getHeight()) / 2;
rr.bottom = rr.top + title_left.getHeight();
if (rr.right <= rr.left) return;
title_right.stretchToRectAlpha(&canvas, &rr, alpha);
RECT cr = r;
cr.left = lr.right;
cr.right = rr.left;
cr.top += ((cr.bottom - cr.top) - title_left.getHeight()) / 2;
cr.bottom = cr.top + title_left.getHeight();
if (cr.right <= cr.left) return;
title_middle.stretchToRectAlpha(&canvas, &cr, alpha);
}
class PaintSetFocusRect : public PaintSet
{
public:
virtual void render(ifc_canvas *canvas, const RECT *r, int alpha)
{
BaseCloneCanvas c;
c.clone(canvas);
c.drawRect(r, 0, 0xFFFFFF, alpha);
}
};
// -----
int paintset_present(int set)
{
return paintset_renderPaintSet(set, NULL, NULL, 255, TRUE);
}
int paintset_renderPaintSet(int type, ifc_canvas *c, const RECT *r, int alpha, int checkonly)
{
PaintSet *ret = NULL;
switch (type)
{
case BUTTONUP:
ret = sets[BUTTONUP];
if (ret == NULL) ret = new PaintSetButtonUp();
sets[BUTTONUP] = ret;
break;
case BUTTONDOWN:
ret = sets[BUTTONDOWN];
if (ret == NULL) ret = new PaintSetButtonDown();
sets[BUTTONDOWN] = ret;
break;
case TRAY:
ret = sets[BUTTONDOWN];
if (ret == NULL) ret = new PaintSetButtonDown();
sets[BUTTONDOWN] = ret;
break;
case APPFRAME:
ret = sets[APPFRAME];
if (ret == NULL) ret = new PaintSetAppFrame();
sets[APPFRAME] = ret;
break;
case BUTTONDISABLED:
ret = sets[BUTTONDISABLED];
if (ret == NULL) ret = new PaintSetButtonDisabled();
sets[BUTTONDISABLED] = ret;
break;
case TITLESTREAK:
ret = sets[TITLESTREAK];
if (ret == NULL) ret = new PaintSetTitleStreak();
sets[TITLESTREAK] = ret;
break;
case LABEL:
ret = sets[LABEL];
if (ret == NULL) ret = new PaintSetLabel();
sets[LABEL] = ret;
break;
case FOCUSRECT:
ret = sets[FOCUSRECT];
if (ret == NULL) ret = new PaintSetFocusRect();
sets[FOCUSRECT] = ret;
break;
}
if (ret != NULL)
{
if (!checkonly) ret->render(c, r, alpha);
return TRUE;
}
return FALSE;
}
#ifdef WASABI_COMPILE_FONTS
#define VERTPAD 2
#define AAFACTOR 2
#define FONTNAME "studio.component.title"
#define FONTNAMEW L"studio.component.title"
void paintset_renderTitle(const wchar_t *title, ifc_canvas *canvasbase, const RECT *_r, int alpha, int dostreaks, int doborder)
{
BaseCloneCanvas canvas;
int ret = canvas.clone(canvasbase);
if (!ret) return;
RECT r = *_r;
int w = r.right - r.left;
int h = (r.bottom - r.top) - VERTPAD;
svc_font *f = Font::requestSkinFont(FONTNAMEW);
if (f->isBitmap() || !doborder)
{
Wasabi::FontInfo fontInfo;
int tw, th;
fontInfo.pointSize = h;
fontInfo.face = FONTNAMEW;
fontInfo.color = title_fg;
canvas.getTextExtent(title, &tw, &th, &fontInfo);
w -= (tw + TITLE_PADDING * 2);
w /= 2;
int x = r.left + w + TITLE_PADDING;
int y = r.top + VERTPAD / 2;
canvas.textOut(x, y, title, &fontInfo);
}
else
{
Wasabi::FontInfo fontInfo;
int tw, th;
fontInfo.pointSize = h*AAFACTOR;
fontInfo.face = FONTNAMEW;
canvas.getTextExtent(title, &tw, &th, &fontInfo);
tw /= AAFACTOR;
th /= AAFACTOR;
tw += 2;
th += 2;
BltCanvas bc(tw*AAFACTOR, th*AAFACTOR + 1);
bc.fillBits(RGB(0, 0, 0)); // not skinned
fontInfo.opaque=false;
fontInfo.color = title_border;
bc.textOut(-AAFACTOR, AAFACTOR / 2, title, &fontInfo);
bc.textOut(AAFACTOR, AAFACTOR / 2, title, &fontInfo);
bc.textOut(AAFACTOR / 2, -AAFACTOR, title, &fontInfo);
bc.textOut(AAFACTOR / 2, AAFACTOR, title, &fontInfo);
fontInfo.color = title_fg;
bc.textOut(AAFACTOR / 2, AAFACTOR / 2, title, &fontInfo);
// mask it
bc.maskColor(RGB(0, 0, 0), RGB(0, 0, 0));
BltCanvas tc(tw, th);
bc.antiAliasTo(&tc, tw, th, AAFACTOR);
//int cw = tw + TITLE_PADDING * 2;
// if (cw > w || th > h) return;
w -= (tw + TITLE_PADDING * 2);
w /= 2;
int x = r.left + w + TITLE_PADDING;
int y = r.top + VERTPAD / 2;
//FG>?? tc.vflip();
tc.blitAlpha(&canvas, x, y, alpha);
//SkinBitmap splef0(tc.getBitmap(), tc.getHDC(), TRUE, tc.getBits());
// splef0.blitAlpha(&canvas, x, y, alpha);
}
if (dostreaks)
{
RECT pr = r;
pr.right = pr.left + w;
paintset_renderPaintSet(TITLESTREAK, &canvas, &pr, alpha);
pr.right = r.right;
pr.left = r.right - w;
paintset_renderPaintSet(TITLESTREAK, &canvas, &pr, alpha);
}
}
#endif
void paintset_reset()
{
for (int i = 0; i < NUM_PAINTSETS; i++)
{
delete sets[i];
sets[i] = NULL;
}
}