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

762 lines
18 KiB
C++

#include <precomp.h>
// bitmap-style buttons
#include "buttwnd.h"
#include <bfc/wasabi_std.h>
#include <tataki/canvas/bltcanvas.h>
#include <tataki/region/region.h>
#include <api/wnd/notifmsg.h>
#include <api/wndmgr/msgbox.h>
#include <api/wnd/PaintCanvas.h>
#define DEFAULT_BUTTON_HEIGHT 20
ButtonWnd::ButtonWnd(const wchar_t *button_text)
{
if (button_text != NULL)
setName(button_text);
currgn = NULL;
hirgn = NULL;
normalrgn = NULL;
pushedrgn = NULL;
activatedrgn = NULL;
base_texture = NULL;
xShift=0;
yShift=0;
textsize = DEFAULT_BUTTON_TEXT_SIZE;
alignment = TEXTALIGN_CENTER;
activated = 0;
userhilite = 0;
userdown = 0;
use_base_texture = 0;
center_bitmap = 0;
enabled = 1;
checked=0;
autodim=0;
borders = 1;
borderstyle = 0;
setBorderStyle(L"button_normal");
iwantfocus = 1;
color_text = L"wasabi.button.text";
color_hilite = L"wasabi.button.hiliteText";
color_dimmed = L"wasabi.button.dimmedText";
checkbmp = L"wasabi.popup.menu.check";
inactivealpha = 255;
activealpha = 255;
setRectRgn(1);
retcode = MSGBOX_ABORTED;
forcedown=0;
}
ButtonWnd::~ButtonWnd() {
delete normalrgn;
delete pushedrgn;
delete hirgn;
delete activatedrgn;
}
void ButtonWnd::checkState(POINT *pt) {
POINT pt2;
if (pt == NULL) {
pt = &pt2;
Wasabi::Std::getMousePos(pt);
}
api_region *old = currgn;
if (getDown()) { // button is down
if (pushedrgn)
currgn = pushedrgn;
else
currgn = normalrgn;
} else { // button is not down
if (hirgn && getHilite())
currgn = hirgn;
else
currgn = normalrgn;
}
if (old != currgn) invalidateWindowRegion();
}
void ButtonWnd::onCancelCapture() {
BUTTONWND_PARENT::onCancelCapture();
checkState();
}
int ButtonWnd::onMouseMove(int x, int y) {
POINT pt;
checkState(&pt);
return BUTTONWND_PARENT::onMouseMove(x, y);
}
api_region *ButtonWnd::getRegion() {
if (borders) return NULL;
return currgn;
}
void ButtonWnd::setModalRetCode(int r) { retcode = r; }
int ButtonWnd::getModalRetCode() const { return retcode; }
void ButtonWnd::onLeaveArea() {
BUTTONWND_PARENT::onLeaveArea();
if (hirgn || getDown()) invalidate();
}
void ButtonWnd::onEnterArea() {
BUTTONWND_PARENT::onEnterArea();
if (hirgn) invalidate();
}
/*BOOL ButtonWnd::mouseInRegion(int x, int y) {
POINT pos={x,y};
POINT p2=pos;
RECT r;
getClientRect(&r);
pos.x-=r.left;
pos.y-=r.top;
return (((!currgn || rectrgn) && PtInRect(&r, p2)) || (currgn && currgn->ptInRegion(&pos)));
}*/
int ButtonWnd::setBitmaps(const wchar_t *_normal, const wchar_t *_pushed, const wchar_t *_hilited, const wchar_t *_activated) {
if (_normal) { delete normalrgn; normalrgn = NULL; }
if (_pushed) { delete pushedrgn; pushedrgn = NULL; }
if (_hilited) { delete hirgn; hirgn = NULL; }
if (_activated) { delete activatedrgn; activatedrgn = NULL; }
if (_normal) {
normalbmp = _normal;
normalrgn = new RegionI(normalbmp.getBitmap());
currgn = normalrgn;
}
if (_pushed) {
pushedbmp = _pushed;
pushedrgn = new RegionI(pushedbmp.getBitmap());
}
if (_hilited) {
hilitebmp = _hilited;
hirgn = new RegionI(hilitebmp.getBitmap());
}
if (_activated) {
activatedbmp = _activated;
activatedrgn = new RegionI(activatedbmp.getBitmap());
}
if (isPostOnInit())
invalidate();
return 1;
}
SkinBitmap *ButtonWnd::getNormalBitmap() {
return normalbmp.getBitmap();
}
void ButtonWnd::freeResources() {
BUTTONWND_PARENT::freeResources();
delete normalrgn;
delete pushedrgn;
delete hirgn;
delete activatedrgn;
pushedrgn=NULL;
normalrgn=NULL;
hirgn=NULL;
activatedrgn=NULL;
currgn=NULL;
}
void ButtonWnd::reloadResources() {
BUTTONWND_PARENT::reloadResources();
if (normalbmp.getBitmap())
normalrgn = new RegionI(normalbmp.getBitmap());
if (pushedbmp.getBitmap())
pushedrgn = new RegionI(pushedbmp.getBitmap());
if (hilitebmp.getBitmap())
hirgn = new RegionI(hilitebmp.getBitmap());
if (activatedbmp.getBitmap())
activatedrgn = new RegionI(activatedbmp.getBitmap());
currgn = normalrgn;
}
int ButtonWnd::setBitmapCenter(int centerit) {
return center_bitmap = !!centerit;
}
int ButtonWnd::setBitmaps(OSMODULEHANDLE hInst, int _normal, int _pushed, int _hilited, int _activated, const wchar_t *_colorgroup)
{
if (_normal) { delete normalrgn; normalrgn = NULL; }
if (_pushed) { delete pushedrgn; pushedrgn = NULL; }
if (_hilited) { delete hirgn; hirgn = NULL; }
if (_activated) { delete activatedrgn; activatedrgn = NULL; }
if (_colorgroup == NULL)
_colorgroup = colorgroup;
if (_normal)
{
normalbmp.setHInstanceBitmapColorGroup(_colorgroup);
#ifdef _WIN32
normalbmp.setHInstance(hInst);
#else
#warning port me?
#endif
normalbmp = _normal;
normalrgn = new RegionI(normalbmp.getBitmap());
}
if (_pushed) {
pushedbmp.setHInstanceBitmapColorGroup(_colorgroup);
#ifdef _WIN32
pushedbmp.setHInstance(hInst);
#else
#warning port me?
#endif
pushedbmp = _pushed;
pushedrgn = new RegionI(pushedbmp.getBitmap());
}
if (_hilited) {
hilitebmp.setHInstanceBitmapColorGroup(_colorgroup);
#ifdef _WIN32
hilitebmp.setHInstance(hInst);
#else
#warning port me?
#endif
hilitebmp = _hilited;
hirgn = new RegionI(hilitebmp.getBitmap());
}
if (_activated) {
activatedbmp.setHInstanceBitmapColorGroup(_colorgroup);
#ifdef _WIN32
activatedbmp.setHInstance(hInst);
#else
#warning port me?
#endif
activatedbmp = _activated;
activatedrgn = new RegionI(activatedbmp.getBitmap());
}
return 1;
}
void ButtonWnd::setUseBaseTexture(int useit)
{
if (use_base_texture == useit) return;
use_base_texture = useit;
invalidate();
}
void ButtonWnd::setBaseTexture(SkinBitmap *bmp, int x, int y, int tile)
{
base_texture = bmp;
use_base_texture = TRUE;
tile_base_texture=tile;
xShift=x;
yShift=y;
invalidate();
}
int ButtonWnd::setButtonText(const wchar_t *text, int size)
{
textsize = size;
ASSERT(textsize > 0);
setName(text);
invalidate();
return 1;
}
const wchar_t * ButtonWnd::getButtonText()
{
return getName();
}
void ButtonWnd::setTextAlign(TextAlign align)
{
alignment = align;
invalidate();
}
int ButtonWnd::getWidth()
{
int addl=0;
if (checked) {
addl=checkbmp.getWidth()+3;
}
if (rightbmp.getBitmap())
addl+=rightbmp.getWidth()+3;
if (normalbmp == NULL)
{
TextInfoCanvas blt(this);
Wasabi::FontInfo fontInfo;
fontInfo.pointSize = textsize;
StringPrintfW lstr(L"j%sj", getNameSafe(L""));
if (wcschr(lstr, '\t')) lstr.cat(L" ");
int a=MAX((blt.getTextWidth(lstr, &fontInfo)*11)/10,8)+addl;
return a;
}
return normalbmp.getWidth()+addl;
}
int ButtonWnd::getHeight()
{
int minh=0;
if (checked>0)
minh=checkbmp.getHeight();
if (rightbmp.getBitmap())
minh=MAX(rightbmp.getHeight(),minh);
if (normalbmp == NULL)
{
TextInfoCanvas blt(this);
Wasabi::FontInfo fontInfo;
fontInfo.pointSize = textsize;
int r = MAX(MAX((blt.getTextHeight(getName(), &fontInfo)*11)/10,minh),4);
return r;
}
return MAX(normalbmp.getHeight(),minh);
}
void ButtonWnd::enableButton(int _enabled) {
_enabled = !!_enabled;
if (enabled != _enabled) invalidate();
enabled = _enabled;
onEnable(enabled);
}
int ButtonWnd::getEnabled() const {
return enabled;
}
int ButtonWnd::onPaint(Canvas *canvas)
{
PaintBltCanvas paintcanvas;
SkinBitmap *bmp;
RECT r;
int labelxoffs=0;
int offset = (enabled&&(getPushed()||getDown())) ? 1 : 0;
if (checked) labelxoffs+=3+checkbmp.getWidth();
if (canvas == NULL) {
if (!paintcanvas.beginPaint(this)) return 0;
canvas = &paintcanvas;
}
BUTTONWND_PARENT::onPaint(canvas);
bmp = normalbmp;
if (pushedbmp && (getDown() || getPushed())) bmp = pushedbmp;
else if ((getHilite() || userhilite) && hilitebmp) bmp = hilitebmp;
else if (activatedbmp && getActivatedButton()) bmp = activatedbmp;
getClientRect(&r);
RECT nr = r;
// RECT fcr = r;
if (use_base_texture)
{
if (!base_texture)
renderBaseTexture(canvas, r);
else {
RECT cr;
cr.left = xShift;
cr.top = yShift;
cr.right = cr.left + (r.right-r.left);
cr.bottom = cr.top + (r.bottom-r.top);
if (tile_base_texture) base_texture->blitTile(canvas, &r,xShift,yShift);
else base_texture->stretchToRectAlpha(canvas, &cr, &r, getPaintingAlpha());
}
}
else
{
if (borders)
{
int sysobj = -1;
if (!enabled)
sysobj = dsoDisabled;
else
sysobj = (getPushed() || getDown()) ? dsoPushed : dsoNormal;
if (sysobj != -1) canvas->drawSysObject(&nr, sysobj, getPaintingAlpha());
}
}
if (checked>0)
{
RECT ar;
int c=(r.top+r.bottom)/2;
ar.left=r.left;
ar.top=c-checkbmp.getHeight()/2;
ar.bottom=ar.top+checkbmp.getHeight();
ar.right=r.left+checkbmp.getWidth();
checkbmp.getBitmap()->stretchToRectAlpha(canvas,&ar,getPaintingAlpha());
}
if (rightbmp.getBitmap()) {
RECT ar;
int c=(r.top+r.bottom)/2;
ar.top=c-rightbmp.getHeight()/2;
ar.bottom=ar.top+rightbmp.getHeight();
ar.right=r.right;
ar.left=ar.right-rightbmp.getWidth();
int alpha = getPaintingAlpha();
if (!getEnabled()) alpha /= 2;
rightbmp.getBitmap()->stretchToRectAlpha(canvas, &ar, alpha);
}
if (bmp != NULL) {
RECT br = r;
if (center_bitmap) {
int w = (r.right - r.left) - getWidth() - labelxoffs;
int h = (r.bottom - r.top) - getHeight();
br.top = r.top + h/2 + offset;
br.bottom = br.top + getHeight();
br.left = r.left + w/2 + labelxoffs + offset;
br.right = br.left + getWidth() - (rightbmp.getBitmap()?rightbmp.getWidth()+3:0);
} else {
br.left += labelxoffs;
br.right -= (rightbmp.getBitmap()?rightbmp.getWidth()+3:0);
}
int alpha2;
if (!hilitebmp && enabled && autodim) {
alpha2=128;
if (getHilite() || userhilite) alpha2=255;
} else alpha2 = enabled ? 255 : 64;
bmp->stretchToRectAlpha(canvas, &br,autodim ? (getPaintingAlpha()+alpha2)>>1 : getPaintingAlpha());
}
if (getName() != NULL)
{
Wasabi::FontInfo fontInfo;
fontInfo.opaque = false;
fontInfo.pointSize = textsize;;
int textw, texth;
canvas->getTextExtent(getName(), &textw, &texth, &fontInfo);
if (!enabled)
fontInfo.color = color_dimmed;
else if (userhilite)
fontInfo.color = color_hilite;
else
fontInfo.color = color_text;
int h=(r.bottom-r.top-texth)/2;
if (h<0) h=0;
r.left += offset + labelxoffs;
r.right += offset - (rightbmp.getBitmap()?rightbmp.getWidth()+3:0);
r.top += offset+h;
r.bottom = r.top+texth;
switch (alignment)
{
case TEXTALIGN_CENTER:
canvas->textOutCentered(&r, getName(), &fontInfo);
break;
case TEXTALIGN_RIGHT:
canvas->textOut(r.right-textw, r.top, textw, texth, getName(), &fontInfo);
break;
case TEXTALIGN_LEFT:
if (!wcsstr(getName(), L"\t"))
{
canvas->textOut(r.left, r.top, r.right-r.left, r.bottom-r.top, getName(), &fontInfo);
}
else
{
StringW lstr(getName());
wchar_t *p=wcsstr(lstr.getNonConstVal(),L"\t");
if (p) *p++=0;
else p=L"";
int tw=canvas->getTextWidth(p, &fontInfo);
canvas->textOut(r.left, r.top, r.right-r.left-tw, r.bottom-r.top, lstr, &fontInfo);
canvas->textOut(r.right-tw, r.top, tw, r.bottom-r.top, p, &fontInfo);
}
break;
case TEXTALIGN_LEFT_ELLIPSIS:
if (!wcsstr(getName(),L"\t"))
{
canvas->textOutEllipsed(r.left, r.top, r.right-r.left, r.bottom-r.top, getName(), &fontInfo);
}
else
{
StringW lstr(getName());
wchar_t *p=wcsstr(lstr.getNonConstVal(),L"\t");
if (p) *p++=0;
else p=L"";
int tw=canvas->getTextWidth(p, &fontInfo);
canvas->textOutEllipsed(r.left, r.top, r.right-r.left-tw, r.bottom-r.top, lstr, &fontInfo);
canvas->textOutEllipsed(r.right-tw, r.top, tw, r.bottom-r.top, p, &fontInfo);
}
break;
}
/*
if (textjustify == BUTTONJUSTIFY_CENTER)
canvas->textOutCentered(&r, getName());
else if (textjustify == BUTTONJUSTIFY_LEFT)
{
if (!STRSTR(getName(),"\t"))
canvas->textOutEllipsed(r.left, r.top, r.right-r.left, r.bottom-r.top, getName());
else
{
char *lstr=STRDUP(getName());
char *p=STRSTR(lstr,"\t");
if (p) *p++=0;
else p="";
int tw=canvas->getTextWidth(p);
canvas->textOutEllipsed(r.left, r.top, r.right-r.left-tw, r.bottom-r.top, lstr);
canvas->textOutEllipsed(r.right-tw, r.top, tw, r.bottom-r.top, p);
FREE(lstr);
}
}
*/
}
/* if (enabled && gotFocus() && wantFocus()) { // SKIN ME
fcr.left+=3;
fcr.right-=3;
fcr.top+=3;
fcr.bottom-=3;
DrawFocusRect(canvas->getHDC(), &fcr);
}*/
return 1;
}
void ButtonWnd::onLeftPush(int x, int y)
{
notifyParent(ChildNotify::BUTTON_LEFTPUSH);
invalidate();
}
void ButtonWnd::onRightPush(int x, int y) {
notifyParent(ChildNotify::BUTTON_RIGHTPUSH);
invalidate();
}
void ButtonWnd::onLeftDoubleClick(int x, int y) {
notifyParent(ChildNotify::BUTTON_LEFTDOUBLECLICK);
}
void ButtonWnd::onRightDoubleClick(int x, int y) {
notifyParent(ChildNotify::BUTTON_RIGHTDOUBLECLICK);
}
void ButtonWnd::setHilite(int h) {
h = !!h;
if (userhilite != h) {
userhilite = h;
invalidate();
}
}
int ButtonWnd::getHilite() {
return userhilite || BUTTONWND_PARENT::getHilite();
}
int ButtonWnd::getPushed() const {
return userdown || forcedown;
}
void ButtonWnd::setPushed(int p) {
p = !!p;
if (userdown != p)
{
userdown=p;
invalidate();
}
}
int ButtonWnd::onResize() {
BUTTONWND_PARENT::onResize();
// invalidate();
return 1;
}
void ButtonWnd::setCheckBitmap(const wchar_t *checkbm) {
checkbmp = checkbm;
}
int ButtonWnd::setRightBitmap(const wchar_t *bitmap) {
rightbmp=bitmap;
return 1;
}
void ButtonWnd::setActivatedButton(int a) {
if (activated != a) {
activated = a;
invalidate();
onActivateButton(activated);
}
}
void ButtonWnd::setActivatedNoCallback(int a) {
// also force invalidate.
activated = a;
invalidate();
}
int ButtonWnd::onActivateButton(int active) {
return 1;
}
int ButtonWnd::getActivatedButton() {
return activated;
}
void ButtonWnd::setBorders(int b) {
b = !!b;
if (borders != b) {
borders = b;
setRectRgn(borders);
invalidate();
}
}
void ButtonWnd::setBorderStyle(const wchar_t *style) {
if (style == NULL) style = L"";
if (borderstyle && !WCSICMP(borderstyle, style)) return;
// borderstyle = style;
using namespace DrawSysObj;
static struct {
const wchar_t *style;
int normal, pushed, disabled;
} chart[] = {
{ L"button_normal", BUTTON, BUTTON_PUSHED, BUTTON_DISABLED },
{ L"osbutton_normal", OSBUTTON, OSBUTTON_PUSHED, OSBUTTON_DISABLED },
{ L"osbutton_close", OSBUTTON_CLOSE, OSBUTTON_CLOSE_PUSHED, OSBUTTON_CLOSE_DISABLED },
{ L"osbutton_minimize", OSBUTTON_MINIMIZE, OSBUTTON_MINIMIZE_PUSHED, OSBUTTON_MINIMIZE_DISABLED },
{ L"osbutton_maximize", OSBUTTON_MAXIMIZE, OSBUTTON_MAXIMIZE_PUSHED, OSBUTTON_MAXIMIZE_DISABLED },
{ NULL, BUTTON, BUTTON_PUSHED, BUTTON_DISABLED },
};
dsoNormal = dsoPushed = dsoDisabled = -1;
for (int i = 0; ; i++) {
if (chart[i].style == NULL) return;
if (!WCSICMP(chart[i].style, style)) {
borderstyle = chart[i].style;
dsoNormal = chart[i].normal;
dsoPushed = chart[i].pushed;
dsoDisabled = chart[i].disabled;
}
}
invalidate();
}
const wchar_t *ButtonWnd::getBorderStyle() {
return borderstyle;
}
void ButtonWnd::setInactiveAlpha(int a) {
inactivealpha=a;
}
void ButtonWnd::setActiveAlpha(int a) {
activealpha=a;
}
int ButtonWnd::onGetFocus() {
BUTTONWND_PARENT::onGetFocus();
// invalidate();
return 1;
}
int ButtonWnd::onKillFocus() {
BUTTONWND_PARENT::onKillFocus();
// invalidate();
return 1;
}
void ButtonWnd::setColors(const wchar_t *text, const wchar_t *hilite, const wchar_t *dimmed) {
color_text=text;
color_hilite=hilite;
color_dimmed=dimmed;
invalidate();
}
void ButtonWnd::setTextColor(const wchar_t *text) {
color_text=text;
invalidate();
}
void ButtonWnd::setTextHoverColor(const wchar_t *hilite) {
color_hilite=hilite;
invalidate();
}
void ButtonWnd::setTextDimmedColor(const wchar_t *dimmed) {
color_dimmed=dimmed;
invalidate();
}
int ButtonWnd::onEnable(int is) {
return BUTTONWND_PARENT::onEnable(is);
}
int ButtonWnd::getPreferences(int what) {
switch (what) {
case SUGGESTED_W: {
if (!normalBmpStr.isempty()) return normalbmp.getWidth();
return getWidth();
}
case SUGGESTED_H: {
if (!normalBmpStr.isempty()) return normalbmp.getHeight();
return getHeight();
}
}
return BUTTONWND_PARENT::getPreferences(what);
}
int ButtonWnd::onInit() {
int r = BUTTONWND_PARENT::onInit();
currgn = normalrgn;
return r;
}
int ButtonWnd::onChar(unsigned int c)
{
switch (c) {
#ifdef _WIN32
case VK_RETURN:
case VK_SPACE:
postDeferredCallback(DEFEREDCB_DOWN, 0, 0);
postDeferredCallback(DEFEREDCB_UP, 0, 250);
//return BUTTONWND_PARENT::onChar(c);
break;
#else
#warning port me
#endif
default:
return BUTTONWND_PARENT::onChar(c);
}
return 1;
}
int ButtonWnd::onDeferredCallback(intptr_t p1, intptr_t p2) {
switch (p1) {
case DEFEREDCB_DOWN:
forcedown = 1;
invalidate();
break;
case DEFEREDCB_UP:
forcedown = 0;
invalidate();
RECT r;
getClientRect(&r);
onLeftPush(r.left+(r.right-r.left)/2, r.top+(r.bottom-r.top)/2);
default:
return BUTTONWND_PARENT::onDeferredCallback(p1, p2);
}
return 1;
}