2014-09-27 09:25:14 +02:00
|
|
|
#define __STL_CONFIG_H
|
|
|
|
#include "pixmapcontainer.h"
|
|
|
|
#include "../config.h"
|
|
|
|
|
|
|
|
cMutex cPixmapContainer::mutex;
|
|
|
|
cOsd *cPixmapContainer::osd = NULL;
|
|
|
|
eFlushState cPixmapContainer::flushState = fsOpen;
|
|
|
|
|
|
|
|
cPixmapContainer::cPixmapContainer(int numPixmaps) {
|
|
|
|
this->numPixmaps = numPixmaps;
|
|
|
|
pixContainerInit = true;
|
|
|
|
mutex.Lock();
|
|
|
|
pixmaps = new cPixmap*[numPixmaps];
|
|
|
|
pixmapsTransparency = new int[numPixmaps];
|
|
|
|
for(int i=0; i < numPixmaps; i++) {
|
|
|
|
pixmaps[i] = NULL;
|
|
|
|
pixmapsTransparency[i] = 0;
|
|
|
|
}
|
|
|
|
mutex.Unlock();
|
|
|
|
checkRunning = false;
|
|
|
|
fadeTime = 0;
|
|
|
|
deleteOsdOnExit = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
cPixmapContainer::~cPixmapContainer(void) {
|
|
|
|
for (int i=0; i < numPixmaps; i++) {
|
|
|
|
mutex.Lock();
|
|
|
|
if (pixmaps[i] && osd) {
|
|
|
|
osd->DestroyPixmap(pixmaps[i]);
|
|
|
|
pixmaps[i] = NULL;
|
|
|
|
}
|
|
|
|
mutex.Unlock();
|
|
|
|
}
|
|
|
|
delete[] pixmaps;
|
|
|
|
delete[] pixmapsTransparency;
|
|
|
|
if (deleteOsdOnExit && osd) {
|
|
|
|
mutex.Lock();
|
|
|
|
delete osd;
|
|
|
|
osd = NULL;
|
|
|
|
mutex.Unlock();
|
|
|
|
}
|
2014-11-02 10:35:29 +01:00
|
|
|
flushState = fsOpen;
|
2014-09-27 09:25:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool cPixmapContainer::CreateOsd(int Left, int Top, int Width, int Height) {
|
|
|
|
if (osd) {
|
2015-01-18 12:03:06 +01:00
|
|
|
return false;
|
2014-09-27 09:25:14 +02:00
|
|
|
}
|
|
|
|
cOsd *newOsd = cOsdProvider::NewOsd(Left, Top);
|
|
|
|
if (newOsd) {
|
|
|
|
tArea Area = { 0, 0, Width, Height, 32 };
|
|
|
|
if (newOsd->SetAreas(&Area, 1) == oeOk) {
|
|
|
|
osd = newOsd;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-18 09:11:11 +02:00
|
|
|
void cPixmapContainer::LockFlush(void) {
|
2014-09-27 09:25:14 +02:00
|
|
|
flushState = fsLock;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::OpenFlush(void) {
|
|
|
|
flushState = fsOpen;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cPixmapContainer::PixmapExists(int num) {
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (pixmaps[num])
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::DoFlush(void) {
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!osd || (checkRunning && !Running()))
|
|
|
|
return;
|
|
|
|
if (flushState == fsOpen) {
|
|
|
|
osd->Flush();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::CreatePixmap(int num, int Layer, const cRect &ViewPort, const cRect &DrawPort) {
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!osd || (checkRunning && !Running()))
|
|
|
|
return;
|
|
|
|
pixmaps[num] = osd->CreatePixmap(Layer, ViewPort, DrawPort);
|
|
|
|
pixmaps[num]->Fill(clrTransparent);
|
|
|
|
if (pixContainerInit && fadeTime) {
|
|
|
|
pixmaps[num]->SetAlpha(0);
|
|
|
|
} else if (pixmapsTransparency[num] > 0) {
|
|
|
|
int alpha = (100 - pixmapsTransparency[num])*255/100;
|
|
|
|
pixmaps[num]->SetAlpha(alpha);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cPixmapContainer::DestroyPixmap(int num) {
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (pixmaps[num] && osd) {
|
|
|
|
osd->DestroyPixmap(pixmaps[num]);
|
|
|
|
pixmaps[num] = NULL;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::DrawText(int num, const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, std::string fontName, int fontSize) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return;
|
|
|
|
fontManager->Lock();
|
|
|
|
cFont *font = fontManager->Font(fontName, fontSize);
|
|
|
|
if (font)
|
|
|
|
pixmaps[num]->DrawText(Point, s, ColorFg, ColorBg, font);
|
|
|
|
fontManager->Unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void cPixmapContainer::DrawRectangle(int num, const cRect &Rect, tColor Color) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return;
|
|
|
|
pixmaps[num]->DrawRectangle(Rect, Color);
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::DrawEllipse(int num, const cRect &Rect, tColor Color, int Quadrants) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return;
|
|
|
|
pixmaps[num]->DrawEllipse(Rect, Color, Quadrants);
|
|
|
|
}
|
|
|
|
|
2014-10-25 16:58:05 +02:00
|
|
|
void cPixmapContainer::DrawSlope(int num, const cRect &Rect, tColor Color, int Type) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return;
|
|
|
|
pixmaps[num]->DrawSlope(Rect, Color, Type);
|
|
|
|
}
|
|
|
|
|
2014-09-27 09:25:14 +02:00
|
|
|
void cPixmapContainer::DrawImage(int num, const cPoint &Point, const cImage &Image) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return;
|
|
|
|
pixmaps[num]->DrawImage(Point, Image);
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::DrawBitmap(int num, const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool Overlay) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return;
|
|
|
|
pixmaps[num]->DrawBitmap(Point, Bitmap, ColorFg, ColorBg, Overlay);
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::Fill(int num, tColor Color) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return;
|
|
|
|
pixmaps[num]->Fill(Color);
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::SetAlpha(int num, int Alpha) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return;
|
|
|
|
pixmaps[num]->SetAlpha(Alpha);
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::SetTransparency(int num, int Transparency) {
|
|
|
|
if (Transparency < 0 && Transparency > 100)
|
|
|
|
return;
|
|
|
|
pixmapsTransparency[num] = Transparency;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::SetLayer(int num, int Layer) {
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return;
|
|
|
|
pixmaps[num]->SetLayer(Layer);
|
|
|
|
}
|
|
|
|
|
2015-02-12 18:50:58 +01:00
|
|
|
void cPixmapContainer::SetViewPort(int num, const cRect &rect) {
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return;
|
|
|
|
pixmaps[num]->SetViewPort(rect);
|
|
|
|
}
|
|
|
|
|
2014-09-27 09:25:14 +02:00
|
|
|
int cPixmapContainer::Width(int num) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return 0;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return 0;
|
|
|
|
int width = pixmaps[num]->ViewPort().Width();
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cPixmapContainer::Height(int num) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return 0;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return 0;
|
|
|
|
int height = pixmaps[num]->ViewPort().Height();
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cPixmapContainer::DrawportWidth(int num) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return 0;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return 0;
|
|
|
|
int width = pixmaps[num]->DrawPort().Width();
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cPixmapContainer::DrawportHeight(int num) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return 0;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return 0;
|
|
|
|
int height = pixmaps[num]->DrawPort().Height();
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cPixmapContainer::DrawportX(int num) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return 0;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return 0;
|
|
|
|
int x = pixmaps[num]->DrawPort().X();
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cPixmapContainer::DrawportY(int num) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return 0;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return 0;
|
|
|
|
int y = pixmaps[num]->DrawPort().Y();
|
|
|
|
return y;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::SetDrawPortPoint(int num, const cPoint &Point) {
|
|
|
|
if (checkRunning && !Running())
|
|
|
|
return;
|
|
|
|
cMutexLock MutexLock(&mutex);
|
|
|
|
if (!pixmaps[num])
|
|
|
|
return;
|
|
|
|
pixmaps[num]->SetDrawPortPoint(Point);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* HELPERS -- do not access the pixmaps array directly, use wrapper functions
|
|
|
|
* to ensure that a proper lock is set before accessing pixmaps
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void cPixmapContainer::FadeIn(void) {
|
|
|
|
if (!fadeTime)
|
|
|
|
return;
|
|
|
|
uint64_t Start = cTimeMs::Now();
|
|
|
|
int FadeFrameTime = fadeTime / 10;
|
|
|
|
while (Running()) {
|
|
|
|
uint64_t Now = cTimeMs::Now();
|
|
|
|
double t = min(double(Now - Start) / fadeTime, 1.0);
|
|
|
|
int Alpha = t * ALPHA_OPAQUE;
|
|
|
|
for (int i = 0; i < numPixmaps; i++) {
|
|
|
|
if (!PixmapExists(i))
|
|
|
|
continue;
|
|
|
|
if (pixmapsTransparency[i] > 0) {
|
|
|
|
int alpha = (100 - pixmapsTransparency[i])*Alpha/100;
|
|
|
|
SetAlpha(i, alpha);
|
|
|
|
} else {
|
|
|
|
SetAlpha(i, Alpha);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DoFlush();
|
|
|
|
int Delta = cTimeMs::Now() - Now;
|
|
|
|
if (Running() && (Delta < FadeFrameTime))
|
|
|
|
cCondWait::SleepMs(FadeFrameTime - Delta);
|
|
|
|
if ((int)(Now - Start) > fadeTime)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::FadeOut(void) {
|
|
|
|
if (!fadeTime)
|
|
|
|
return;
|
|
|
|
uint64_t Start = cTimeMs::Now();
|
|
|
|
int FadeFrameTime = fadeTime / 10;
|
|
|
|
while (true) {
|
|
|
|
uint64_t Now = cTimeMs::Now();
|
|
|
|
double t = min(double(Now - Start) / fadeTime, 1.0);
|
|
|
|
int Alpha = (1 - t) * ALPHA_OPAQUE;
|
|
|
|
for (int i = 0; i < numPixmaps; i++) {
|
|
|
|
if (!PixmapExists(i))
|
|
|
|
continue;
|
|
|
|
if (pixmapsTransparency[i] > 0) {
|
|
|
|
int alpha = (100 - pixmapsTransparency[i])*Alpha/100;
|
|
|
|
SetAlpha(i, alpha);
|
|
|
|
} else {
|
|
|
|
SetAlpha(i, Alpha);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DoFlush();
|
|
|
|
int Delta = cTimeMs::Now() - Now;
|
|
|
|
if (Running() && (Delta < FadeFrameTime))
|
|
|
|
cCondWait::SleepMs(FadeFrameTime - Delta);
|
|
|
|
if ((int)(Now - Start) > fadeTime)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************
|
|
|
|
* scrollSpeed: 1 slow
|
|
|
|
* 2 medium
|
|
|
|
* 3 fast
|
|
|
|
******************************************/
|
|
|
|
void cPixmapContainer::ScrollHorizontal(int num, int scrollDelay, int scrollSpeed, int scrollMode) {
|
|
|
|
bool carriageReturn = (scrollMode == 1) ? true : false;
|
|
|
|
|
|
|
|
int scrollDelta = 1;
|
|
|
|
int drawPortX;
|
|
|
|
|
|
|
|
int FrameTime = 0;
|
|
|
|
if (scrollSpeed == 1)
|
|
|
|
FrameTime = 50;
|
|
|
|
else if (scrollSpeed == 2)
|
|
|
|
FrameTime = 30;
|
|
|
|
else
|
|
|
|
FrameTime = 15;
|
|
|
|
if (!Running())
|
|
|
|
return;
|
|
|
|
int maxX = DrawportWidth(num) - Width(num);
|
|
|
|
bool doSleep = false;
|
|
|
|
while (Running()) {
|
|
|
|
if (doSleep) {
|
|
|
|
DoSleep(scrollDelay);
|
|
|
|
doSleep = false;
|
|
|
|
}
|
|
|
|
if (!Running())
|
|
|
|
return;
|
|
|
|
uint64_t Now = cTimeMs::Now();
|
|
|
|
drawPortX = DrawportX(num);
|
|
|
|
drawPortX -= scrollDelta;
|
|
|
|
|
|
|
|
if (abs(drawPortX) > maxX) {
|
|
|
|
DoSleep(scrollDelay);
|
|
|
|
if (carriageReturn)
|
|
|
|
drawPortX = 0;
|
|
|
|
else {
|
|
|
|
scrollDelta *= -1;
|
|
|
|
drawPortX -= scrollDelta;
|
|
|
|
}
|
|
|
|
doSleep = true;
|
|
|
|
}
|
|
|
|
if (!carriageReturn && (drawPortX == 0)) {
|
|
|
|
scrollDelta *= -1;
|
|
|
|
doSleep = true;
|
|
|
|
}
|
|
|
|
SetDrawPortPoint(num, cPoint(drawPortX, 0));
|
|
|
|
int Delta = cTimeMs::Now() - Now;
|
|
|
|
DoFlush();
|
|
|
|
if (Running() && (Delta < FrameTime))
|
|
|
|
cCondWait::SleepMs(FrameTime - Delta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************
|
|
|
|
* scrollSpeed: 1 slow
|
|
|
|
* 2 medium
|
|
|
|
* 3 fast
|
|
|
|
******************************************/
|
|
|
|
void cPixmapContainer::ScrollVertical(int num, int scrollDelay, int scrollSpeed) {
|
|
|
|
if (!scrollSpeed)
|
|
|
|
return;
|
|
|
|
DoSleep(scrollDelay);
|
|
|
|
int drawPortY;
|
|
|
|
int FrameTime = 0;
|
|
|
|
if (scrollSpeed == 1)
|
|
|
|
FrameTime = 50;
|
|
|
|
else if (scrollSpeed == 2)
|
|
|
|
FrameTime = 30;
|
|
|
|
else
|
|
|
|
FrameTime = 15;
|
|
|
|
int maxY = DrawportHeight(num) - Height(num);
|
|
|
|
bool doSleep = false;
|
|
|
|
while (Running()) {
|
|
|
|
if (doSleep) {
|
|
|
|
doSleep = false;
|
|
|
|
DoSleep(scrollDelay);
|
|
|
|
}
|
|
|
|
uint64_t Now = cTimeMs::Now();
|
|
|
|
drawPortY = DrawportY(num);
|
|
|
|
drawPortY -= 1;
|
|
|
|
if (abs(drawPortY) > maxY) {
|
|
|
|
doSleep = true;
|
|
|
|
DoSleep(scrollDelay);
|
|
|
|
drawPortY = 0;
|
|
|
|
}
|
|
|
|
SetDrawPortPoint(num, cPoint(0, drawPortY));
|
|
|
|
if (doSleep) {
|
|
|
|
DoSleep(scrollDelay);
|
|
|
|
}
|
|
|
|
int Delta = cTimeMs::Now() - Now;
|
|
|
|
DoFlush();
|
|
|
|
if (Running() && (Delta < FrameTime))
|
|
|
|
cCondWait::SleepMs(FrameTime - Delta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::CancelSave(void) {
|
|
|
|
Cancel(-1);
|
|
|
|
while (Active())
|
|
|
|
cCondWait::SleepMs(10);
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::DoSleep(int duration) {
|
|
|
|
int sleepSlice = 10;
|
|
|
|
for (int i = 0; Running() && (i*sleepSlice < duration); i++)
|
|
|
|
cCondWait::SleepMs(sleepSlice);
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::DrawBlendedBackground(int num, int xStart, int width, tColor color, tColor colorBlending, bool fromTop) {
|
|
|
|
int height = Height(num);
|
|
|
|
int numSteps = 16;
|
|
|
|
int alphaStep = 0x0F;
|
|
|
|
int alpha = 0x00;
|
|
|
|
int step, begin, end;
|
|
|
|
if (fromTop) {
|
|
|
|
step = 1;
|
|
|
|
begin = 0;
|
|
|
|
end = numSteps;
|
|
|
|
} else {
|
|
|
|
step = -1;
|
|
|
|
begin = height;
|
|
|
|
end = height - numSteps;
|
|
|
|
}
|
|
|
|
tColor clr;
|
|
|
|
bool cont = true;
|
|
|
|
for (int i = begin; cont; i = i + step) {
|
|
|
|
clr = AlphaBlend(color, colorBlending, alpha);
|
|
|
|
DrawRectangle(num, cRect(xStart,i,width,1), clr);
|
|
|
|
alpha += alphaStep;
|
|
|
|
if (i == end)
|
|
|
|
cont = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::DrawRoundedCorners(int num, int radius, int x, int y, int width, int height) {
|
|
|
|
if (radius > 2) {
|
|
|
|
DrawEllipse(num, cRect(x, y, radius, radius), clrTransparent, -2);
|
|
|
|
DrawEllipse(num, cRect(x + width - radius, y , radius, radius), clrTransparent, -1);
|
|
|
|
DrawEllipse(num, cRect(x, y + height - radius, radius, radius), clrTransparent, -3);
|
|
|
|
DrawEllipse(num, cRect(x + width - radius, y + height - radius, radius, radius), clrTransparent, -4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPixmapContainer::DrawRoundedCornersWithBorder(int num, tColor borderColor, int radius, int width, int height) {
|
|
|
|
if (radius < 3)
|
|
|
|
return;
|
|
|
|
DrawEllipse(num, cRect(0,0,radius,radius), borderColor, -2);
|
|
|
|
DrawEllipse(num, cRect(-1,-1,radius,radius), clrTransparent, -2);
|
|
|
|
|
|
|
|
DrawEllipse(num, cRect(width-radius,0,radius,radius), borderColor, -1);
|
|
|
|
DrawEllipse(num, cRect(width-radius+1,-1,radius,radius), clrTransparent, -1);
|
|
|
|
|
|
|
|
DrawEllipse(num, cRect(0,height-radius,radius,radius), borderColor, -3);
|
|
|
|
DrawEllipse(num, cRect(-1,height-radius+1,radius,radius), clrTransparent, -3);
|
|
|
|
|
|
|
|
DrawEllipse(num, cRect(width-radius,height-radius,radius,radius), borderColor, -4);
|
|
|
|
DrawEllipse(num, cRect(width-radius+1,height-radius+1,radius,radius), clrTransparent, -4);
|
|
|
|
}
|