Collision handling in Win32 application - winapi

After i draw many circle i want handle collisions between a circle but i don't know how to do it . And I want the color of the circle is random . I use function RGB() but it doesn't work . Please help me ! . Thanks .
My code
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
HBRUSH brush;
HBRUSH hBrush;
HPEN hPen;
static int dX[10] , dY[10] ;
static int x[10], y[10], oldX[10], oldY[10];
switch (message)
{
case WM_CREATE:
SetTimer(hWnd, 1, 3, NULL);
Beep(750, 300);
for (int i = 0; i < 10; i++){
dX[i] = rand() % 15 + 0;
dY[i] = rand() % 15 + 0;
x[i] = rand() % 15 + 0;
y[i] = rand() % 15 + 0;
oldX[i] = x[i];
oldY[i] = y[i];
}
break;
case WM_TIMER:
hdc = GetDC(hWnd);
brush = (HBRUSH)SelectObject(hdc, GetStockObject(WHITE_BRUSH));
RECT temp[10];
RECT rect;
GetClientRect(hWnd, &rect);
brush = (HBRUSH)SelectObject(hdc, GetStockObject(RGB(rand() % 255 + 0, rand() % 255 + 0, rand() % 255 + 0)));
for (int i = 0; i <10; i++){
temp[i].left = oldX[i];
temp[i].top = oldY[i];
temp[i].right = oldX[i] + 30;
temp[i].bottom = oldY[i] + 30;
FillRect(hdc, &temp[i], brush);
Ellipse(hdc, x[i], y[i], 30 + x[i], 30 + y[i]);
oldX[i] = x[i];
oldY[i] = y[i];
x[i] += dX[i];
y[i] += dY[i];
if (x[i] + 30 > rect.right || x[i] < 0)
{
dX[i] = -dX[i];
}
if (y[i] + 30 > rect.bottom || y[i] < 0)
{
dY[i] = -dY[i];
}
}
SelectObject(hdc, brush);
ReleaseDC(hWnd, hdc);
break;
My picture Demo here .
http://www.upsieutoc.com/images/2014/07/14/289ccd.jpg

Related

Windows.h GDI - BITMAPINFO alloca indicates failure

I want to create an image from the desktop and set it to gray using BITMAPINFO, but it keeps showing me the warning, "Warning C6255 _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead".
I would appreciate any advice.
HBITMAP CreateGreyscaleBitmap(int cx, int cy)
{
BITMAPINFO* pbmi = (BITMAPINFO*)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = cx;
pbmi->bmiHeader.biHeight = cy;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 8;
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = 0;
pbmi->bmiHeader.biXPelsPerMeter = 14173;
pbmi->bmiHeader.biYPelsPerMeter = 14173;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;
for (int i = 0; i < 256; i++)
{
pbmi->bmiColors[i].rgbRed = i;
pbmi->bmiColors[i].rgbGreen = i;
pbmi->bmiColors[i].rgbBlue = i;
pbmi->bmiColors[i].rgbReserved = 0;
}
PVOID pv;
return CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, &pv, NULL, 0);
}

Creating 24-bit BITMAP in Winapi

I'm using the following code in order to convert my ImageMagick image to 32-bit HBITMAP:
BITMAP bitmap;
std::memset(&bitmap, 0, sizeof(bitmap));
bitmap.bmType = 0;
bitmap.bmWidth = image->image()->columns;
bitmap.bmHeight = image->image()->rows;
bitmap.bmWidthBytes = 4 * bitmap.bmWidth;
bitmap.bmPlanes = 1;
bitmap.bmBitsPixel = 32;
bitmap.bmBits = NULL;
const size_t size = bitmap.bmWidthBytes * bitmap.bmHeight;
auto buffer = (HANDLE)GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
RGBQUAD *bitmap_bits = (RGBQUAD *) GlobalLock((HGLOBAL) buffer);
register RGBQUAD *q = bitmap_bits;
for (size_t y = 0; y < image->image()->rows; y++)
{
register auto p = GetVirtualPixels(image->image(), 0, y, image->image()->columns, 1, exception);
if (!p) break;
for (size_t x = 0; x < image->image()->columns; x++)
{
q->rgbRed = ScaleQuantumToChar(GetPixelRed(image->image(), p));
q->rgbGreen = ScaleQuantumToChar(GetPixelGreen(image->image(), p));
q->rgbBlue = ScaleQuantumToChar(GetPixelBlue(image->image(), p));
q->rgbReserved = 0;
p += GetPixelChannels(image->image());
q++;
}
}
bitmap.bmBits = bitmap_bits;
HBITMAP hbmp = CreateBitmapIndirect(&bitmap);
It works well, but I'd like to save some memory by using images with lower depth. Unfortunately I'm not even able to make it work with 24-bit images. I modified my code to look like this:
BITMAP bitmap;
std::memset(&bitmap, 0, sizeof(bitmap));
bitmap.bmType = 0;
bitmap.bmWidth = image->image()->columns;
bitmap.bmHeight = image->image()->rows;
bitmap.bmWidthBytes = ((bitmap.bmWidth * 24 + 31) / 32) * 4;
bitmap.bmPlanes = 1;
bitmap.bmBitsPixel = 24;
bitmap.bmBits = NULL;
const size_t length = bitmap.bmWidthBytes * bitmap.bmHeight;
auto buffer = (HANDLE)GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, length);
RGBTRIPLE *bitmap_bits = (RGBTRIPLE *) GlobalLock((HGLOBAL) buffer);
register RGBTRIPLE *q = bitmap_bits;
for (size_t y = 0; y < image->image()->rows; y++)
{
register auto p = GetVirtualPixels(image->image(), 0, y, image->image()->columns, 1, exception);
if (!p) break;
for (size_t x = 0; x < image->image()->columns; x++)
{
q->rgbtRed = ScaleQuantumToChar(GetPixelRed(image->image(), p));
q->rgbtGreen = ScaleQuantumToChar(GetPixelGreen(image->image(), p));
q->rgbtBlue = ScaleQuantumToChar(GetPixelBlue(image->image(), p));
p += GetPixelChannels(image->image());
q++;
}
}
bitmap.bmBits = bitmap_bits;
HBITMAP hbmp = CreateBitmapIndirect(&bitmap);
But it seems that this code cannot produce valid bitmap. What am I doing wrong?
You are not taking the stride/alignment into account. Each row needs to be DWORD aligned.
Calculating Surface Stride
In an uncompressed bitmap, the stride is the number of bytes needed to go from the start of one row of pixels to the start of the next row. The image format defines a minimum stride for an image. In addition, the graphics hardware might require a larger stride for the surface that contains the image.
For uncompressed RGB formats, the minimum stride is always the image width in bytes, rounded up to the nearest DWORD. You can use the following formula to calculate the stride:
stride = ((((biWidth * biBitCount) + 31) & ~31) >> 3)
You need to fix the way you access the RGBTRIPLEs in the buffer.
Before the "x loop" you should do something like q = (RGBTRIPLE*) (((char*)bitmap_bits) + (y * bitmap.bmWidthBytes));
CreateBitmapIndirect creates a DDB which is perhaps not the best choice, create a DIB instead:
#define CalcStride(w, bpp) ( ((((w) * (bpp)) + 31) & ~31) >> 3 )
static void SetPixel24(UINT w, void*bits, UINT x, UINT y, COLORREF cr)
{
RGBTRIPLE*p = ((RGBTRIPLE*) ( ((char*)bits) + (y * CalcStride(w, 24)) )) + x;
p->rgbtRed = GetRValue(cr);
p->rgbtGreen = GetGValue(cr);
p->rgbtBlue = GetBValue(cr);
}
void Silly24BPPExample()
{
HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, WC_STATIC, 0, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_OVERLAPPEDWINDOW|SS_BITMAP|SS_REALSIZECONTROL, 0, 0, 99, 99, 0, 0, 0, 0);
const INT w = 4, h = 4, bpp = 24;
BITMAPINFO bi;
ZeroMemory(&bi, sizeof(bi));
BITMAPINFOHEADER&bih = bi.bmiHeader;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = w, bih.biHeight = -h;
bih.biPlanes = 1, bih.biBitCount = bpp;
bih.biCompression = BI_RGB;
void*bits;
HBITMAP hBmp = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &bits, NULL, 0);
for (UINT x = 0; x < w; ++x)
for (UINT y = 0; y < h; ++y)
SetPixel24(w, bits, x, y, RGB(255, 0, 0)); // All red
SetPixel24(w, bits, 0, 0, RGB(0, 0, 255)); // except one blue
SendMessage(hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hBmp);
for (MSG msg; IsWindow(hWnd) && GetMessage(&msg, 0, 0, 0); ) DispatchMessage(&msg);
// DeleteObject(...)
}

The breakpoint will not currently be hit. No executable code of the debbuger's target code type is

Intro: Code does not work in Release mode. Works in Debug.
This shows on one of my breakpoints:
Code spot is:
void Font::operator<<(std::string s)
{
this->printf(s); // this line
}
This method is called like this:
float oneframe;
oneframe = (double)elapsed/ 1000000.0;
float ffps =1. / oneframe;
int fps = ffps;
char txt[200];
sprintf(txt, "%d FPS", fps);
font << txt; // displays text
Printf is:
void Font::printf(std::string s)
{
UINT lines = 0;
std::vector<float> offsetX;
float offsetY=0;
UINT length = s.size();
XMMATRIX M = XMMatrixScaling(m_scaling.x, m_scaling.y, m_scaling.z)*
XMMatrixTranslation(m_translation.x, m_translation.y, m_translation.z);
float fontLength=0;
float fontHeight = 60.0f / windowHeight;
float fontWidth = 60.0f / windowWidth * 0.6f;
m_deviceContext->VSSetShader(m_vertexShader, 0, 0);
m_deviceContext->IASetInputLayout(m_inputLayout);
m_deviceContext->PSSetShader(m_pixelShader, 0, 0);
m_deviceContext->PSSetShaderResources(0, 1, &m_texture);
m_deviceContext->PSSetSamplers(0, 1, &m_sampler);
m_deviceContext->OMSetDepthStencilState(m_dsOff, 1);
if (m_anchor != TOP_LEFT)
{
float offset = 0;
for (int i = 0; i < length; i++)
{
offset += m_kerning*widthMap[s[i]];
if (s[i] == '\n' || s[i] == '\r' || i == length - 1)
{
offsetX.push_back(offset);
offset = 0;
}
}
}
for (int i = 0; i < length; i++)
{
XMFLOAT3 TL(-1, 1, 0), BR(1, -1, 0);
XMVECTOR vTL, vBR;
if (s[i] == '\n' || s[i] == '\r')
{
fontLength = 0;
lines++;
continue;
}
switch (m_anchor)
{
default:
case TOP_LEFT:
vTL = XMVector3TransformCoord(XMLoadFloat3(&XMFLOAT3(fontLength, -m_leading*lines, 0)), M);
vBR = XMVector3TransformCoord(XMLoadFloat3(&XMFLOAT3(fontWidth + fontLength, -m_leading*lines - fontHeight, 0)), M);
break;
case TOP_RIGHT:
vTL = XMVector3TransformCoord(XMLoadFloat3(&XMFLOAT3(fontLength - offsetX[lines], -m_leading*lines, 0)), M);
vBR = XMVector3TransformCoord(XMLoadFloat3(&XMFLOAT3(fontWidth + fontLength - offsetX[lines], -m_leading*lines - fontHeight, 0)), M);
break;
case BOTTOM_LEFT:
offsetY = m_leading*offsetX.size();
vTL = XMVector3TransformCoord(XMLoadFloat3(&XMFLOAT3(fontLength, -m_leading*lines+ offsetY, 0)), M);
vBR = XMVector3TransformCoord(XMLoadFloat3(&XMFLOAT3(fontWidth + fontLength, -m_leading*lines - fontHeight+ offsetY, 0)), M);
break;
case BOTTOM_RIGHT:
offsetY = m_leading*offsetX.size();
vTL = XMVector3TransformCoord(XMLoadFloat3(&XMFLOAT3(fontLength - offsetX[lines], -m_leading*lines + offsetY, 0)), M);
vBR = XMVector3TransformCoord(XMLoadFloat3(&XMFLOAT3(fontWidth + fontLength - offsetX[lines], -m_leading*lines - fontHeight + offsetY, 0)), M);
break;
case CENTER:
{
offsetY = m_leading*offsetX.size() / 2;
float halfOffsetx = offsetX[lines] / 2;
vTL = XMVector3TransformCoord(XMLoadFloat3(&XMFLOAT3(fontLength - halfOffsetx, -m_leading*lines + offsetY, 0)), M);
vBR = XMVector3TransformCoord(XMLoadFloat3(&XMFLOAT3(fontWidth + fontLength - halfOffsetx, -m_leading*lines - fontHeight + offsetY, 0)), M);
break;
}
}
XMStoreFloat3(&TL, vTL);
XMStoreFloat3(&BR, vBR);
assert(updateBuffer(TL, BR, fontMap[s[i]]));
UINT stride, offset;
stride = sizeof(SimpleVertex);
offset = 0;
m_deviceContext->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset);
m_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_deviceContext->Draw(6, 0);
fontLength += m_kerning*widthMap[s[i]];
}
m_deviceContext->OMSetDepthStencilState(m_dsOn, 1);
}
Here's where it gets weird. I get this notification while in Release mode. The code above completely works, in Debug. For whatever reason, it does not work when I switch to Release. I've checked the txtvariable that is being sent to the function, it has text. To me, it seems as if the code has somehow been optimized out or something.
I have also deleted everything in the Debug and Release folders and did a fresh Build. Nothing. I've tested the executables without running from VS, same result. Debugging in Release shows that there is text in txt but I can't determine what happens as the debugger seems to float right over font << txt.
I did find out the answer. There is an assert used in printf near the end. Asserts do not run in Release. Only in debug.

Rescaling image in J2ME

I'm resizing a bird image using the following code:
private Image resizeImage(Image src) {
int srcWidth = src.getWidth();
int srcHeight = src.getHeight();
int screenWidth=getWidth()/3;
int screenHeight=getHeight()/3;
Image tmp = Image.createImage(screenWidth, srcHeight);
Graphics g = tmp.getGraphics();
int ratio = (srcWidth << 16) / screenWidth;
int pos = ratio/2;
//Horizontal Resize
for (int x = 0; x < screenWidth; x++) {
g.setClip(x, 0, 1, srcHeight);
g.drawImage(src, x - (pos >> 16), 0, Graphics.LEFT | Graphics.TOP);
pos += ratio;
}
Image resizedImage = Image.createImage(screenWidth, screenHeight);
g = resizedImage.getGraphics();
ratio = (srcHeight << 16) / screenHeight;
pos = ratio/2;
//Vertical resize
for (int y = 0; y < screenHeight; y++) {
g.setClip(0, y, screenWidth, 1);
g.drawImage(tmp, 0, y - (pos >> 16), Graphics.LEFT | Graphics.TOP);
pos += ratio;
}
return resizedImage;
}
The image is resized but it has white background along with it as shown. How to get only resized image with transparent background..?
Here is an Image scaling function I've been using. Includes transparency. Found here: http://willperone.net/Code/codescaling.php
public Image scale(Image original, int newWidth, int newHeight) {
int[] rawInput = new int[original.getHeight() * original.getWidth()];
original.getRGB(rawInput, 0, original.getWidth(), 0, 0, original.getWidth(), original.getHeight());
int[] rawOutput = new int[newWidth * newHeight];
// YD compensates for the x loop by subtracting the width back out
int YD = (original.getHeight() / newHeight) * original.getWidth() - original.getWidth();
int YR = original.getHeight() % newHeight;
int XD = original.getWidth() / newWidth;
int XR = original.getWidth() % newWidth;
int outOffset = 0;
int inOffset = 0;
for (int y = newHeight, YE = 0; y > 0; y--) {
for (int x = newWidth, XE = 0; x > 0; x--) {
rawOutput[outOffset++] = rawInput[inOffset];
inOffset += XD;
XE += XR;
if (XE >= newWidth) {
XE -= newWidth;
inOffset++;
}
}
inOffset += YD;
YE += YR;
if (YE >= newHeight) {
YE -= newHeight;
inOffset += original.getWidth();
}
}
rawInput = null;
return Image.createRGBImage(rawOutput, newWidth, newHeight, true);
}

Rendering subscript using DrawText or similar function

The question is simple. How to draw following text into TStringGrid cell?
Operating system is Windows XP (or Windows Vista or Windows 7). Preferred development environment is C++ Builder 6, but I will accept also solutions for C++ Builder XE of Delphi. Preferred API function is DrawText, but if better function exists than this no problem. Font name is Times New Roman, font size is 11. Currently I am using this method to render cell content (simplified):
void __fastcall TForm_Main::StringGrid_DrawCell(TObject *Sender,
int ACol, int ARow, TRect &Rect, TGridDrawState State)
{
TStringGrid *grid = (TStringGrid*)Sender;
if (grid == NULL) return;
// 1. BACKGROUND
grid->Canvas->Brush->Color = grid->Color;
grid->Canvas->FillRect(Rect);
// 2. TEXT
grid->Canvas->Font->Assign(grid->Font); // Times New Roman, 11pt
// horizontal centering
RECT RText = static_cast<RECT>(Rect);
AnsiString text = grid->Cells[ACol][ARow];
if (!text.IsEmpty()) {
int text_len = strlen(text.c_str());
SIZE size;
memset(&size, 0, sizeof(SIZE));
GetTextExtentPoint32(grid->Canvas->Handle, text.c_str(), text_len, &size);
int offset_x = (Rect.Width() - size.cx) >> 1;
RText.left += offset_x; RText.right += offset_x;
// rendering
DrawText(grid->Canvas->Handle, text.c_str(), text_len, &RText, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
}
}
Some characters have subscript glyph as special unicode character (for example code 0x2081 is assigned to subscript one) but unfortunately this is not case for capital letter U. Also these characters are not supported by all fonts (for example Times New Roman font doesnt support code range 0x2070 - 209F), see this Wikipedia article. I am searching for a more general solution like those implemented by Microsoft Word. MS Word doesn't have problem to render capital letter U as subscript using Times New Roman font.
If you want some char to render as superscript you must prefix it with ^. Likewise subscript characters must be prefixed with _.
void __fastcall TForm_Main::StringGrid_DrawCell(TObject *Sender, int ACol, int ARow, TRect &Rect, TGridDrawState State)
{
TStringGrid *grid = (TStringGrid*)Sender;
if (grid == NULL)
{
return;
}
WideString wtext = L"φ_U = 120";
if (wtext.IsEmpty()) return;
// layout
SIZE size;
memset(&size, 0, sizeof(SIZE));
SSGetTextExtentPoint(grid->Canvas, wtext, size);
int offset_x = (Rect.Width() - size.cx + 1) >> 1; // horizontal centering
RECT RText = static_cast<RECT>(Rect);
RText.left += offset_x;
RText.right += offset_x;
// rendering
SetBkMode(grid->Canvas->Handle, TRANSPARENT);
SSDrawText(grid->Canvas, wtext, RText, DT_LEFT);
}
int TForm_Main::SSGetTextExtentPoint(TCanvas *canvas, WideString text, SIZE &size)
{
// Source: http://www.codeproject.com/Articles/12660/Using-Subscripts-and-Superscripts-When-Showing-Tex
SaveDC(canvas->Handle);
SIZE sz;
RECT outRect =
{0, 0, 0, 0};
HFONT oldFont;
LOGFONT lf;
GetObject(canvas->Font->Handle, sizeof(LOGFONT), &lf);
POINT sub, sup, subofs, supofs;
// Calculate subscript/superscript size and offsets
bool use_pixel_unit = false;
if (lf.lfHeight < 0)
{
lf.lfHeight = MulDiv(-lf.lfHeight, 72, GetDeviceCaps(canvas->Handle, LOGPIXELSY));
use_pixel_unit = true;
}
sub.x = lf.lfWidth / 2;
sup.x = lf.lfWidth / 2;
sub.y = lf.lfHeight / 3 * 2;
sup.y = lf.lfHeight / 3 * 2;
subofs.x = lf.lfWidth / 2;
supofs.x = lf.lfWidth / 2;
subofs.y = lf.lfHeight / 6;
supofs.y = lf.lfHeight / 3;
lf.lfWidth = sub.x;
lf.lfHeight = sub.y;
if (use_pixel_unit)
{
lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(canvas->Handle, LOGPIXELSY), 72);
}
HFONT SubFont;
SubFont = CreateFontIndirect(&lf);
lf.lfWidth = sup.x;
lf.lfHeight = sup.y;
HFONT SupFont;
if (use_pixel_unit)
{
lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(canvas->Handle, LOGPIXELSY), 72);
}
SupFont = CreateFontIndirect(&lf);
WideString temp = text;
TCHAR c;
// Calculate the size of the text that needs to be displayed
do
{
int x1 = 1, x2 = 1, x = 1;
WideString s = "";
c = ' ';
bool bFind = true;
// Find the first "^" or "_", indicating the sub- or superscript
while (bFind)
{
x1 = text.Pos(L"^");
x2 = text.Pos(L"_");
if ((x1 == 0) && (x2 == 0))
{
x = 0;
}
else if ((x1 > 0) && (x2 > 0))
{
x = min(x1, x2);
}
else if (x1 > 0)
{
x = x1;
}
else
{
x = x2;
}
if (x == 0)
{
bFind = false;
x = text.Length() + 1;
}
else if (x == text.Length())
{
bFind = false;
}
else if (text[x] != text[x + 1])
{
bFind = false;
c = text[x];
}
else
{
x++;
}
s = s + text.SubString(1, x - 1);
text.Delete(1, min(x, text.Length()));
}
sz = canvas->TextExtent(s);
outRect.right += sz.cx;
if ((outRect.bottom - outRect.top) < sz.cy)
{
outRect.top = outRect.bottom - sz.cy;
}
switch (c)
{
case '^':
oldFont = (HFONT)SelectObject(canvas->Handle, SupFont);
GetTextExtentPoint32W(canvas->Handle, text.c_bstr(), 1, &sz);
outRect.right += sz.cx + supofs.x;
text.Delete(1, 1);
SelectObject(canvas->Handle, oldFont);
break;
case '_':
oldFont = (HFONT)SelectObject(canvas->Handle, SubFont);
GetTextExtentPoint32W(canvas->Handle, text.c_bstr(), 1, &sz);
outRect.right += sz.cx + subofs.x;
text.Delete(1, 1);
SelectObject(canvas->Handle, oldFont);
break;
}
}
while (c != ' ');
// Adjust text position
outRect.bottom += subofs.y;
outRect.top -= subofs.x;
size.cx = outRect.right - outRect.left;
size.cy = outRect.bottom - outRect.top;
DeleteObject(SubFont);
DeleteObject(SupFont);
// Done, restoring the device context
RestoreDC(canvas->Handle, -1);
return 0;
}
// ---------------------------------------------------------------------------
int TForm_Main::SSDrawText(TCanvas *canvas, WideString text, RECT &drawRect, int justification)
{
// Source: http://www.codeproject.com/Articles/12660/Using-Subscripts-and-Superscripts-When-Showing-Tex
SaveDC(canvas->Handle);
SIZE sz;
RECT outRect =
{0, 0, 0, 0};
HFONT oldFont;
LOGFONT lf;
GetObject(canvas->Font->Handle, sizeof(LOGFONT), &lf);
POINT sub, sup, subofs, supofs;
bool contains_subscript = false;
bool contains_superscript = false;
// Calculate subscript/superscript size and offsets
bool use_pixel_unit = false;
if (lf.lfHeight < 0)
{
lf.lfHeight = MulDiv(-lf.lfHeight, 72, GetDeviceCaps(canvas->Handle, LOGPIXELSY));
use_pixel_unit = true;
}
sub.x = (lf.lfWidth + 1) >> 1;
sup.x = (lf.lfWidth + 1) >> 1;
sub.y = (lf.lfHeight << 1) / 3;
sup.y = (lf.lfHeight << 1) / 3;
if (lf.lfHeight == 10)
{
sub.y++; // make subscript a little larger
}
subofs.x = (lf.lfWidth + 1) >> 1;
supofs.x = (lf.lfWidth + 1) >> 1;
subofs.y = (lf.lfHeight + 3) / 6;
supofs.y = (lf.lfHeight) / 3;
long sub_shift_down = lf.lfHeight - sub.y;
lf.lfWidth = sub.x;
lf.lfHeight = sub.y;
if (use_pixel_unit)
{
lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(canvas->Handle, LOGPIXELSY), 72);
}
HFONT SubFont;
SubFont = CreateFontIndirect(&lf);
lf.lfWidth = sup.x;
lf.lfHeight = sup.y;
if (use_pixel_unit)
{
lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(canvas->Handle, LOGPIXELSY), 72);
}
HFONT SupFont;
SupFont = CreateFontIndirect(&lf);
WideString temp = text;
TCHAR c;
// Calculate the size of the text that needs to be displayed
do
{
int x1 = 1, x2 = 1, x = 1;
WideString s = "";
c = ' ';
bool bFind = true;
// Find the first "^" or "_", indicating the sub- or superscript
while (bFind)
{
x1 = text.Pos(L"^");
x2 = text.Pos(L"_");
if ((x1 == 0) && (x2 == 0))
{
x = 0;
}
else if ((x1 > 0) && (x2 > 0))
{
x = min(x1, x2);
}
else if (x1 > 0)
{
x = x1;
}
else
{
x = x2;
}
if (x == 0)
{
bFind = false;
x = text.Length() + 1;
}
else if (x == text.Length())
{
bFind = false;
}
else if (text[x] != text[x + 1])
{
bFind = false;
c = text[x];
}
else
{
x++;
}
s = s + text.SubString(1, x - 1);
text.Delete(1, min(x, text.Length()));
}
sz = canvas->TextExtent(s);
outRect.right += sz.cx;
if ((outRect.bottom - outRect.top) < sz.cy)
{
outRect.top = outRect.bottom - sz.cy;
}
switch (c)
{
case '^':
oldFont = (HFONT)SelectObject(canvas->Handle, SupFont);
GetTextExtentPoint32W(canvas->Handle, text.c_bstr(), 1, &sz);
outRect.right += sz.cx + supofs.x;
text.Delete(1, 1);
SelectObject(canvas->Handle, oldFont);
contains_superscript = true;
break;
case '_':
oldFont = (HFONT)SelectObject(canvas->Handle, SubFont);
GetTextExtentPoint32W(canvas->Handle, text.c_bstr(), 1, &sz);
outRect.right += sz.cx + subofs.x;
text.Delete(1, 1);
SelectObject(canvas->Handle, oldFont);
contains_subscript = true;
break;
}
}
while (c != ' ');
// Adjust text position
if (contains_subscript)
{
outRect.bottom += subofs.y;
}
if (contains_superscript)
{
outRect.top -= supofs.y;
}
POINT Origin;
Origin.y = drawRect.top + (((drawRect.bottom - drawRect.top) - (outRect.bottom - outRect.top) + 1) >> 1);
switch (justification)
{
case DT_CENTER:
Origin.x = (drawRect.right - drawRect.left) / 2 - (outRect.right - outRect.left) / 2 + drawRect.left;
break;
case DT_LEFT:
Origin.x = drawRect.left;
break;
case DT_RIGHT:
Origin.x = drawRect.right - (outRect.right - outRect.left);
}
POINT pnt = Origin;
text = temp;
// Draw text
do
{
int x1 = 1, x2 = 1, x = 1;
WideString s = "";
c = ' ';
bool bFind = true;
// Find the first "^" or "_", indicating the sub- or superscript
while (bFind)
{
x = text.Pos(L"^_");
x1 = text.Pos(L"^");
x2 = text.Pos(L"_");
if ((x1 == 0) && (x2 == 0))
{
x = 0;
}
else if ((x1 > 0) && (x2 > 0))
{
x = min(x1, x2);
}
else if (x1 > 0)
{
x = x1;
}
else
{
x = x2;
}
if (x == 0)
{
bFind = false;
x = text.Length() + 1;
}
else if (x == text.Length())
{
bFind = false;
}
else if (text[x] != text[x + 1])
{
bFind = false;
c = text[x];
}
else
{
x++;
}
s = s + text.SubString(1, x - 1);
text.Delete(1, min(x, text.Length()));
}
// Draw main text
ExtTextOutW(canvas->Handle, pnt.x, pnt.y, 0, &drawRect, s.c_bstr(), s.Length(), NULL);
GetTextExtentPoint32W(canvas->Handle, s.c_bstr(), s.Length(), &sz);
pnt.x += sz.cx;
// Draw subscript or superscript
switch (c)
{
case '^':
oldFont = (HFONT)SelectObject(canvas->Handle, SupFont);
ExtTextOutW(canvas->Handle, pnt.x + supofs.x, pnt.y - supofs.y, 0, &drawRect, text.c_bstr(), 1, NULL);
GetTextExtentPoint32W(canvas->Handle, text.c_bstr(), 1, &sz);
pnt.x += sz.cx + supofs.x;
text.Delete(1, 1);
SelectObject(canvas->Handle, oldFont);
break;
case '_':
oldFont = (HFONT)SelectObject(canvas->Handle, SubFont);
ExtTextOutW(canvas->Handle, pnt.x + subofs.x, pnt.y + subofs.y + sub_shift_down, 0, &drawRect, text.c_bstr(), 1, NULL);
GetTextExtentPoint32W(canvas->Handle, text.c_bstr(), 1, &sz);
pnt.x += sz.cx + subofs.x;
text.Delete(1, 1);
SelectObject(canvas->Handle, oldFont);
break;
}
}
while (c != ' ');
DeleteObject(SubFont);
DeleteObject(SupFont);
// Done, restoring the device context
RestoreDC(canvas->Handle, -1);
return 0;
}
`
function SSTextLeft(ACanvas: TCanvas; ARect: TRect; const S: string): integer;
var
i,
h,
h3: integer;
sup,
sub: boolean;
begin
with ACanvas, ARect do begin
h:= textHeight('H');
h3:= h div 3;
brush.Style:= bsClear;
moveTo(Left +1, Top +1);
i:= 1;
while i < Length(s) +1 do begin
if s[i] = '^' then
begin
Inc(i);
font.Height:= MulDiv(font.Height, 8, 10);
textOut(penPos.X, penPos.Y -h3, s[i]);
moveTo(penPos.X +1, penPos.Y +h3);
font.Height:= h;
Inc(i);
end
else if s[i] = '_' then
begin
Inc(i);
font.Height:= MulDiv(font.Height, 8, 10);
textOut(penPos.X, penPos.Y +h3, s[i]);
moveTo(penPos.X +1, penPos.Y -h3);
font.Height:= h;
Inc(i);
end
else
begin
textOut(penPos.X, penPos.Y, s[i]);
Inc(i);
moveTo(penPos.X +1, penPos.Y);
end;
end;// while
end;
sup:= Pos('^', S) > 0;
sub:= Pos('_', S) > 0;
if sup and sub then
result:= MulDiv(h, 5, 3)
else if sup or sub then
result:= h +h3
else
result:= h;
end;// SSTextLeft
`

Resources