1797 lines
49 KiB
C++
1797 lines
49 KiB
C++
/*
|
|
WDL - virtwnd.cpp
|
|
Copyright (C) 2006 and later Cockos Incorporated
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
|
|
Implementation for basic virtual window types.
|
|
|
|
*/
|
|
|
|
#include "virtwnd-controls.h"
|
|
#include "../lice/lice.h"
|
|
#include "../assocarray.h"
|
|
|
|
WDL_VWnd_Painter::WDL_VWnd_Painter()
|
|
{
|
|
m_GSC=0;
|
|
m_bm=0;
|
|
m_bgbm=0;
|
|
m_bgbmtintUnderMode = false;
|
|
m_bgbmtintcolor = -1;
|
|
|
|
m_paint_xorig=m_paint_yorig=0;
|
|
m_cur_hwnd=0;
|
|
memset(&m_ps,0,sizeof(m_ps));
|
|
m_wantg=-1;
|
|
m_gradstart=0.5;
|
|
m_gradslope=0.2;
|
|
m_bgcache=0;
|
|
m_render_scale = WDL_VWND_SCALEBASE;
|
|
m_advisory_scale = WDL_VWND_SCALEBASE;
|
|
}
|
|
|
|
WDL_VWnd_Painter::~WDL_VWnd_Painter()
|
|
{
|
|
delete m_bm;
|
|
}
|
|
|
|
void WDL_VWnd_Painter::SetGSC(int (*_GSC)(int))
|
|
{
|
|
m_GSC=_GSC;
|
|
}
|
|
int WDL_VWnd_Painter::GSC(int a)
|
|
{
|
|
if (m_GSC) return m_GSC(a);
|
|
return GetSysColor(a);
|
|
}
|
|
|
|
void WDL_VWnd_Painter::SetBGGradient(int wantGradient, double start, double slope)
|
|
{
|
|
m_wantg=wantGradient;
|
|
m_gradstart=start;
|
|
m_gradslope=slope;
|
|
}
|
|
|
|
void WDL_VWnd_Painter::DoPaintBackground(LICE_IBitmap *bmOut, int bgcolor, const RECT *clipr, int wnd_w, int wnd_h, int xoffs, int yoffs)
|
|
{
|
|
if (!bmOut) return;
|
|
|
|
if (m_bgbm&&m_bgbm->bgimage)
|
|
{
|
|
int srcw=m_bgbm->bgimage->getWidth();
|
|
int srch=m_bgbm->bgimage->getHeight();
|
|
if (srcw && srch)
|
|
{
|
|
int fflags=0;
|
|
if (srcw < wnd_w/4 || srch < wnd_h/4)
|
|
fflags|=LICE_BLIT_FILTER_BILINEAR;
|
|
|
|
if (m_bgbmtintUnderMode)
|
|
{
|
|
tintRect(bmOut, clipr, xoffs, yoffs,true);
|
|
}
|
|
|
|
if (m_bgcache && !xoffs && !yoffs)
|
|
{
|
|
const int sinfo2 = bmOut ? (int)bmOut->Extended(LICE_EXT_GET_ADVISORY_SCALING,NULL) : 0;
|
|
if (m_bgbmtintUnderMode)
|
|
{
|
|
LICE_IBitmap *tmp = m_bgcache->GetCachedBG(wnd_w, wnd_h, sinfo2, this, m_bgbm->bgimage);
|
|
if (!tmp)
|
|
{
|
|
tmp = m_bgcache->SetCachedBG(wnd_w, wnd_h, sinfo2, NULL, this, m_bgbm->bgimage);
|
|
|
|
// if added to cache, scale and copy alpha information
|
|
if (tmp) WDL_VirtualWnd_ScaledBlitBG(tmp, m_bgbm, 0, 0, wnd_w, wnd_h,
|
|
0, 0,
|
|
wnd_w,
|
|
wnd_h,
|
|
1.0, LICE_BLIT_MODE_COPY | fflags);
|
|
}
|
|
|
|
if (tmp) // copy from cache
|
|
{
|
|
LICE_Blit(bmOut, tmp, clipr->left, clipr->top, clipr->left, clipr->top, clipr->right - clipr->left, clipr->bottom - clipr->top, 1.0f, LICE_BLIT_USE_ALPHA|LICE_BLIT_MODE_COPY);
|
|
}
|
|
else // scale as if no cache present
|
|
{
|
|
WDL_VirtualWnd_ScaledBlitBG(bmOut, m_bgbm, 0, 0, wnd_w, wnd_h,
|
|
0, 0,
|
|
wnd_w,
|
|
wnd_h,
|
|
1.0, LICE_BLIT_MODE_COPY | fflags | LICE_BLIT_USE_ALPHA);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// tint-over mode, we can render then cache
|
|
LICE_IBitmap *tmp = m_bgcache->GetCachedBG(wnd_w, wnd_h, sinfo2, this, m_bgbm->bgimage);
|
|
if (tmp)
|
|
{
|
|
LICE_Blit(bmOut, tmp, clipr->left, clipr->top, clipr->left, clipr->top, clipr->right - clipr->left, clipr->bottom - clipr->top, 1.0f, LICE_BLIT_MODE_COPY);
|
|
}
|
|
else
|
|
{
|
|
WDL_VirtualWnd_ScaledBlitBG(bmOut, m_bgbm, 0, 0, wnd_w, wnd_h,
|
|
0, 0,
|
|
wnd_w,
|
|
wnd_h,
|
|
1.0, LICE_BLIT_MODE_COPY | fflags);
|
|
m_bgcache->SetCachedBG(wnd_w, wnd_h, sinfo2, bmOut, this, m_bgbm->bgimage);
|
|
}
|
|
}
|
|
}
|
|
else // no bg cache
|
|
{
|
|
WDL_VirtualWnd_ScaledBlitBG(bmOut,m_bgbm,xoffs,yoffs,wnd_w,wnd_h,
|
|
clipr->left+xoffs,clipr->top+yoffs,
|
|
clipr->right-clipr->left,
|
|
clipr->bottom-clipr->top,
|
|
1.0, LICE_BLIT_MODE_COPY | fflags | (m_bgbmtintUnderMode?LICE_BLIT_USE_ALPHA:0));
|
|
}
|
|
|
|
if (!m_bgbmtintUnderMode)
|
|
tintRect(bmOut,clipr,xoffs,yoffs,false);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (bgcolor<0) bgcolor=m_GSC?m_GSC(COLOR_3DFACE):GetSysColor(COLOR_3DFACE);
|
|
|
|
int needfill=1;
|
|
|
|
#ifdef WDL_VWND_WANTBGGRADIENT_SUPPORT
|
|
double gradslope=m_gradslope;
|
|
double gradstart=m_gradstart;
|
|
bool wantGrad=m_wantg>0;
|
|
if (m_wantg<0) wantGrad=WDL_STYLE_GetBackgroundGradient(&gradstart,&gradslope);
|
|
|
|
if (wantGrad && gradslope >= 0.01)
|
|
{
|
|
|
|
{
|
|
needfill=0;
|
|
|
|
int spos = (int) (gradstart * wnd_h);
|
|
if (spos > 0)
|
|
{
|
|
if (spos > wnd_h) spos=wnd_h;
|
|
if (clipr->top < spos)
|
|
{
|
|
LICE_FillRect(bmOut,clipr->left+xoffs,clipr->top+yoffs,
|
|
clipr->right-clipr->left,spos-clipr->top,
|
|
LICE_RGBA_FROMNATIVE(bgcolor,255),1.0f,LICE_BLIT_MODE_COPY);
|
|
}
|
|
}
|
|
else spos=0;
|
|
|
|
if (spos < wnd_h)
|
|
{
|
|
struct
|
|
{
|
|
int x,y,Red,Green,Blue;
|
|
}
|
|
vert[2]={{0,},};
|
|
|
|
double sr=GetRValue(bgcolor);
|
|
double sg=GetGValue(bgcolor);
|
|
double sb=GetBValue(bgcolor);
|
|
|
|
vert [0] .x = clipr->left;
|
|
vert [1] .x = clipr->right;
|
|
|
|
|
|
vert[0].y=clipr->top;
|
|
vert[1].y=clipr->bottom;
|
|
|
|
if (vert[0].y < spos) vert[0].y=spos;
|
|
if (vert[1].y>wnd_h) vert[1].y=wnd_h;
|
|
|
|
wnd_h-=spos;
|
|
|
|
int x;
|
|
for (x =0 ; x < 2; x ++)
|
|
{
|
|
double sc1=(wnd_h-(vert[x].y-spos)*gradslope)/(double)wnd_h * 256.0;
|
|
|
|
vert[x].Red = (int) (sr * sc1);
|
|
vert[x].Green = (int) (sg * sc1);
|
|
vert[x].Blue = (int) (sb * sc1);
|
|
}
|
|
|
|
{
|
|
|
|
int bmh=vert[1].y-vert[0].y;
|
|
float s=(float) (1.0/(65535.0*bmh));
|
|
|
|
LICE_GradRect(bmOut,vert[0].x+xoffs,vert[0].y+yoffs,clipr->right-clipr->left,bmh,
|
|
vert[0].Red/65535.0f,vert[0].Green/65535.0f,vert[0].Blue/65535.0f,1.0,0,0,0,0,
|
|
(vert[1].Red-vert[0].Red)*s,
|
|
(vert[1].Green-vert[0].Green)*s,
|
|
(vert[1].Blue-vert[0].Blue)*s,
|
|
0.0,LICE_BLIT_MODE_COPY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif//WDL_VWND_WANTBGGRADIENT_SUPPORT
|
|
|
|
if (needfill)
|
|
{
|
|
LICE_FillRect(bmOut,clipr->left+xoffs,
|
|
clipr->top+yoffs,
|
|
clipr->right-clipr->left,
|
|
clipr->bottom-clipr->top,LICE_RGBA_FROMNATIVE(bgcolor,255),1.0f,LICE_BLIT_MODE_COPY);
|
|
}
|
|
|
|
}
|
|
|
|
void WDL_VWnd_Painter::PaintBegin(HWND hwnd, int bgcolor, const RECT *limitBGrect, const RECT *windowRect, HDC hdcOut, const RECT *clip_r)
|
|
{
|
|
if (!hwnd && (!windowRect||!hdcOut||!clip_r)) return;
|
|
if (!m_cur_hwnd)
|
|
{
|
|
if (hwnd)
|
|
{
|
|
if (BeginPaint(hwnd,&m_ps))
|
|
{
|
|
m_cur_hwnd=hwnd;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_ps.hdc = hdcOut;
|
|
m_ps.rcPaint = *clip_r;
|
|
}
|
|
if (m_cur_hwnd || !hwnd)
|
|
{
|
|
RECT rrr;
|
|
if (windowRect) rrr=*windowRect;
|
|
else GetClientRect(m_cur_hwnd,&rrr);
|
|
RenderScaleRect(&rrr);
|
|
int fwnd_w=rrr.right-rrr.left,fwnd_h=rrr.bottom-rrr.top;
|
|
if (fwnd_h<0)fwnd_h=-fwnd_h;
|
|
|
|
int wnd_w,wnd_h;
|
|
|
|
if (fwnd_w < 2048 && fwnd_h < 2048)
|
|
{
|
|
m_paint_xorig=m_paint_yorig=0;
|
|
wnd_w=fwnd_w;
|
|
wnd_h=fwnd_h;
|
|
}
|
|
else // alternate large canvas mode
|
|
{
|
|
m_bgcache=0; // force no caching in large canvas mode
|
|
|
|
// note: there can be some slight background artifacts in this mode that need to be resolved (REAPER TCP bg bottom line on partial redraw etc)
|
|
RECT pr = m_ps.rcPaint;
|
|
RenderScaleRect(&pr);
|
|
m_paint_xorig=pr.left;
|
|
m_paint_yorig=pr.top;
|
|
wnd_w = pr.right-pr.left;
|
|
wnd_h = pr.bottom - pr.top;
|
|
}
|
|
|
|
if (wnd_h<0)wnd_h=-wnd_h;
|
|
|
|
if (!m_bm) m_bm=new LICE_SysBitmap;
|
|
|
|
m_bm->Extended(LICE_EXT_SET_ADVISORY_SCALING,&m_advisory_scale);
|
|
|
|
if (m_bm->getWidth()<wnd_w || m_bm->getHeight() < wnd_h)
|
|
{
|
|
m_bm->resize(wdl_max(m_bm->getWidth(),wnd_w),wdl_max(m_bm->getHeight(),wnd_h));
|
|
}
|
|
RECT tr = m_ps.rcPaint;
|
|
RenderScaleRect(&tr);
|
|
RECT lbg;
|
|
if (limitBGrect)
|
|
{
|
|
lbg = *limitBGrect;
|
|
RenderScaleRect(&lbg);
|
|
}
|
|
|
|
if (!limitBGrect || (lbg.left <1 && lbg.top < 1 && lbg.right >= fwnd_w && lbg.bottom >= fwnd_h))
|
|
{
|
|
DoPaintBackground(m_bm,bgcolor,&tr, fwnd_w, fwnd_h, -m_paint_xorig, -m_paint_yorig);
|
|
}
|
|
else
|
|
{
|
|
if (tr.left < lbg.left) tr.left = lbg.left;
|
|
if (tr.top < lbg.top) tr.top = lbg.top;
|
|
if (tr.right > lbg.right) tr.right = lbg.right;
|
|
if (tr.bottom > lbg.bottom) tr.bottom = lbg.bottom;
|
|
|
|
if (tr.left < tr.right && tr.top < tr.bottom)
|
|
{
|
|
const int bgw = lbg.right-lbg.left, bgh = lbg.bottom-lbg.top;
|
|
|
|
const int xl = lbg.left - m_paint_xorig, yl = lbg.top - m_paint_yorig;
|
|
const int xo = wdl_min(xl,0), yo = wdl_min(yl,0);
|
|
const int use_w = bgw + xo, use_h = bgh + yo;
|
|
if (use_w > 0 && use_h > 0)
|
|
{
|
|
LICE_SubBitmap bm(m_bm, wdl_max(xl,0), wdl_max(yl,0), use_w, use_h);
|
|
|
|
OffsetRect(&tr, -lbg.left,-lbg.top);
|
|
DoPaintBackground(&bm,bgcolor,&tr, bgw,bgh, xo, yo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef _WIN32
|
|
typedef struct
|
|
{
|
|
HRGN rgn;
|
|
HWND par;
|
|
RECT *sr;
|
|
} enumInfo;
|
|
|
|
static BOOL CALLBACK enumProc(HWND hwnd,LPARAM lParam)
|
|
{
|
|
enumInfo *p=(enumInfo*)lParam;
|
|
if (IsWindowVisible(hwnd))
|
|
{
|
|
RECT r;
|
|
GetWindowRect(hwnd,&r);
|
|
ScreenToClient(p->par,(LPPOINT)&r);
|
|
ScreenToClient(p->par,((LPPOINT)&r)+1);
|
|
if (!p->rgn) p->rgn=CreateRectRgnIndirect(p->sr);
|
|
|
|
HRGN rgn2=CreateRectRgnIndirect(&r);
|
|
CombineRgn(p->rgn,p->rgn,rgn2,RGN_DIFF);
|
|
DeleteObject(rgn2);
|
|
}
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
void WDL_VWnd_Painter::PaintEnd(int xoffs, int yoffs)
|
|
{
|
|
m_bgbm=0;
|
|
m_bgbmtintUnderMode = false;
|
|
m_bgbmtintcolor = -1;
|
|
if (!m_cur_hwnd && !m_ps.hdc) return;
|
|
if (m_bm)
|
|
{
|
|
#ifdef _WIN32
|
|
HRGN rgnsave=0;
|
|
if (m_cur_hwnd)
|
|
{
|
|
enumInfo a={0,m_cur_hwnd,&m_ps.rcPaint};
|
|
EnumChildWindows(m_cur_hwnd,enumProc,(LPARAM)&a);
|
|
if (a.rgn)
|
|
{
|
|
rgnsave=CreateRectRgn(0,0,0,0);
|
|
GetClipRgn(m_ps.hdc,rgnsave);
|
|
|
|
ExtSelectClipRgn(m_ps.hdc,a.rgn,RGN_AND);
|
|
DeleteObject(a.rgn);
|
|
}
|
|
}
|
|
BitBlt(m_ps.hdc,xoffs+m_ps.rcPaint.left,yoffs+m_ps.rcPaint.top,
|
|
m_ps.rcPaint.right-m_ps.rcPaint.left,
|
|
m_ps.rcPaint.bottom-m_ps.rcPaint.top,
|
|
m_bm->getDC(),m_ps.rcPaint.left-m_paint_xorig,m_ps.rcPaint.top-m_paint_yorig,SRCCOPY);
|
|
|
|
if (rgnsave)
|
|
{
|
|
SelectClipRgn(m_ps.hdc,rgnsave);
|
|
DeleteObject(rgnsave);
|
|
}
|
|
#else
|
|
SWELL_SyncCtxFrameBuffer(m_bm->getDC());
|
|
const int rscale = GetRenderScale();
|
|
|
|
if (rscale != 256)
|
|
{
|
|
RECT p2 = m_ps.rcPaint;
|
|
RenderScaleRect(&p2);
|
|
StretchBlt(m_ps.hdc,xoffs+m_ps.rcPaint.left,yoffs+m_ps.rcPaint.top,
|
|
m_ps.rcPaint.right-m_ps.rcPaint.left,
|
|
m_ps.rcPaint.bottom-m_ps.rcPaint.top,
|
|
m_bm->getDC(),
|
|
p2.left-m_paint_xorig,
|
|
p2.top-m_paint_yorig,
|
|
p2.right-p2.left,
|
|
p2.bottom-p2.top,
|
|
SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
BitBlt(m_ps.hdc,xoffs+m_ps.rcPaint.left,yoffs+m_ps.rcPaint.top,
|
|
m_ps.rcPaint.right-m_ps.rcPaint.left,
|
|
m_ps.rcPaint.bottom-m_ps.rcPaint.top,
|
|
m_bm->getDC(),m_ps.rcPaint.left-m_paint_xorig,m_ps.rcPaint.top-m_paint_yorig,SRCCOPY);
|
|
}
|
|
#endif
|
|
}
|
|
if (m_cur_hwnd)
|
|
{
|
|
EndPaint(m_cur_hwnd,&m_ps);
|
|
m_cur_hwnd=0;
|
|
}
|
|
m_ps.hdc=NULL;
|
|
}
|
|
|
|
void WDL_VWnd_Painter::GetPaintInfo(RECT *rclip, int *xoffsdraw, int *yoffsdraw)
|
|
{
|
|
if (rclip)
|
|
{
|
|
*rclip = m_ps.rcPaint;
|
|
RenderScaleRect(rclip);
|
|
}
|
|
if (xoffsdraw) *xoffsdraw = -m_paint_xorig;
|
|
if (yoffsdraw) *yoffsdraw = -m_paint_yorig;
|
|
}
|
|
|
|
void WDL_VWnd_Painter::tintRect(LICE_IBitmap *bmOut, const RECT *clipr, int xoffs, int yoffs, bool isCopy)
|
|
{
|
|
if (m_bgbmtintcolor>=0 || isCopy)
|
|
{
|
|
if (isCopy)
|
|
{
|
|
LICE_FillRect(bmOut, clipr->left + xoffs, clipr->top + yoffs, clipr->right - clipr->left, clipr->bottom - clipr->top, LICE_RGBA_FROMNATIVE(m_bgbmtintcolor), 1.0f, LICE_BLIT_MODE_COPY);
|
|
return;
|
|
}
|
|
float rv=GetRValue(m_bgbmtintcolor)/255.0f;
|
|
float gv=GetGValue(m_bgbmtintcolor)/255.0f;
|
|
float bv=GetBValue(m_bgbmtintcolor)/255.0f;
|
|
|
|
float avg=(rv+gv+bv)*0.33333f;
|
|
if (avg<0.05f)avg=0.05f;
|
|
|
|
float sc=0.5f;
|
|
float sc2 = (1.0f-sc)/avg;
|
|
|
|
float sc3=32.0f;
|
|
float sc4=64.0f*(avg-0.5f);
|
|
// tint
|
|
LICE_MultiplyAddRect(bmOut,clipr->left+xoffs,clipr->top+yoffs,clipr->right-clipr->left,clipr->bottom-clipr->top,
|
|
sc+rv*sc2,sc+gv*sc2,sc+bv*sc2,1,
|
|
(rv-avg)*sc3+sc4,
|
|
(gv-avg)*sc3+sc4,
|
|
(bv-avg)*sc3+sc4,
|
|
0);
|
|
}
|
|
}
|
|
|
|
|
|
void WDL_VWnd_Painter::PaintBGCfg(WDL_VirtualWnd_BGCfg *bitmap, const RECT *coords, bool allowTint, float alpha, int mode)
|
|
{
|
|
if (!bitmap || !coords || !bitmap->bgimage || !m_bm) return;
|
|
|
|
RECT rr, paintScaled = m_ps.rcPaint, coordsScaled = *coords;
|
|
RenderScaleRect(&coordsScaled);
|
|
RenderScaleRect(&paintScaled);
|
|
rr.left = wdl_max(coordsScaled.left, paintScaled.left);
|
|
rr.top = wdl_max(coordsScaled.top, paintScaled.top);
|
|
rr.right = wdl_min(coordsScaled.right, paintScaled.right);
|
|
rr.bottom = wdl_min(coordsScaled.bottom, paintScaled.bottom);
|
|
|
|
if (allowTint && m_bgbmtintUnderMode)
|
|
{
|
|
if (rr.right>rr.left && rr.bottom>rr.top)
|
|
tintRect(m_bm, &rr, -m_paint_xorig, -m_paint_yorig,true);
|
|
}
|
|
|
|
WDL_VirtualWnd_ScaledBlitBG(m_bm,bitmap,coordsScaled.left - m_paint_xorig,
|
|
coordsScaled.top - m_paint_yorig,
|
|
coordsScaled.right-coordsScaled.left,
|
|
coordsScaled.bottom-coordsScaled.top,
|
|
paintScaled.left - m_paint_xorig,
|
|
paintScaled.top - m_paint_yorig,
|
|
paintScaled.right - paintScaled.left,
|
|
paintScaled.bottom - paintScaled.top,alpha,mode);
|
|
|
|
if (allowTint && !m_bgbmtintUnderMode)
|
|
{
|
|
if (rr.right>rr.left && rr.bottom>rr.top)
|
|
tintRect(m_bm,&rr,-m_paint_xorig,-m_paint_yorig,false);
|
|
}
|
|
}
|
|
|
|
void WDL_VWnd_Painter::PaintVirtWnd(WDL_VWnd *vwnd, int borderflags, int x_xlate, int y_xlate)
|
|
{
|
|
RECT tr=m_ps.rcPaint;
|
|
RenderScaleRect(&tr);
|
|
if (!m_bm||(!m_cur_hwnd&&!m_ps.hdc)|| !vwnd->IsVisible()) return;
|
|
|
|
RECT r;
|
|
vwnd->GetPosition(&r); // maybe should use GetPositionPaintExtent or GetPositionPaintOverExtent ?
|
|
OffsetRect(&r,x_xlate,y_xlate);
|
|
RenderScaleRect(&r);
|
|
const int rscale = GetRenderScale();
|
|
|
|
if (tr.left<r.left) tr.left=r.left;
|
|
if (tr.right>r.right) tr.right=r.right;
|
|
if (tr.top<r.top) tr.top=r.top;
|
|
if (tr.bottom>r.bottom)tr.bottom=r.bottom;
|
|
|
|
if (tr.bottom > tr.top && tr.right > tr.left)
|
|
{
|
|
const int xorig = m_paint_xorig - x_xlate * rscale / WDL_VWND_SCALEBASE;
|
|
const int yorig = m_paint_yorig - y_xlate * rscale / WDL_VWND_SCALEBASE;
|
|
tr.left -= m_paint_xorig;
|
|
tr.right -= m_paint_xorig;
|
|
tr.top -= m_paint_yorig;
|
|
tr.bottom -= m_paint_yorig;
|
|
vwnd->SetCurPainter(this);
|
|
vwnd->OnPaint(m_bm,-xorig,-yorig,&tr,rscale);
|
|
if (borderflags)
|
|
{
|
|
PaintBorderForRect(&r,borderflags);
|
|
}
|
|
if (vwnd->WantsPaintOver()) vwnd->OnPaintOver(m_bm,-xorig,-yorig,&tr,rscale);
|
|
vwnd->SetCurPainter(NULL);
|
|
|
|
}
|
|
}
|
|
|
|
void WDL_VWnd_Painter::PaintBorderForHWND(HWND hwnd, int borderflags)
|
|
{
|
|
#ifdef _WIN32
|
|
if (m_cur_hwnd)
|
|
{
|
|
RECT r;
|
|
GetWindowRect(hwnd,&r);
|
|
ScreenToClient(m_cur_hwnd,(LPPOINT)&r);
|
|
ScreenToClient(m_cur_hwnd,((LPPOINT)&r)+1);
|
|
RenderScaleRect(&r);
|
|
PaintBorderForRect(&r,borderflags);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void WDL_VWnd_Painter::PaintBorderForRect(const RECT *r, int borderflags)
|
|
{
|
|
if (!m_bm|| (!m_cur_hwnd && !m_ps.hdc) ||!borderflags) return;
|
|
RECT rrr = *r;
|
|
RenderScaleRect(&rrr);
|
|
rrr.left-=m_paint_xorig;
|
|
rrr.right-=m_paint_xorig;
|
|
rrr.top-=m_paint_yorig;
|
|
rrr.bottom-=m_paint_yorig;
|
|
|
|
LICE_pixel pencol = m_GSC?m_GSC(COLOR_3DHILIGHT):GetSysColor(COLOR_3DHILIGHT);
|
|
LICE_pixel pencol2 = m_GSC?m_GSC(COLOR_3DSHADOW):GetSysColor(COLOR_3DSHADOW);
|
|
pencol = LICE_RGBA_FROMNATIVE(pencol,255);
|
|
pencol2 = LICE_RGBA_FROMNATIVE(pencol2,255);
|
|
|
|
if (borderflags== WDL_VWP_SUNKENBORDER || borderflags == WDL_VWP_SUNKENBORDER_NOTOP)
|
|
{
|
|
LICE_Line(m_bm,rrr.left-1,rrr.bottom,rrr.right,rrr.bottom,pencol,1.0f,LICE_BLIT_MODE_COPY,false);
|
|
LICE_Line(m_bm,rrr.right,rrr.bottom,rrr.right,rrr.top-1,pencol,1.0f,LICE_BLIT_MODE_COPY,false);
|
|
|
|
if (borderflags != WDL_VWP_SUNKENBORDER_NOTOP)
|
|
LICE_Line(m_bm,rrr.right,rrr.top-1,rrr.left-1,rrr.top-1,pencol2,1.0f,LICE_BLIT_MODE_COPY,false);
|
|
|
|
LICE_Line(m_bm,rrr.left-1,rrr.top-1,rrr.left-1,rrr.bottom,pencol2,1.0f,LICE_BLIT_MODE_COPY,false);
|
|
}
|
|
else if (borderflags == WDL_VWP_DIVIDER_VERT) // vertical
|
|
{
|
|
int left=rrr.left;
|
|
|
|
LICE_Line(m_bm,left,rrr.top,left,rrr.bottom+1,pencol2,1.0f,LICE_BLIT_MODE_COPY,false);
|
|
LICE_Line(m_bm,left+1,rrr.top,left+1,rrr.bottom+1,pencol,1.0f,LICE_BLIT_MODE_COPY,false);
|
|
}
|
|
else if (borderflags == WDL_VWP_DIVIDER_HORZ)
|
|
{
|
|
int top=rrr.top+1;
|
|
LICE_Line(m_bm,rrr.left,top,rrr.right+1,top,pencol2,1.0f,LICE_BLIT_MODE_COPY,false);
|
|
LICE_Line(m_bm,rrr.left,top+1,rrr.right+1,top+1,pencol,1.0f,LICE_BLIT_MODE_COPY,false);
|
|
}
|
|
}
|
|
|
|
WDL_VWnd::WDL_VWnd()
|
|
{
|
|
m__iaccess=0;
|
|
m__iaccess_desc=0;
|
|
m_visible=true; m_id=0;
|
|
m_position.left=0; m_position.top=0; m_position.right=0; m_position.bottom=0;
|
|
m_parent=0;
|
|
m_children=0;
|
|
m_realparent=0;
|
|
m_captureidx=-1;
|
|
m_lastmouseidx=-1;
|
|
m_userdata=0;
|
|
m_curPainter=0;
|
|
m_focused_child = -2;
|
|
}
|
|
|
|
WDL_VWnd::~WDL_VWnd()
|
|
{
|
|
if (m_children)
|
|
{
|
|
WDL_VWnd *cap = m_children->Get(m_captureidx);
|
|
if (cap) cap->OnCaptureLost();
|
|
m_children->Empty(true);
|
|
delete m_children;
|
|
}
|
|
if (m__iaccess) m__iaccess->Release();
|
|
}
|
|
|
|
int WDL_VWnd::GSC(int a)
|
|
{
|
|
return m_curPainter ? m_curPainter->GSC(a) : GetSysColor(a);
|
|
}
|
|
|
|
INT_PTR WDL_VWnd::SendCommand(int command, INT_PTR parm1, INT_PTR parm2, WDL_VWnd *src)
|
|
{
|
|
if (m_realparent)
|
|
{
|
|
return SendMessage(m_realparent,command,parm1,parm2);
|
|
}
|
|
else if (m_parent) return m_parent->SendCommand(command,parm1,parm2,src);
|
|
return 0;
|
|
}
|
|
|
|
void WDL_VWnd::RequestRedraw(RECT *r)
|
|
{
|
|
if (!IsVisible() ||
|
|
m_position.right <= m_position.left ||
|
|
m_position.bottom <= m_position.top) return;
|
|
|
|
RECT r2;
|
|
|
|
if (r)
|
|
{
|
|
r2=*r;
|
|
r2.left+=m_position.left; r2.right += m_position.left;
|
|
r2.top += m_position.top; r2.bottom += m_position.top;
|
|
}
|
|
else
|
|
{
|
|
GetPositionPaintExtent(&r2, WDL_VWND_SCALEBASE);
|
|
RECT r3;
|
|
if (WantsPaintOver())
|
|
{
|
|
GetPositionPaintOverExtent(&r3, WDL_VWND_SCALEBASE);
|
|
if (r3.left<r2.left)r2.left=r3.left;
|
|
if (r3.top<r2.top)r2.top=r3.top;
|
|
if (r3.right>r2.right)r2.right=r3.right;
|
|
if (r3.bottom>r2.bottom)r2.bottom=r3.bottom;
|
|
}
|
|
}
|
|
|
|
if (m_realparent)
|
|
{
|
|
#ifdef _WIN32
|
|
HWND hCh;
|
|
if ((hCh=GetWindow(m_realparent,GW_CHILD)))
|
|
{
|
|
HRGN rgn=CreateRectRgnIndirect(&r2);
|
|
int n=30; // limit to 30 children
|
|
while (n-- && hCh)
|
|
{
|
|
if (IsWindowVisible(hCh))
|
|
{
|
|
RECT r;
|
|
GetWindowRect(hCh,&r);
|
|
ScreenToClient(m_realparent,(LPPOINT)&r);
|
|
ScreenToClient(m_realparent,((LPPOINT)&r)+1);
|
|
HRGN tmprgn=CreateRectRgn(r.left,r.top,r.right,r.bottom);
|
|
CombineRgn(rgn,rgn,tmprgn,RGN_DIFF);
|
|
DeleteObject(tmprgn);
|
|
}
|
|
hCh=GetWindow(hCh,GW_HWNDNEXT);
|
|
}
|
|
InvalidateRgn(m_realparent,rgn,FALSE);
|
|
DeleteObject(rgn);
|
|
|
|
}
|
|
else
|
|
#else
|
|
// OS X, expand region up slightly
|
|
r2.top--;
|
|
#endif
|
|
InvalidateRect(m_realparent,&r2,FALSE);
|
|
}
|
|
else if (m_parent) m_parent->RequestRedraw(&r2);
|
|
}
|
|
|
|
bool WDL_VWnd::IsDescendent(WDL_VWnd *w)
|
|
{
|
|
if (!w || !m_children) return false;
|
|
int x,n=m_children->GetSize();
|
|
for(x=0;x<n;x++) if (m_children->Get(x) == w) return true;
|
|
for(x=0;x<n;x++)
|
|
{
|
|
WDL_VWnd *tmp = m_children->Get(x);
|
|
if (tmp && tmp->IsDescendent(w)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void WDL_VWnd::SetChildPosition(WDL_VWnd *ch, int pos)
|
|
{
|
|
if (!ch || !m_children) return;
|
|
int x;
|
|
for(x=0;x<m_children->GetSize();x++)
|
|
{
|
|
if (m_children->Get(x) == ch)
|
|
{
|
|
if (pos>x) pos--;
|
|
if (pos != x)
|
|
{
|
|
WDL_VWnd * const cap = m_children->Get(m_captureidx);
|
|
m_children->Delete(x);
|
|
m_children->Insert(pos,ch);
|
|
if (cap) m_captureidx = m_children->Find(cap);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void WDL_VWnd::AddChild(WDL_VWnd *wnd, int pos)
|
|
{
|
|
if (!wnd) return;
|
|
|
|
wnd->SetParent(this);
|
|
if (!m_children) m_children=new WDL_PtrList<WDL_VWnd>;
|
|
if (pos<0||pos>=m_children->GetSize())
|
|
{
|
|
m_children->Add(wnd);
|
|
}
|
|
else
|
|
{
|
|
m_children->Insert(pos,wnd);
|
|
if (pos <= m_captureidx) m_captureidx++;
|
|
}
|
|
if (m__iaccess) m__iaccess->ClearCaches();
|
|
}
|
|
|
|
WDL_VWnd *WDL_VWnd::GetChildByID(int id)
|
|
{
|
|
if (m_children)
|
|
{
|
|
int x;
|
|
for (x = 0; x < m_children->GetSize(); x ++)
|
|
if (m_children->Get(x)->GetID()==id) return m_children->Get(x);
|
|
WDL_VWnd *r;
|
|
for (x = 0; x < m_children->GetSize(); x ++) if ((r=m_children->Get(x)->GetChildByID(id))) return r;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void WDL_VWnd::RemoveChild(WDL_VWnd *wnd, bool dodel)
|
|
{
|
|
int idx=m_children ? m_children->Find(wnd) : -1;
|
|
if (idx>=0)
|
|
{
|
|
if (idx == m_captureidx)
|
|
{
|
|
wnd->OnCaptureLost();
|
|
m_captureidx = -1;
|
|
}
|
|
else if (idx < m_captureidx)
|
|
{
|
|
m_captureidx--;
|
|
}
|
|
|
|
if (!dodel) wnd->SetParent(NULL);
|
|
m_children->Delete(idx,dodel);
|
|
}
|
|
if (m__iaccess) m__iaccess->ClearCaches();
|
|
}
|
|
|
|
void WDL_VWnd::OnPaint(LICE_IBitmap *drawbm, int origin_x, int origin_y, RECT *cliprect, int rscale)
|
|
{
|
|
int x;
|
|
if (m_children) for (x = m_children->GetSize()-1; x >=0; x --)
|
|
{
|
|
WDL_VWnd *ch=m_children->Get(x);
|
|
if (PrepareToDrawChild(ch,0) && ch->IsVisible())
|
|
{
|
|
RECT re;
|
|
ch->GetPosition(&re);
|
|
if (re.right>re.left&&re.bottom>re.top)
|
|
{
|
|
ch->GetPositionPaintExtent(&re, rscale);
|
|
RECT p = m_position;
|
|
ScaleRect(&p,rscale);
|
|
re.left += origin_x + p.left;
|
|
re.right += origin_x + p.left;
|
|
re.top += origin_y + p.top;
|
|
re.bottom += origin_y + p.top;
|
|
|
|
RECT cr=*cliprect;
|
|
if (cr.left < re.left) cr.left=re.left;
|
|
if (cr.right > re.right) cr.right=re.right;
|
|
if (cr.top < re.top) cr.top=re.top;
|
|
if (cr.bottom > re.bottom) cr.bottom=re.bottom;
|
|
|
|
if (cr.left < cr.right && cr.top < cr.bottom)
|
|
{
|
|
ch->SetCurPainter(m_curPainter);
|
|
ch->OnPaint(drawbm,p.left+origin_x,p.top+origin_y,&cr, rscale);
|
|
ch->SetCurPainter(NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void WDL_VWnd::OnPaintOver(LICE_IBitmap *drawbm, int origin_x, int origin_y, RECT *cliprect, int rscale)
|
|
{
|
|
int x;
|
|
if (m_children) for (x = m_children->GetSize()-1; x >=0; x --)
|
|
{
|
|
WDL_VWnd *ch=m_children->Get(x);
|
|
if (PrepareToDrawChild(ch,1) && ch->IsVisible() && ch->WantsPaintOver())
|
|
{
|
|
RECT re;
|
|
ch->GetPosition(&re);
|
|
if (re.right>re.left && re.bottom > re.top)
|
|
{
|
|
ch->GetPositionPaintOverExtent(&re,rscale);
|
|
RECT p = m_position;
|
|
ScaleRect(&p,rscale);
|
|
re.left += origin_x + p.left;
|
|
re.right += origin_x + p.left;
|
|
re.top += origin_y + p.top;
|
|
re.bottom += origin_y + p.top;
|
|
|
|
RECT cr=*cliprect;
|
|
|
|
if (cr.left < re.left) cr.left=re.left;
|
|
if (cr.right > re.right) cr.right=re.right;
|
|
if (cr.top < re.top) cr.top=re.top;
|
|
if (cr.bottom > re.bottom) cr.bottom=re.bottom;
|
|
|
|
if (cr.left < cr.right && cr.top < cr.bottom)
|
|
{
|
|
ch->SetCurPainter(m_curPainter);
|
|
ch->OnPaintOver(drawbm,p.left+origin_x,p.top+origin_y,&cr,rscale);
|
|
ch->SetCurPainter(NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int WDL_VWnd::GetNumChildren()
|
|
{
|
|
return m_children ? m_children->GetSize() : 0;
|
|
}
|
|
WDL_VWnd *WDL_VWnd::EnumChildren(int x)
|
|
{
|
|
return m_children ? m_children->Get(x) : 0;
|
|
}
|
|
|
|
void WDL_VWnd::RemoveAllChildren(bool dodel)
|
|
{
|
|
if (m_children)
|
|
{
|
|
WDL_VWnd *cap = m_children->Get(m_captureidx);
|
|
if (cap) cap->OnCaptureLost();
|
|
m_captureidx = -1;
|
|
if (!dodel) // update parent pointers
|
|
{
|
|
int x;
|
|
for (x = 0; x < m_children->GetSize(); x++)
|
|
{
|
|
WDL_VWnd *ch = m_children->Get(x);
|
|
if (ch) ch->SetParent(NULL);
|
|
}
|
|
}
|
|
m_children->Empty(dodel);
|
|
}
|
|
}
|
|
|
|
WDL_VWnd *WDL_VWnd::VirtWndFromPoint(int xpos, int ypos, int maxdepth)
|
|
{
|
|
int x;
|
|
if (m_children) for (x = 0; x < m_children->GetSize(); x++)
|
|
{
|
|
WDL_VWnd *wnd=m_children->Get(x);
|
|
if (wnd->IsVisible() && !wnd->DoNotHitTest())
|
|
{
|
|
RECT r;
|
|
wnd->GetPosition(&r);
|
|
if (xpos >= r.left && xpos < r.right && ypos >= r.top && ypos < r.bottom)
|
|
{
|
|
if (maxdepth!=0)
|
|
{
|
|
WDL_VWnd *cwnd=wnd->VirtWndFromPoint(xpos-r.left,ypos-r.top,maxdepth > 0 ? (maxdepth-1) : -1);
|
|
if (cwnd) return cwnd;
|
|
}
|
|
return wnd;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
int WDL_VWnd::OnMouseDown(int xpos, int ypos) // returns TRUE if handled
|
|
{
|
|
if (!m_children) return 0;
|
|
|
|
WDL_VWnd *wnd=VirtWndFromPoint(xpos,ypos,0);
|
|
if (!wnd)
|
|
{
|
|
m_captureidx=-1;
|
|
return 0;
|
|
}
|
|
RECT r;
|
|
wnd->GetPosition(&r);
|
|
WDL_VWND_DCHK(chk);
|
|
int a;
|
|
if ((a=wnd->OnMouseDown(xpos-r.left,ypos-r.top)))
|
|
{
|
|
if (a<0) return -1;
|
|
if (chk.isOK()) m_captureidx=m_children->Find(wnd);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool WDL_VWnd::OnMouseDblClick(int xpos, int ypos) // returns TRUE if handled
|
|
{
|
|
WDL_VWnd *wnd=VirtWndFromPoint(xpos,ypos,0);
|
|
if (!wnd) return false;
|
|
RECT r;
|
|
wnd->GetPosition(&r);
|
|
return wnd->OnMouseDblClick(xpos-r.left,ypos-r.top);
|
|
}
|
|
|
|
|
|
bool WDL_VWnd::OnMouseWheel(int xpos, int ypos, int amt)
|
|
{
|
|
WDL_VWnd *wnd=VirtWndFromPoint(xpos,ypos,0);
|
|
if (!wnd) return false;
|
|
RECT r;
|
|
wnd->GetPosition(&r);
|
|
return wnd->OnMouseWheel(xpos-r.left,ypos-r.top,amt);
|
|
}
|
|
|
|
|
|
bool WDL_VWnd::GetToolTipString(int xpos, int ypos, char *bufOut, int bufOutSz)
|
|
{
|
|
WDL_VWnd *wnd=VirtWndFromPoint(xpos,ypos,0);
|
|
if (!wnd) return false;
|
|
|
|
RECT r;
|
|
wnd->GetPosition(&r);
|
|
return wnd->GetToolTipString(xpos-r.left,ypos-r.top,bufOut,bufOutSz);
|
|
}
|
|
|
|
int WDL_VWnd::UpdateCursor(int xpos, int ypos)
|
|
{
|
|
WDL_VWnd *wnd=VirtWndFromPoint(xpos,ypos,0);
|
|
if (!wnd) return 0;
|
|
|
|
RECT r;
|
|
wnd->GetPosition(&r);
|
|
return wnd->UpdateCursor(xpos-r.left,ypos-r.top);
|
|
}
|
|
|
|
void WDL_VWnd::OnMouseMove(int xpos, int ypos)
|
|
{
|
|
if (!m_children) return;
|
|
|
|
WDL_VWnd *wnd=m_children->Get(m_captureidx);
|
|
|
|
WDL_VWND_DCHK(chk);
|
|
if (!wnd)
|
|
{
|
|
wnd=VirtWndFromPoint(xpos,ypos,0);
|
|
int idx = wnd ? m_children->Find(wnd) : -1;
|
|
if (idx != m_lastmouseidx)
|
|
{
|
|
WDL_VWnd *t=m_children->Get(m_lastmouseidx);
|
|
if (t) t->OnMouseMove(-1000,-1000);
|
|
if (chk.isOK()) m_lastmouseidx=idx;
|
|
}
|
|
}
|
|
|
|
if (wnd && chk.isOK())
|
|
{
|
|
RECT r;
|
|
wnd->GetPosition(&r);
|
|
wnd->OnMouseMove(xpos-r.left,ypos-r.top);
|
|
}
|
|
}
|
|
|
|
void WDL_VWnd::OnCaptureLost()
|
|
{
|
|
int oldcap=m_captureidx;
|
|
m_captureidx=-1;
|
|
if (m_children)
|
|
{
|
|
WDL_VWnd *wnd=m_children->Get(oldcap);
|
|
if (wnd)
|
|
{
|
|
wnd->OnCaptureLost();
|
|
}
|
|
}
|
|
}
|
|
|
|
void WDL_VWnd::OnMouseUp(int xpos, int ypos)
|
|
{
|
|
int oldcap=m_captureidx;
|
|
m_captureidx=-1; // set this before passing to children, in case a child ends up destroying us
|
|
if (m_children)
|
|
{
|
|
WDL_VWnd *wnd=m_children->Get(oldcap);
|
|
|
|
if (!wnd)
|
|
{
|
|
wnd=VirtWndFromPoint(xpos,ypos,0);
|
|
}
|
|
|
|
if (wnd)
|
|
{
|
|
RECT r;
|
|
wnd->GetPosition(&r);
|
|
wnd->OnMouseUp(xpos-r.left,ypos-r.top);
|
|
}
|
|
}
|
|
}
|
|
void WDL_VWnd::GetPositionInTopVWnd(RECT *r)
|
|
{
|
|
GetPosition(r);
|
|
WDL_VWnd *par=GetParent();
|
|
while (par)
|
|
{
|
|
WDL_VWnd *tmp=par;
|
|
par=par->GetParent();
|
|
if (par)
|
|
{
|
|
RECT t;
|
|
tmp->GetPosition(&t);
|
|
r->left+=t.left;
|
|
r->right+=t.left;
|
|
r->top+=t.top;
|
|
r->bottom+=t.top;
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
class WDL_VirtualWnd_BGCfgCache_img
|
|
{
|
|
public:
|
|
WDL_VirtualWnd_BGCfgCache_img(unsigned int szinfo, int szinfo2, LICE_IBitmap *image, unsigned int now)
|
|
{
|
|
lastowner=0;
|
|
bgimage=image;
|
|
sizeinfo=szinfo;
|
|
scalinginfo=szinfo2;
|
|
lastused=now;
|
|
}
|
|
~WDL_VirtualWnd_BGCfgCache_img()
|
|
{
|
|
delete bgimage;
|
|
}
|
|
|
|
LICE_IBitmap *bgimage;
|
|
unsigned int sizeinfo; // (h<<16)+w
|
|
int scalinginfo; // advisory scaling
|
|
unsigned int lastused; // last used time
|
|
void *lastowner;
|
|
|
|
static int compar(const WDL_VirtualWnd_BGCfgCache_img **a, const WDL_VirtualWnd_BGCfgCache_img ** b)
|
|
{
|
|
const int v = (*a)->scalinginfo - (*b)->scalinginfo;
|
|
if (v) return v;
|
|
return (*a)->sizeinfo - (*b)->sizeinfo;
|
|
|
|
}
|
|
};
|
|
|
|
|
|
class WDL_VirtualWnd_BGCfgCache_ar
|
|
{
|
|
public:
|
|
WDL_VirtualWnd_BGCfgCache_ar() : m_cachelist(compar, NULL, NULL, destrval) { }
|
|
~WDL_VirtualWnd_BGCfgCache_ar() { }
|
|
|
|
WDL_AssocArray<const LICE_IBitmap *, WDL_PtrList<WDL_VirtualWnd_BGCfgCache_img> * > m_cachelist;
|
|
|
|
static void destrval(WDL_PtrList<WDL_VirtualWnd_BGCfgCache_img> *list)
|
|
{
|
|
if (list) list->Empty(true);
|
|
delete list;
|
|
}
|
|
static int compar(const LICE_IBitmap **a, const LICE_IBitmap ** b)
|
|
{
|
|
if ((*a) < (*b)) return -1;
|
|
if ((*a) > (*b)) return 1;
|
|
return 0;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
WDL_VirtualWnd_BGCfgCache::WDL_VirtualWnd_BGCfgCache(int want_size, int max_size)
|
|
{
|
|
m_ar = new WDL_VirtualWnd_BGCfgCache_ar;
|
|
m_want_size=want_size;
|
|
m_max_size = max_size;
|
|
}
|
|
WDL_VirtualWnd_BGCfgCache::~WDL_VirtualWnd_BGCfgCache()
|
|
{
|
|
delete m_ar;
|
|
}
|
|
|
|
void WDL_VirtualWnd_BGCfgCache::Invalidate()
|
|
{
|
|
m_ar->m_cachelist.DeleteAll();
|
|
}
|
|
|
|
LICE_IBitmap *WDL_VirtualWnd_BGCfgCache::GetCachedBG(int w, int h, int sinfo2, void *owner_hint, const LICE_IBitmap *bgbmp)
|
|
{
|
|
if (w<1 || h<1 || w>65535 || h>65535) return NULL;
|
|
|
|
WDL_PtrList<WDL_VirtualWnd_BGCfgCache_img> *cache = m_ar->m_cachelist.Get(bgbmp);
|
|
if (!cache) return NULL;
|
|
|
|
WDL_VirtualWnd_BGCfgCache_img tmp((h<<16)+w,sinfo2,NULL,0);
|
|
WDL_VirtualWnd_BGCfgCache_img *r = cache->Get(cache->FindSorted(&tmp,WDL_VirtualWnd_BGCfgCache_img::compar));
|
|
if (r)
|
|
{
|
|
r->lastused = GetTickCount();
|
|
if (owner_hint && r->lastowner != owner_hint) r->lastowner=0;
|
|
return r->bgimage;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
class MemBitmapScaleRef : public LICE_MemBitmap {
|
|
public:
|
|
MemBitmapScaleRef(int w, int h, int sc) : LICE_MemBitmap(w,h), m_scaling(sc) { }
|
|
int m_scaling;
|
|
virtual INT_PTR Extended(int id, void* data)
|
|
{
|
|
switch (id)
|
|
{
|
|
case LICE_EXT_GET_ADVISORY_SCALING: return m_scaling;
|
|
case LICE_EXT_SET_ADVISORY_SCALING: m_scaling = *(const int *)data; return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
};
|
|
LICE_IBitmap *WDL_VirtualWnd_BGCfgCache::SetCachedBG(int w, int h, int sinfo2, LICE_IBitmap *bmCopy, void *owner_hint, const LICE_IBitmap *bgbmp)
|
|
{
|
|
if (w<1 || h<1 || w>65535 || h>65535) return NULL;
|
|
|
|
const unsigned int sinfo=(h<<16)+w;;
|
|
WDL_PtrList<WDL_VirtualWnd_BGCfgCache_img> *cache = m_ar->m_cachelist.Get(bgbmp);
|
|
if (!cache)
|
|
{
|
|
cache = new WDL_PtrList<WDL_VirtualWnd_BGCfgCache_img>;
|
|
m_ar->m_cachelist.Insert(bgbmp,cache);
|
|
}
|
|
|
|
// caller should ALWAYS call GetCachedBG() and use that if present
|
|
|
|
WDL_VirtualWnd_BGCfgCache_img *img = NULL;
|
|
const DWORD now = GetTickCount();
|
|
bool cacheAtWantSize = cache->GetSize()>=m_want_size;
|
|
if (cacheAtWantSize || owner_hint)
|
|
{
|
|
int x;
|
|
int bestpos=-1;
|
|
DWORD best_age=0;
|
|
for(x=0;x<cache->GetSize();x++)
|
|
{
|
|
WDL_VirtualWnd_BGCfgCache_img *a = cache->Get(x);
|
|
if (owner_hint && a->lastowner == owner_hint)
|
|
{
|
|
cacheAtWantSize=true;
|
|
best_age = 5000;
|
|
bestpos=x;
|
|
break; // FOUND exact match!
|
|
}
|
|
const DWORD age = now-a->lastused;
|
|
if (age > best_age) // find oldest entry
|
|
{
|
|
best_age = age;
|
|
bestpos = x;
|
|
}
|
|
}
|
|
|
|
if (cacheAtWantSize && (best_age > 500 || cache->GetSize() >= m_max_size)) // use this slot if over 1000ms old, or if we're up against the max size
|
|
{
|
|
img = cache->Get(bestpos);
|
|
cache->Delete(bestpos,false);
|
|
if (img)
|
|
{
|
|
img->sizeinfo = sinfo;
|
|
img->scalinginfo = sinfo2;
|
|
img->lastused = now;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (!img)
|
|
{
|
|
LICE_IBitmap *bmcp = new MemBitmapScaleRef(w,h,sinfo2);
|
|
if (bmcp->getWidth()==w && bmcp->getHeight()==h) img = new WDL_VirtualWnd_BGCfgCache_img(sinfo,sinfo2,bmcp,now);
|
|
else delete bmcp;
|
|
}
|
|
else
|
|
{
|
|
if (img->bgimage)
|
|
{
|
|
img->bgimage->Extended(LICE_EXT_SET_ADVISORY_SCALING,&sinfo2);
|
|
img->bgimage->resize(w,h);
|
|
}
|
|
}
|
|
|
|
if (img)
|
|
{
|
|
img->lastowner = owner_hint;
|
|
if (bmCopy) LICE_Copy(img->bgimage, bmCopy);
|
|
|
|
cache->InsertSorted(img, WDL_VirtualWnd_BGCfgCache_img::compar);
|
|
return img->bgimage;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void WDL_VirtualWnd_PreprocessBGConfig(WDL_VirtualWnd_BGCfg *a)
|
|
{
|
|
if (!a) return;
|
|
|
|
if (!a->bgimage) return;
|
|
a->bgimage_lt[0]=a->bgimage_lt[1]=a->bgimage_rb[0]=a->bgimage_rb[1]=0;
|
|
a->bgimage_lt_out[0]=a->bgimage_lt_out[1]=a->bgimage_rb_out[0]=a->bgimage_rb_out[1]=1;
|
|
|
|
int w=a->bgimage->getWidth();
|
|
int h=a->bgimage->getHeight();
|
|
if (w>1&&h>1 && LICE_GetPixel(a->bgimage,0,0)==LICE_RGBA(255,0,255,255) &&
|
|
LICE_GetPixel(a->bgimage,w-1,h-1)==LICE_RGBA(255,0,255,255))
|
|
{
|
|
int x;
|
|
for (x = 1; x < w && LICE_GetPixel(a->bgimage,x,0)==LICE_RGBA(255,0,255,255); x ++);
|
|
a->bgimage_lt[0] = x;
|
|
for (x = w-2; x >= a->bgimage_lt[0]+1 && LICE_GetPixel(a->bgimage,x,h-1)==LICE_RGBA(255,0,255,255); x --);
|
|
a->bgimage_rb[0] = w-1-x;
|
|
|
|
for (x = 1; x < h && LICE_GetPixel(a->bgimage,0,x)==LICE_RGBA(255,0,255,255); x ++);
|
|
a->bgimage_lt[1] = x;
|
|
for (x = h-2; x >= a->bgimage_lt[1]+1 && LICE_GetPixel(a->bgimage,w-1,x)==LICE_RGBA(255,0,255,255); x --);
|
|
a->bgimage_rb[1] = h-1-x;
|
|
}
|
|
else if (w>1&&h>1 && LICE_GetPixel(a->bgimage,0,0)==LICE_RGBA(255,255,0,255) &&
|
|
LICE_GetPixel(a->bgimage,w-1,h-1)==LICE_RGBA(255,255,0,255))
|
|
{
|
|
|
|
bool hadPink=false;
|
|
|
|
//graphic image contains an outside area -- must contain at least one pink pixel in its definition or we assume it's just a yellow image...
|
|
int x, x2, x3;
|
|
for (x = 1, x2 = 0, x3 = 0; x < w; x++)
|
|
{
|
|
LICE_pixel p = LICE_GetPixel(a->bgimage,x,0);
|
|
if(p==LICE_RGBA(255,0,255,255)) { hadPink=true; x2++; }
|
|
else if(p==LICE_RGBA(255,255,0,255)) { x3+=x2+1; x2=0; }
|
|
else break;
|
|
}
|
|
a->bgimage_lt[0] = x2+1;
|
|
a->bgimage_lt_out[0] = x3+1;
|
|
for (x = w-2, x2 = 0, x3 = 0; x >= a->bgimage_lt[0]+1; x--)
|
|
{
|
|
LICE_pixel p = LICE_GetPixel(a->bgimage,x,h-1);
|
|
if(p==LICE_RGBA(255,0,255,255)) { hadPink=true; x2++; }
|
|
else if(p==LICE_RGBA(255,255,0,255)) { x3+=x2+1; x2=0; }
|
|
else break;
|
|
}
|
|
a->bgimage_rb[0] = x2+1;
|
|
a->bgimage_rb_out[0] = x3+1;
|
|
|
|
for (x = 1, x2 = 0, x3 = 0; x < h;x++)
|
|
{
|
|
LICE_pixel p = LICE_GetPixel(a->bgimage,0,x);
|
|
if(p==LICE_RGBA(255,0,255,255)) { hadPink=true; x2++; }
|
|
else if(p==LICE_RGBA(255,255,0,255)) { x3+=x2+1; x2=0; }
|
|
else break;
|
|
}
|
|
a->bgimage_lt[1] = x2+1;
|
|
a->bgimage_lt_out[1] = x3+1;
|
|
for (x = h-2, x2 = 0, x3 = 0; x >= a->bgimage_lt[1]+1; x --)
|
|
{
|
|
LICE_pixel p = LICE_GetPixel(a->bgimage,w-1,x);
|
|
if(p==LICE_RGBA(255,0,255,255)) { hadPink=true; x2++; }
|
|
else if(p==LICE_RGBA(255,255,0,255)) { x3+=x2+1; x2=0; }
|
|
else break;
|
|
}
|
|
a->bgimage_rb[1] = x2+1;
|
|
a->bgimage_rb_out[1] = x3+1;
|
|
if (!hadPink) // yellow by itself isnt enough, need at least a bit of pink.
|
|
{
|
|
a->bgimage_lt[0]=a->bgimage_lt[1]=a->bgimage_rb[0]=a->bgimage_rb[1]=0;
|
|
a->bgimage_lt_out[0]=a->bgimage_lt_out[1]=a->bgimage_rb_out[0]=a->bgimage_rb_out[1]=1;
|
|
}
|
|
}
|
|
|
|
|
|
int flags=0xffff;
|
|
LICE_pixel_chan *ch = (LICE_pixel_chan *) a->bgimage->getBits();
|
|
int span = a->bgimage->getRowSpan()*4;
|
|
if (a->bgimage->isFlipped())
|
|
{
|
|
ch += span*(h-1);
|
|
span=-span;
|
|
}
|
|
|
|
// not sure if this works yet -- it needs more testing for sure
|
|
bool isFull=true;
|
|
if (a->bgimage_lt[0] ||a->bgimage_lt[1] || a->bgimage_rb[0] || a->bgimage_rb[1])
|
|
{
|
|
isFull=false;
|
|
ch += span; // skip a line
|
|
ch += 4; // skip a column
|
|
h-=2;
|
|
w-=2;
|
|
}
|
|
|
|
// points at which we change to the next block
|
|
int xdivs[3] = { a->bgimage_lt[0]+a->bgimage_lt_out[0]-2,
|
|
w-a->bgimage_rb[0]-a->bgimage_rb_out[0]+2,
|
|
w-a->bgimage_rb_out[0]+1};
|
|
int ydivs[3] = { a->bgimage_lt[1]+a->bgimage_lt_out[1]-2,
|
|
h-a->bgimage_rb[1]-a->bgimage_rb_out[1]+2,
|
|
h-a->bgimage_rb_out[1]+1};
|
|
|
|
int y,ystate=0;
|
|
for(y=0;y<h;y++)
|
|
{
|
|
while (ystate<3 && y>=ydivs[ystate]) ystate++;
|
|
int xstate=0;
|
|
|
|
int x;
|
|
LICE_pixel_chan *chptr = ch + LICE_PIXEL_A;
|
|
for (x=0;x<w;x++)
|
|
{
|
|
while (xstate<3 && x>=xdivs[xstate]) xstate++;
|
|
|
|
if (*chptr != 255)
|
|
{
|
|
if (isFull)
|
|
{
|
|
flags=0;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
flags &= ~(1<<(ystate*4 + xstate));
|
|
if (!flags) break;
|
|
}
|
|
}
|
|
chptr+=4;
|
|
}
|
|
if (!flags) break;
|
|
|
|
ch += span;
|
|
}
|
|
|
|
a->bgimage_noalphaflags=flags;
|
|
|
|
}
|
|
|
|
static void __VirtClipBlit(int clipx, int clipy, int clipright, int clipbottom,
|
|
LICE_IBitmap *dest, LICE_IBitmap *src, int dstx, int dsty, int dstw, int dsth,
|
|
int _srcx, int _srcy, int _srcw, int _srch, float alpha, int mode)
|
|
{
|
|
if (dstw<1||dsth<1 || dstx+dstw < clipx || dstx > clipright ||
|
|
dsty+dsth < clipy || dsty > clipbottom)
|
|
{
|
|
return; // dont draw if fully outside
|
|
}
|
|
|
|
double srcx = (double) _srcx;
|
|
double srcy = (double) _srcy;
|
|
double srcw = (double) _srcw;
|
|
double srch = (double) _srch;
|
|
|
|
if (dstx < clipx || dsty < clipy || dstx+dstw > clipright || dsty+dsth > clipbottom)
|
|
{
|
|
double xsc=srcw/dstw;
|
|
double ysc=srch/dsth;
|
|
|
|
if (dstx<clipx)
|
|
{
|
|
int diff=clipx-dstx;
|
|
srcx += xsc*diff;
|
|
srcw -= xsc*diff;
|
|
dstw -= diff;
|
|
dstx += diff;
|
|
}
|
|
if (dsty<clipy)
|
|
{
|
|
int diff=clipy-dsty;
|
|
srcy += ysc*diff;
|
|
srch -= ysc*diff;
|
|
dsth -= diff;
|
|
dsty += diff;
|
|
}
|
|
if (dstx+dstw > clipright)
|
|
{
|
|
int diff = dstx+dstw-clipright; //clipright-dstx-dstw;
|
|
dstw -= diff;
|
|
srcw -= diff*xsc;
|
|
}
|
|
if (dsty+dsth > clipbottom)
|
|
{
|
|
int diff = dsty+dsth-clipbottom; //clipbottom-dsty-dsth;
|
|
dsth -= diff;
|
|
srch -= diff*ysc;
|
|
}
|
|
|
|
}
|
|
|
|
if (dstw>0&&dsth>0)
|
|
{
|
|
const double eps=0.0005;
|
|
if (srcw > 0.0 && srcw < eps) srcw=eps;
|
|
if (srch > 0.0 && srch < eps) srch=eps;
|
|
LICE_ScaledBlit(dest,src,dstx,dsty,dstw,dsth,(float)srcx,(float)srcy,(float)srcw,(float)srch,alpha,mode);
|
|
}
|
|
}
|
|
|
|
void WDL_VirtualWnd_ScaledBlitSubBG(LICE_IBitmap *dest,
|
|
WDL_VirtualWnd_BGCfg *src,
|
|
int destx, int desty, int destw, int desth,
|
|
int clipx, int clipy, int clipw, int cliph,
|
|
int srcx, int srcy, int srcw, int srch, // these coordinates are not including pink lines (i.e. if pink lines are present, use src->bgimage->getWidth()-2, etc)
|
|
float alpha, int mode)
|
|
{
|
|
if (!src || !src->bgimage) return;
|
|
|
|
int adj=2;
|
|
if (src->bgimage_lt[0] < 1 || src->bgimage_lt[1] < 1 || src->bgimage_rb[0] < 1 || src->bgimage_rb[1] < 1)
|
|
{
|
|
adj=0;
|
|
}
|
|
if (srcx == 0 && srcy == 0 && srcw+adj >= src->bgimage->getWidth() && srch+adj >= src->bgimage->getHeight())
|
|
{
|
|
WDL_VirtualWnd_ScaledBlitBG(dest,src,destx,desty,destw,desth,clipx,clipy,clipw,cliph,alpha,mode);
|
|
return;
|
|
}
|
|
|
|
LICE_SubBitmap bm(src->bgimage,srcx,srcy,srcw+adj,srch+adj);
|
|
WDL_VirtualWnd_BGCfg ts = *src;
|
|
ts.bgimage = &bm;
|
|
|
|
if ((ts.bgimage_noalphaflags&0xffff)!=0xffff) ts.bgimage_noalphaflags=0; // force alpha channel if any alpha
|
|
|
|
WDL_VirtualWnd_ScaledBlitBG(dest,&ts,destx,desty,destw,desth,clipx,clipy,clipw,cliph,alpha,mode);
|
|
}
|
|
|
|
void WDL_VirtualWnd_ScaledBlitBG(LICE_IBitmap *dest,
|
|
WDL_VirtualWnd_BGCfg *src,
|
|
int destx, int desty, int destw, int desth,
|
|
int clipx, int clipy, int clipw, int cliph,
|
|
float alpha, int mode)
|
|
{
|
|
// todo: blit clipping optimizations
|
|
if (!src || !src->bgimage) return;
|
|
|
|
int left_margin=src->bgimage_lt[0];
|
|
int top_margin=src->bgimage_lt[1];
|
|
int right_margin=src->bgimage_rb[0];
|
|
int bottom_margin=src->bgimage_rb[1];
|
|
|
|
int sw=src->bgimage->getWidth();
|
|
int sh=src->bgimage->getHeight();
|
|
|
|
int clipright=clipx+clipw;
|
|
int clipbottom=clipy+cliph;
|
|
|
|
if (clipx<destx) clipx=destx;
|
|
if (clipy<desty) clipy=desty;
|
|
if (clipright>destx+destw) clipright=destx+destw;
|
|
if (clipbottom>desty+desth) clipbottom=desty+desth;
|
|
|
|
if (left_margin<1||top_margin<1||right_margin<1||bottom_margin<1)
|
|
{
|
|
float xsc=(float)sw/destw;
|
|
float ysc=(float)sh/desth;
|
|
|
|
if (mode&LICE_BLIT_USE_ALPHA)
|
|
{
|
|
if ((src->bgimage_noalphaflags & 0xffff)==0xffff)
|
|
{
|
|
mode &= ~LICE_BLIT_USE_ALPHA;
|
|
}
|
|
}
|
|
|
|
|
|
LICE_ScaledBlit(dest,src->bgimage,
|
|
clipx,clipy,clipright-clipx,clipbottom-clipy,
|
|
(clipx-destx)*xsc,
|
|
(clipy-desty)*ysc,
|
|
(clipright-clipx)*xsc,
|
|
(clipbottom-clipy)*ysc,
|
|
alpha,mode);
|
|
|
|
return;
|
|
}
|
|
|
|
WDL_ASSERT(src->bgimage_lt_out[0]>0); // if pinklines are nonzero, yellowlines must be too (they are all 1-based)
|
|
WDL_ASSERT(src->bgimage_lt_out[1]>0); // if these fire, check for uninitialized bgimage_lt_out etc
|
|
WDL_ASSERT(src->bgimage_rb_out[0]>0);
|
|
WDL_ASSERT(src->bgimage_rb_out[1]>0);
|
|
|
|
const int left_margin_out = src->bgimage_lt_out[0]-1;
|
|
const int top_margin_out = src->bgimage_lt_out[1]-1;
|
|
const int right_margin_out = src->bgimage_rb_out[0]-1;
|
|
const int bottom_margin_out = src->bgimage_rb_out[1]-1;
|
|
|
|
// remove 1px additional margins from calculations
|
|
left_margin--; top_margin--; right_margin--; bottom_margin--;
|
|
|
|
if (left_margin+right_margin>destw)
|
|
{
|
|
int w=left_margin+right_margin;
|
|
left_margin = destw*left_margin/wdl_max(w,1);
|
|
right_margin=destw-left_margin;
|
|
}
|
|
if (top_margin+bottom_margin>desth)
|
|
{
|
|
int h=(top_margin+bottom_margin);
|
|
top_margin=desth*top_margin/wdl_max(h,1);
|
|
bottom_margin=desth-top_margin;
|
|
}
|
|
|
|
int no_alpha_flags=src->bgimage_noalphaflags;
|
|
int pass;
|
|
int nbpass = 3;
|
|
if (bottom_margin_out>0)
|
|
nbpass = 4;
|
|
|
|
bool no_inside = !!(mode & WDL_VWND_SCALEDBLITBG_IGNORE_INSIDE);
|
|
bool no_outside = !!(mode & WDL_VWND_SCALEDBLITBG_IGNORE_OUTSIDE);
|
|
|
|
bool no_lr=!!(mode & WDL_VWND_SCALEDBLITBG_IGNORE_LR);
|
|
|
|
int __sc = (int) dest->Extended(LICE_EXT_GET_ADVISORY_SCALING,NULL);
|
|
if (__sc < 1) __sc=256;
|
|
const int lm = (left_margin*__sc)>>8,
|
|
rm = (right_margin*__sc)>>8,
|
|
lmod = (left_margin_out*__sc)>>8,
|
|
rmod = (right_margin_out*__sc)>>8;
|
|
|
|
for (pass=(top_margin_out> 0 ? -1 : 0); pass<nbpass; pass++)
|
|
{
|
|
int outy, outh;
|
|
int iny, inh;
|
|
int this_clipy = clipy;
|
|
switch (pass)
|
|
{
|
|
case -1: // top margin
|
|
outh = (top_margin_out*__sc) >> 8;
|
|
outy = desty - outh;
|
|
this_clipy-=outh;
|
|
iny=1;
|
|
inh=top_margin_out;
|
|
break;
|
|
case 0:
|
|
outy=desty;
|
|
outh=(top_margin*__sc) >> 8;
|
|
iny=1+top_margin_out;
|
|
inh=src->bgimage_lt[1]-1;
|
|
break;
|
|
case 1:
|
|
outy=desty+((top_margin*__sc)>>8);
|
|
outh=desty+desth-outy-((bottom_margin*__sc)>>8);
|
|
iny=src->bgimage_lt[1]+top_margin_out;
|
|
inh=sh-src->bgimage_rb[1]-bottom_margin_out - iny;
|
|
break;
|
|
case 2:
|
|
outh=(bottom_margin*__sc)>>8;
|
|
outy=desty+desth-outh;
|
|
iny=sh - src->bgimage_rb[1] - bottom_margin_out;
|
|
inh=src->bgimage_rb[1]-1;
|
|
break;
|
|
case 3:
|
|
outh=(bottom_margin_out*__sc)>>8;
|
|
clipbottom += outh;
|
|
outy=desty+desth;
|
|
iny=sh-1-bottom_margin_out;
|
|
inh=bottom_margin_out;
|
|
break;
|
|
}
|
|
bool is_outer = pass<0 || pass>=3;
|
|
|
|
if (no_outside && is_outer)
|
|
{
|
|
}
|
|
else if (outh > 0 && inh > 0)
|
|
{
|
|
|
|
if (no_lr)
|
|
{
|
|
__VirtClipBlit(clipx,this_clipy,clipright,clipbottom,dest,src->bgimage,destx,outy,
|
|
destw,outh,
|
|
src->bgimage_lt[0]+left_margin_out,iny,
|
|
sw-src->bgimage_lt[0]-src->bgimage_rb[0]-left_margin_out - right_margin_out,
|
|
inh,alpha,(no_alpha_flags&2) ? (mode&~LICE_BLIT_USE_ALPHA) : mode);
|
|
}
|
|
else
|
|
{
|
|
// left
|
|
if (left_margin_out>0 && !no_outside)
|
|
{
|
|
__VirtClipBlit(clipx-lmod,this_clipy,clipright,clipbottom,dest,src->bgimage,destx-lmod,outy,lmod,outh,
|
|
1,iny,left_margin_out,inh,alpha,
|
|
(no_alpha_flags&1) ? (mode&~LICE_BLIT_USE_ALPHA) : mode);
|
|
}
|
|
|
|
if (!no_inside||is_outer)
|
|
{
|
|
if (left_margin > 0)
|
|
__VirtClipBlit(clipx,this_clipy,clipright,clipbottom,dest,src->bgimage,destx,outy,lm,outh,
|
|
1+left_margin_out,iny,src->bgimage_lt[0]-1,inh,alpha,
|
|
(no_alpha_flags&1) ? (mode&~LICE_BLIT_USE_ALPHA) : mode);
|
|
|
|
|
|
// center
|
|
__VirtClipBlit(clipx,this_clipy,clipright,clipbottom,dest,src->bgimage,destx+lm,outy,
|
|
destw-rm-lm,outh,
|
|
src->bgimage_lt[0]+left_margin_out,iny,
|
|
sw-src->bgimage_lt[0]-src->bgimage_rb[0]-right_margin_out-left_margin_out,
|
|
inh,alpha,(no_alpha_flags&2) ? (mode&~LICE_BLIT_USE_ALPHA) : mode);
|
|
// right
|
|
if (right_margin > 0)
|
|
__VirtClipBlit(clipx,this_clipy,clipright,clipbottom,dest,src->bgimage,destx+destw-rm,outy, rm,outh,
|
|
sw-src->bgimage_rb[0]-right_margin_out,iny,
|
|
src->bgimage_rb[0]-1,inh,alpha,(no_alpha_flags&4) ? (mode&~LICE_BLIT_USE_ALPHA) : mode);
|
|
}
|
|
|
|
// right outside area
|
|
if (right_margin_out>0 && !no_outside)
|
|
{
|
|
__VirtClipBlit(clipx,this_clipy,clipright+rmod,clipbottom,dest,src->bgimage,destx+destw,outy,rmod,outh,
|
|
sw-right_margin_out-1,iny,
|
|
right_margin_out,inh,alpha,(no_alpha_flags&8) ? (mode&~LICE_BLIT_USE_ALPHA) : mode);
|
|
}
|
|
|
|
}
|
|
}
|
|
if (pass>=0)
|
|
no_alpha_flags>>=4;
|
|
}
|
|
}
|
|
|
|
int WDL_VirtualWnd_ScaledBG_GetPix(WDL_VirtualWnd_BGCfg *src,
|
|
int ww, int wh,
|
|
int x, int y)
|
|
{
|
|
if (!src->bgimage) return 0;
|
|
int imgw=src->bgimage->getWidth();
|
|
int imgh=src->bgimage->getHeight();
|
|
|
|
int left_margin=src->bgimage_lt[0];
|
|
int top_margin=src->bgimage_lt[1];
|
|
int right_margin=src->bgimage_rb[0];
|
|
int bottom_margin=src->bgimage_rb[1];
|
|
|
|
if (left_margin<1||top_margin<1||right_margin<1||bottom_margin<1)
|
|
{
|
|
if (ww<1)ww=1;
|
|
x=(x * imgw)/ww;
|
|
if (wh<1)wh=1;
|
|
y=(y * imgh)/wh;
|
|
}
|
|
else
|
|
{
|
|
// remove 1px additional margins from calculations
|
|
left_margin--; top_margin--; right_margin--; bottom_margin--;
|
|
int destw=ww,desth=wh;
|
|
if (left_margin+right_margin>destw)
|
|
{
|
|
int w=left_margin+right_margin;
|
|
left_margin = destw*left_margin/wdl_max(w,1);
|
|
right_margin=destw-left_margin;
|
|
}
|
|
if (top_margin+bottom_margin>desth)
|
|
{
|
|
int h=(top_margin+bottom_margin);
|
|
top_margin=desth*top_margin/wdl_max(h,1);
|
|
bottom_margin=desth-top_margin;
|
|
}
|
|
|
|
if (x >= ww-right_margin) x=imgw-1- (ww-x);
|
|
else if (x >= left_margin)
|
|
{
|
|
int xd=ww-left_margin-right_margin;
|
|
if (xd<1)xd=1;
|
|
x=src->bgimage_lt[0] +
|
|
(x-left_margin) * (imgw-src->bgimage_lt[0]-src->bgimage_rb[0])/xd;
|
|
}
|
|
else x++;
|
|
|
|
if (y >= wh-bottom_margin) y=imgh -1- (wh-y);
|
|
else if (y >= top_margin)
|
|
{
|
|
int yd=wh-top_margin-bottom_margin;
|
|
if (yd<1)yd=1;
|
|
y=src->bgimage_lt[1] +
|
|
(y-top_margin) * (imgh-src->bgimage_lt[1]-src->bgimage_rb[1])/yd;
|
|
}
|
|
else y++;
|
|
}
|
|
|
|
return LICE_GetPixel(src->bgimage,x,y);
|
|
}
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
static WNDPROC vwndDlgHost_oldProc;
|
|
static LRESULT CALLBACK vwndDlgHost_newProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (msg==WM_ERASEBKGND) return 1;
|
|
if (msg==WM_PAINT ||
|
|
(msg == WM_SETFOCUS && (GetWindowLong(hwnd,GWL_STYLE)&(WS_CHILD|WS_TABSTOP))==(WS_CHILD|WS_TABSTOP))
|
|
)
|
|
{
|
|
WNDPROC pc=(WNDPROC)GetWindowLongPtr(hwnd,DWLP_DLGPROC);
|
|
if (pc)
|
|
{
|
|
CallWindowProc(pc,hwnd,msg,wParam,lParam);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return CallWindowProc(vwndDlgHost_oldProc,hwnd,msg,wParam,lParam);
|
|
}
|
|
|
|
#endif
|
|
|
|
void WDL_VWnd_regHelperClass(const char *classname, void *icon1, void *icon2)
|
|
{
|
|
#ifdef _WIN32
|
|
static bool reg;
|
|
if (reg) return;
|
|
|
|
reg=true;
|
|
|
|
WNDCLASSEX wc={sizeof(wc),};
|
|
GetClassInfoEx(NULL,"#32770",&wc);
|
|
wc.lpszClassName = (char*)classname;
|
|
if (icon1) wc.hIcon = (HICON)icon1;
|
|
if (icon2) wc.hIconSm = (HICON)icon2;
|
|
vwndDlgHost_oldProc=wc.lpfnWndProc;
|
|
wc.lpfnWndProc=vwndDlgHost_newProc;
|
|
RegisterClassEx(&wc);
|
|
#endif
|
|
}
|
|
|
|
bool wdl_virtwnd_nosetcursorpos;
|