Toolbar in child window acting weird - winapi

Okay, so I'm using win32, with as few extra libraries as possible for the moment. My application is divided into multiple child windows using splitterbars, and I've added a toolbar and status bar to the main window. Now, I'm trying to add a toolbar to one of the child windows, and it works, but as soon as WM_SIZE happens, the buttons dissapear. This is all done in the WndProc for the Main window, by the way. Here's the code that creates the child window's toolbar:
toolRender = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS,
0, 0, 0, 0, wndRender, NULL, gHinst, 0);
SendMessage(toolRender, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
SendMessage(toolRender, CCM_SETVERSION, (WPARAM)5, 0);
himl = ImageList_LoadImage(NULL, L"buttons.bmp", 16, 2, RGB(0, 255, 255), IMAGE_BITMAP, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
SendMessage(toolRender, TB_SETIMAGELIST, 0, (LPARAM)himl);
TBBUTTON tbb2[2];
memset(tbb2, 0, sizeof(tbb2));
tbb2[0].iBitmap = 0;
tbb2[0].fsState = TBSTATE_ENABLED;
tbb2[0].fsStyle = TBSTYLE_BUTTON;
tbb2[0].idCommand = TOOL_SAVEALL;
tbb2[0].iString = (INT_PTR)L"Save All";
tbb2[1].iBitmap = 1;
tbb2[1].fsState = TBSTATE_ENABLED;
tbb2[1].fsStyle = TBSTYLE_BUTTON;
tbb2[1].idCommand = TOOL_HELP;
tbb2[1].iString = (INT_PTR)L"Help";
SendMessage(toolRender, TB_SETMAXTEXTROWS, 0, 0);
SendMessage(toolRender, TB_ADDBUTTONS, sizeof(tbb2)/sizeof(TBBUTTON), (LPARAM)&tbb2);
And here's my entire WM_SIZE message:
case WM_SIZE :
{
GetClientRect(hwnd, &rect);
// Resize toolbar
SendMessage(toolMain, TB_AUTOSIZE, 0, 0);
SendMessage(toolRender, TB_AUTOSIZE, 0, 0);
SendMessage(statusMain, WM_SIZE, 0, 0);
GetWindowRect(toolMain, &toolrect);
GetWindowRect(statusMain, &statusrect);
toolHeight = toolrect.bottom - toolrect.top;
statusHeight = statusrect.bottom - statusrect.top;
windowHeight = rect.bottom - rect.top;
GetWindowRect(toolRender, &toolrect);
toolRendHeight = toolrect.bottom - toolrect.top;
//Make sure window isn't too small
if (rect.right < MINSIZE * 4)
{
rect.right = MINSIZE * 4;
forceresize = true;
}
if (windowHeight < toolHeight + statusHeight + toolRendHeight + (MINSIZE * 2))
{
rect.bottom = toolHeight + statusHeight + toolRendHeight + (MINSIZE * 2);
forceresize = true;
}
//resize splitters
xDiv1 = rect.right * xDiv1p;
xDiv2 = rect.right * xDiv2p;
xDiv3 = rect.right * xDiv3p;
yDiv = rect.bottom * yDivp;
// Make sure splitters aren't beyond bounds
if (xDiv3 > rect.right - MINSIZE)
xDiv3 = rect.right - MINSIZE;
else if(xDiv3 < xDiv2 + MINSIZE)
xDiv3 = xDiv2 + MINSIZE;
if (xDiv2 > xDiv3 - MINSIZE)
xDiv2 = xDiv3 - MINSIZE;
else if (xDiv3 < xDiv1 + MINSIZE)
xDiv2 = xDiv1 + MINSIZE;
if (xDiv1 > xDiv2 - MINSIZE)
xDiv1 = xDiv2 - MINSIZE;
else if (xDiv1 < MINSIZE)
xDiv1 = MINSIZE;
if (yDiv > rect.bottom - MINSIZE)
yDiv = rect.bottom - MINSIZE;
else if(yDiv < MINSIZE + toolrect.bottom)
yDiv = MINSIZE + toolrect.bottom;
// Resize windows
MoveWindow(wndObjBrowser, 0, toolHeight, xDiv1 - SBS, windowHeight - toolHeight - statusHeight, FALSE);
MoveWindow(wndObjList, xDiv1 + SBS, toolHeight, xDiv2 - xDiv1 - (SBS * 2), windowHeight - toolHeight - statusHeight, FALSE);
if (!bDualMonitor)
{
MoveWindow(wndRender, xDiv2 + SBS, toolHeight, rect.right - xDiv2 - SBS, yDiv - toolHeight - SBS, FALSE);
//SendMessage(toolRender, TB_AUTOSIZE, 0, 0);
MoveWindow(wndAreaList, xDiv2 + SBS, yDiv + SBS, xDiv3 - xDiv2 - (SBS * 2), windowHeight - statusHeight - yDiv - SBS, FALSE);
MoveWindow(wndAreaInfo, xDiv3 + SBS, yDiv + SBS, rect.right - xDiv3 - SBS, windowHeight - statusHeight - yDiv - SBS, FALSE);
}
else if (bDualMonitor)
{
MoveWindow(wndAreaList, xDiv2 + SBS, toolHeight, rect.right - xDiv2 - SBS, yDiv - toolHeight, FALSE);
MoveWindow(wndAreaInfo, xDiv2 + SBS, yDiv + SBS, rect.right - xDiv2 - SBS, windowHeight - statusHeight - yDiv - SBS, FALSE);
}
if (forceresize)
MoveWindow(hwnd, rect.left, rect.top, rect.right, rect.bottom, FALSE);
InvalidateRect(hwnd, &rect, TRUE);
}
break; //WM_SIZE
Any ideas?

Why are you passing FALSE for the bRepaint parameter in most of the MoveWindow calls? The InvalidateRect at the end only invalidates the current window, not its children.

Related

Retrieving the palette of a bitmap image

I am loading a bitmap image from a file (type BMP) via the GDI function LoadImage, which returns a BITMAP handle.
I know how to access the bitmap bits. But the image is in the format 8BPP, hence palettized. How can I obtain the palette entries ?
Select the bitmap in to dc and call GetDIBColorTable. A temporary memory dc can be used here:
RGBQUAD rgb[256] = { 0 };
HDC memdc = CreateCompatibleDC(hdc);
auto oldbmp = SelectObject(memdc, hbitmap);
GetDIBColorTable(memdc, 0, 256, rgb);
SelectObject(memdc, oldbmp);
DeleteDC(memdc);
Alternatively use GetDIBits to read BITMAPINFO. You have to reserve enough memory to read the color table + all bytes + sizeof(BITMAPINFO).
Color table will be copied to BITMAPINFO -> bmiColors
Gdi+ is another option. Here is GDI example:
int main()
{
HBITMAP hbitmap = (HBITMAP)LoadImage(0, L"source.bmp",
IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
if (!hbitmap)
return 0;
BITMAP bm;
GetObject(hbitmap, sizeof(bm), &bm);
int width = bm.bmWidth;
int height = bm.bmHeight;
WORD clrbits = (WORD)(bm.bmPlanes * bm.bmBitsPixel);
if (clrbits == 8) clrbits = 1;
else if (clrbits <= 4) clrbits = 4;
else if (clrbits <= 8) clrbits = 8;
else if (clrbits <= 16) clrbits = 16;
else if (clrbits <= 24) clrbits = 24;
else clrbits = 32;
HDC hdc = GetDC(0);
if(clrbits == 8)
{
RGBQUAD rgb[256] = { 0 };
HDC memdc = CreateCompatibleDC(hdc);
auto oldbmp = SelectObject(memdc, hbitmap);
GetDIBColorTable(memdc, 0, 256, rgb);
SelectObject(memdc, oldbmp);
DeleteDC(memdc);
}
int palette_size = (clrbits < 24) ? sizeof(RGBQUAD) * (1 << clrbits) : 0;
BITMAPINFO* bmpinfo = (BITMAPINFO*)new BYTE[sizeof(BITMAPINFO) + palette_size];
int width_in_bytes = ((width * clrbits + 31) & ~31) / 8;
DWORD size = width_in_bytes * height;
bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpinfo->bmiHeader.biWidth = width;
bmpinfo->bmiHeader.biHeight = height;
bmpinfo->bmiHeader.biPlanes = bm.bmPlanes;
bmpinfo->bmiHeader.biBitCount = bm.bmBitsPixel;
bmpinfo->bmiHeader.biClrUsed = (clrbits < 24) ? (1 << clrbits) : 0;
bmpinfo->bmiHeader.biCompression = BI_RGB;
bmpinfo->bmiHeader.biSizeImage = size;
BYTE* bits = new BYTE[size];
GetDIBits(hdc, hbitmap, 0, height, bits, bmpinfo, 0);
//palette size should be 1024 for 256 color
//it should be stored in `bmpinfo->bmiColors`
delete[]bits;
delete[](BYTE*)bmpinfo;
DeleteObject(hbitmap);
ReleaseDC(0, hdc);
return 0;
}

How to generate the suggestion lines to align the rectangles along with group of other rectangles?

I have a grid-based system, think of it as a photoshop, There are draggable blocks in the system which can be moved around. I want to provide the lines of suggestion where the user can drop the block so that it is aligned with the appropriate block.
Here, in the video, the blue lines are being generated by such an algorithm. What is the name of this algorithm?
Example: from PandaDoc.
I don't know what algorithm is used here.
But I created a simple demo of the same using P5.js library.
The main logic is to consider each element a box and match it corners with the coordinates of the mouse.
const wOffset = draggableBox.w /2 ;
const hOffset = draggableBox.h / 2;
const currentPosX = mouseX - wOffset;
const currentPosY = mouseY - hOffset;
for(let i = 0; i<boxes.length ; i++){
stroke(boxes[i].color_);
noFill();
rect(boxes[i].x, boxes[i].y, boxes[i].w, boxes[i].h);
let diff = abs(currentPosX - boxes[i].x);
if(diff < 7){
stroke(255);
strokeWeight(2);
line(boxes[i].x, boxes[i].y, boxes[i].x, currentPosY);
}
diff = abs(currentPosY - boxes[i].y);
if(diff < 7){
stroke(255);
strokeWeight(2);
line(boxes[i].x, boxes[i].y, currentPosX, boxes[i].y);
}
diff = abs(currentPosX - (boxes[i].x + boxes[i].w));
if(diff < 7){
stroke(255);
strokeWeight(2);
line((boxes[i].x + boxes[i].w), boxes[i].y, (boxes[i].x + boxes[i].w), currentPosY);
}
diff = abs(currentPosX - (boxes[i].x + boxes[i].w/2));
if(diff < 7){
stroke(255);
strokeWeight(2);
line((boxes[i].x + boxes[i].w /2), boxes[i].y, (boxes[i].x + boxes[i].w /2), currentPosY);
}
diff = abs(currentPosY - (boxes[i].y + boxes[i].h));
if(diff < 7){
stroke(255);
strokeWeight(2);
line(boxes[i].x, (boxes[i].y + boxes[i].h), currentPosX, (boxes[i].y + boxes[i].h));
}
diff = abs(currentPosY - (boxes[i].y + boxes[i].h / 2));
if(diff < 7){
stroke(255);
strokeWeight(2);
line(boxes[i].x, (boxes[i].y + boxes[i].h / 2), currentPosX, (boxes[i].y + boxes[i].h / 2));
}
}
let diff = abs(currentPosX - width / 2);
if(diff < 1.5){
stroke(MOUSE_LINE_COLOR);
line(currentPosX, 0, currentPosX, currentPosY);
}
diff = abs(currentPosY - height / 2);
if(diff < 1.5) {
stroke(MOUSE_LINE_COLOR);
line(0, currentPosY, currentPosX, currentPosY);
}
stroke(color(255, 0, 0));
rect(mouseX - wOffset, mouseY - hOffset, draggableBox.w, draggableBox.h);
// line(0, mouseY, 600, mouseY);
You can find my github gist here.

How to draw curved text using MFC functions?

How to draw curved text using MFC functions? I want to achieve like this below.
DrawText() function draws text in straight line only, I do not know how to draw curved text at particular angle. Please help me.
Thanks.
You could use GDI+, There is a sample in code project, which is written in C#, I translate it into C++:
Graphics graphics(hWnd);
RECT rect = { 0 };
GetWindowRect(hWnd, &rect);
POINT center = { (rect.right - rect.left) / 2,(rect.bottom - rect.top) / 2 };
double radius = min(rect.right - rect.left, (rect.bottom - rect.top)) / 3;
TCHAR text[] = L"ABCDEFGHIJLKMNOPQRSTUVWXYZ";
REAL emSize = 24;
Font* font = new Font(FontFamily::GenericSansSerif(), emSize, FontStyleBold);
for (int i = 0; i < _tcslen(text); ++i)
{
RectF re, in;
Status result = graphics.MeasureString(&text[i], 1, font, in, &re);;
double charRadius = radius + re.Height;
double angle = (((float)i / _tcslen(text)) - 0.25) * 2 * M_PI;
double x = (int)(center.x + cos(angle) * charRadius);
double y = (int)(center.y + sin(angle) * charRadius);
result = graphics.TranslateTransform(x, y);
result = graphics.RotateTransform((float)(90 + 360 * angle / (2 * M_PI)));
PointF start(0, 0);
SolidBrush Red(Color(255, 255, 0, 0));
result = graphics.DrawString(&text[i], 1, font, start, &Red);
result = graphics.ResetTransform();
SolidBrush Green(Color(255, 0, 255, 0));
Pen* pen = new Pen(&Green, 2.0f);
result = graphics.DrawArc(pen, (REAL)(center.x - radius), (REAL)(center.y - radius), radius * 2, radius * 2, 0, 360);
}
Some header files:
#define _USE_MATH_DEFINES
#include <math.h>
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")
Usage:
You must call GdiplusStartup before you create any GDI+ objects, and
you must delete all of your GDI+ objects (or have them go out of
scope) before you call GdiplusShutdown.
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
//To Do.
GdiplusShutdown(gdiplusToken);
Result:
UPDATE:
Graphics graphics(hWnd);
RECT rect = { 0 };
GetWindowRect(hWnd, &rect);
POINT center = { (rect.right - rect.left) / 2,(rect.bottom - rect.top) / 2 };
double radius = min(rect.right - rect.left, (rect.bottom - rect.top)) / 3;
TCHAR text[72][4] = { 0 };
for (int i = 0; i < 72; i++)
{
_itot((i/2)*10, text[i],10);
i++;
_tcscpy(text[i],L"");
}
REAL emSize = 8;
Font* font = new Font(FontFamily::GenericSansSerif(), emSize, FontStyleBold);
for (int i = 0; i < 72; ++i)
{
RectF re, in,rel;
Status result = graphics.MeasureString(text[i], _tcslen(text[i]), font, in, &re);
result = graphics.MeasureString(L"|", 1, font, in, &rel);
double charRadius = radius - re.Height;
double angle = (((float)i / 72) - 0.25) * 2 * M_PI;
double x = (center.x + cos(angle) * charRadius);
double y = (center.y + sin(angle) * charRadius);
result = graphics.TranslateTransform(x, y);
result = graphics.RotateTransform((float)(90 + 360 * angle / (2 * M_PI)));
PointF start(0- re.Width/2, 0);
SolidBrush Red(Color(255, 255, 0, 0));
result = graphics.DrawString(text[i], _tcslen(text[i]), font, start, &Red);
result = graphics.ResetTransform();
x = (int)(center.x + cos(angle) * radius);
y = (int)(center.y + sin(angle) * radius);
result = graphics.TranslateTransform(x, y);
result = graphics.RotateTransform((float)(90 + 360 * angle / (2 * M_PI)));
PointF start1(0 - rel.Width / 2, 0);
result = graphics.DrawString(L"|", 1, font, start1, &Red);
result = graphics.ResetTransform();
}
SolidBrush Green(Color(255, 0, 255, 0));
Pen* pen = new Pen(&Green, 2.0f);
Status result = graphics.DrawArc(pen, (REAL)(center.x - radius), (REAL)(center.y - radius), radius * 2, radius * 2, 0, 360);
Result:

Drawing asian text with GDI+ gives transparent characters on a layered window

I have a layered window that I create myself with the WS_EX_LAYERED extended style and the UpdateLayeredWindow function.
Then I draw some text in it using GDI+ library, Graphics::DrawString method.
And the result is this:
Screenshot of the layered window.
As you can see, the japanese, korean and chinese characters are completely transparent. They even make the window's white background transparent, which is not transparent at all.
The problem occurs only on Windows Vista and Windows 7 when Desktop Composition (Aero theme) is disabled.
On Windows 10 it works fine, as Desktop Composition is always enabled there.
Why does this strange effect happen only with East-Asian characters?
And how can this be solved?
I don't have a Windows 7 machine to test on so I don't know if the alpha channel is the real issue but assuming that it is, you can work around it by setting the alpha channel back to the correct state after writing the buggy text:
enum { WIDTH = 255 * 3, HEIGHT = 25 };
#define CalcStride(w, bpp) ( ((((w) * (bpp)) + 31) & ~31) >> 3 )
#define PMC(c, a) ( (c) = ((int)(c) * (a) / 255) )
#define PM(q) PMC( (q).rgbRed, (q).rgbReserved), PMC( (q).rgbGreen, (q).rgbReserved), PMC( (q).rgbBlue, (q).rgbReserved)
RGBQUAD* GetPxPtr32(void*pBits, UINT x, UINT y)
{
return ((RGBQUAD*) ( ((char*)pBits) + (y * CalcStride(WIDTH, 32)) )) + x;
}
void SaveAlpha32(void*pBits, BYTE*buf)
{
for (UINT x = 0; x < WIDTH; ++x)
for (UINT y = 0; y < HEIGHT; ++y)
buf[(y * WIDTH) + x] = GetPxPtr32(pBits, x, y)->rgbReserved;
}
void RestoreAlpha32(void*pBits, const BYTE*buf)
{
for (UINT x = 0; x < WIDTH; ++x)
for (UINT y = 0; y < HEIGHT; ++y)
GetPxPtr32(pBits, x, y)->rgbReserved = buf[(y * WIDTH) + x];
}
void Draw(HDC hDC, HBITMAP hBM, void*pBits, UINT w, UINT h, bool isDwmActive)
{
// Fill with white and a silly gradient alpha channel:
for (UINT y = 0; y < h; ++y)
for (UINT x = 0; x < w; ++x)
(*(UINT32*)GetPxPtr32(pBits, x, y)) = 0xffffffff, GetPxPtr32(pBits, x, y)->rgbReserved = max(42, x % 255);
BYTE *alphas = isDwmActive ? 0 : (BYTE*) LocalAlloc(LPTR, sizeof(BYTE) * w * h), fillWithRed = true;
if (!isDwmActive) SaveAlpha32(pBits, alphas);
HGDIOBJ hBmOld = SelectObject(hDC, hBM);
RECT r = { 0, 0, WIDTH, HEIGHT };
int cbk = SetBkColor(hDC, RGB(255, 0, 0));
if (fillWithRed) ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &r, NULL, 0, NULL);
int ctx = SetTextColor(hDC, RGB(0, 0, 0));
int mode = SetBkMode(hDC, TRANSPARENT);
DrawText(hDC, TEXT("Hello World Hello World Hello World Hello World Hello World"), -1, &r, DT_SINGLELINE|DT_VCENTER|DT_CENTER); // Plain GDI always destroys the alpha
SetBkMode(hDC, mode), SetBkColor(hDC, cbk), SetTextColor(hDC, ctx);
SelectObject(hDC, hBmOld), GdiFlush();
if (!isDwmActive) RestoreAlpha32(pBits, alphas), LocalFree(alphas);
for (UINT y = 0; y < h; ++y) for (UINT x = 0; x < w; ++x) PM(*GetPxPtr32(pBits, x, y));
}
int main()
{
const INT w = WIDTH, h = HEIGHT, bpp = 32, x = 222, y = 222;
HWND hWnd = CreateWindowEx(WS_EX_LAYERED|WS_EX_TOPMOST, WC_STATIC, 0, WS_VISIBLE|WS_POPUP, x, y, WIDTH, HEIGHT, 0, 0, 0, 0);
SetWindowLong(hWnd, GWLP_WNDPROC, (LONG_PTR) DefWindowProc); // HACK
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);
HDC hDCScreen = GetDC(NULL), hDC = CreateCompatibleDC(hDCScreen);
Draw(hDC, hBmp, bits, w, h, false);
HGDIOBJ hBmOld = SelectObject(hDC, hBmp);
BLENDFUNCTION blend = { 0 };
blend.BlendOp = AC_SRC_OVER, blend.AlphaFormat = AC_SRC_ALPHA, blend.SourceConstantAlpha = 255;
POINT location = { x, y }, srcpt = { 0, 0 };
SIZE szWnd = { w, h };
UpdateLayeredWindow(hWnd, hDCScreen, &location, &szWnd, hDC, &srcpt, 0, &blend, ULW_ALPHA);
SelectObject(hDC, hBmOld), DeleteObject(hBmp);
DeleteDC(hDC), ReleaseDC(NULL, hDCScreen);
struct Closer { Closer(HWND h) { SetTimer(h, 1, 1000 * 11, TP); } static void CALLBACK TP(HWND h,UINT,UINT_PTR,DWORD) { ExitProcess(666); } } closer(hWnd); // HACK
for (MSG msg; GetMessage(&msg, 0, 0, 0); ) DispatchMessage(&msg);
return 666;
}
If you don't care about Vista without the platform update, you can try using Direct2D instead of GDI+.

Does MinGW influence compilation -- a GTK program

I compiled a GTK program in MinGW environment. It worked perfect. Recently, I updated MinGW and recompiled the GTK program, then the program always stopped with Segmentation fault. I have tried to use gdb to look for errors but I couldn't. The config of GTK is exactly same in the old and new MinGW. Therefore, I am suspicious of MinGW environment that influences compilation. I found the version of gcc is different in two environment:
old MinGW new MinGW
gcc 3.4.5 4.7.2
Any idea? Does anybody meet the situation?
Another clue is about GTK itself. I found the program stopped here:
g_signal_emit_by_name(G_OBJECT(g_object_get_data(G_OBJECT(window), "plat_GA_canvas")), "expose-event", G_TYPE_NONE);
It is a canvas to draw a image according to different situation. Here it just sends a signal to expose the canvas. The curious thing is that it worked in the old MinGW. So I don't doubt it is the point of the problem. Just maybe a clue. By the way, I compiled the GTK program in a pure Linux environment at home. It also worked perfect.
Any idea? Please help.
#duskast, below is the part of the code. It is a little lengthy.
+++++++++++++++++++++++++++++++++++++++++++++++++++
The problem maybe happened -- g_signal_emit_by_name:
void ACC_platform_unit_num_changed (GtkWidget *box, GtkWidget *window)
{
int kind;
kind = gtk_option_menu_get_history((GtkOptionMenu *)box) + 1;
if(plat.unit_num != kind)
{
plat_GA_canvas_refresh (window);
g_signal_emit_by_name(G_OBJECT(g_object_get_data(G_OBJECT(window), "plat_GA_canvas")), "expose-event", G_TYPE_NONE);
plat.unit_num = kind;
if(plat.unit_num == 1)
{
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_if_gap"), FALSE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_if_big_gap"), FALSE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_gap_w"), FALSE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_live_load_gap"), FALSE);
}
else
{
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_if_gap"), TRUE);
if(plat.has_gap)
{
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_if_big_gap"), TRUE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_gap_w"), TRUE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_live_load_gap"), TRUE);
}
else
{
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_if_big_gap"), FALSE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_gap_w"), FALSE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_live_load_gap"), FALSE);
}
}
gap_span_show (g_object_get_data(G_OBJECT(window), "ACC_platform_gap_span_store"));
}
}
The core drawing function:
void ACC_GA_draw (cairo_t *cr, int width, int height)
{
/* #define X_MARGIN 30
#define Y_MARGIN 30 */
#define COLUMN_RADIUS_ASSUME 1.6
#define COLUMN_SQUARE_LEN_ASSUME 2.0
double x, y, x1, y1, x2, y2, scale, x_base, y_base, X_MARGIN, Y_MARGIN;
double x3, y3, downward_height = 0, downward_width = 0;
double x_one_unit, y_one_unit, x_total, y_total, gap_value;
double alpha = 60.0, arrow_side_length = 20.0, arrow_tail_length = 10.0;
ACC_AXIS *x_axis, *y_axis;
int i, j, unit_num, downward;
char *AX, *AY, *Wx_left, *Wx_right, *Wy_top, *Wy_bottom, *gap, *axis;
cairo_text_extents_t te;
AX = g_strdup_printf("%.0f", plat.fan_section_AX * 1000);
AY = g_strdup_printf("%.0f", plat.fan_section_AY * 1000);
Wx_left = g_strdup_printf("%.0f", plat.walkway_Wx_left * 1000);
Wx_right = g_strdup_printf("%.0f", plat.walkway_Wx_right * 1000);
Wy_bottom = g_strdup_printf("%.0f", plat.walkway_Wy_bottom * 1000);
Wy_top = g_strdup_printf("%.0f", plat.walkway_Wy_top * 1000);
x_one_unit = plat.fan_section_AX * plat.SDD_num;
x_total = x_one_unit * plat.unit_num + plat.gap_total + plat.walkway_Wx_left + plat.walkway_Wx_right;
y_one_unit = plat.fan_section_AY * plat.row_num;
y_total = y_one_unit + plat.walkway_Wy_bottom + plat.walkway_Wy_top;
scale = calcu_scale (width, height, x_total, y_total, Wx_left, Wy_top, cr, &X_MARGIN, &Y_MARGIN);
cairo_set_line_width (cr, NORMAL_LINE_WIDTH * 0.7);
for(unit_num = 1; unit_num <= plat.unit_num; unit_num++)
{
if(unit_num == 1)
x_base = X_MARGIN;
else
{
double total_gap = 0;
for(i = 0; i < unit_num - 1; i++)
total_gap += strtod(g_list_nth(plat.gap_w, i)->data, NULL);
x_base = X_MARGIN + (x_one_unit * (unit_num - 1) + total_gap) * scale;
}
y_base = Y_MARGIN;
for(i = 0, x_axis = plat.X_axis; x_axis; x_axis = x_axis->next, i++)
{
if(i == 0)
x = x_base;
else
x += plat.fan_section_AX * scale;
y = y_base;
cairo_move_to(cr, x, y);
y += y_one_unit * scale;
cairo_line_to(cr, x, y); /* vertical grid */
cairo_stroke(cr);
/* SDD */
if(i != plat.SDD_num)
{
cairo_arrow (cr, x + plat.fan_section_AX / 2 * scale, y + plat.walkway_Wy_bottom * scale, alpha, arrow_side_length, 1, arrow_tail_length);
cairo_save(cr);
cairo_set_line_width (cr, BOLD_LINE_WIDTH);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
cairo_move_to(cr, x_base + plat.fan_section_AX / 2 * scale, y + plat.walkway_Wy_bottom * scale + arrow_side_length + arrow_tail_length);
cairo_rel_line_to(cr, (x_one_unit - plat.fan_section_AX) * scale, 0);
cairo_stroke(cr);
cairo_restore(cr);
}
/* dim line for A1, A2 ... */
cairo_move_to(cr, x, y + plat.walkway_Wy_bottom * scale + arrow_side_length + arrow_tail_length + 10);
cairo_rel_line_to(cr, 0, 20);
cairo_get_current_point(cr, &x3, &y3);
if(i != plat.SDD_num)
{
cairo_text_align_horizontal_center (cr, AX, 0, 1, plat.fan_section_AX / 2 * scale, -10);
}
else
{
if(plat.unit_num > 1 && plat.has_gap && unit_num != plat.unit_num)
{
gap_value = strtod(g_list_nth(plat.gap_w, unit_num - 1)->data, NULL);
gap = g_strdup_printf("%.0f", 1000 * gap_value);
cairo_text_extents(cr, gap, &te);
if(gap_value * scale < te.x_bearing + te.width)
{
downward = 1;
downward_height = 11;
downward_width = gap_value * scale;
cairo_rel_move_to(cr, gap_value / 2 * scale - (te.x_bearing + te.width / 2), 10);
}
else
{
downward = 0;
cairo_rel_move_to(cr, gap_value / 2 * scale - (te.x_bearing + te.width / 2), -10);
}
cairo_show_text(cr, gap);
g_free(gap);
}
else
downward = 0;
}
if(unit_num == 1 && i == 0)
{
cairo_move_to(cr, x - plat.walkway_Wx_left * scale, y + plat.walkway_Wy_bottom * scale + arrow_side_length + arrow_tail_length + 10);
cairo_rel_line_to(cr, 0, 20);
cairo_rel_move_to(cr, -25, -10);
cairo_show_text(cr, Wx_left);
}
if(unit_num == plat.unit_num && i == plat.SDD_num)
{
cairo_move_to(cr, x + plat.walkway_Wx_right * scale, y + plat.walkway_Wy_bottom * scale + arrow_side_length + arrow_tail_length + 10);
cairo_rel_line_to(cr, 0, 20);
cairo_rel_move_to(cr, 3, -10);
cairo_show_text(cr, Wx_right);
}
if(plat.axis_style_SDD == 0) /* 递增 */
axis = g_strdup_printf("A%d", plat.start_axis_SDD + (unit_num - 1) * (plat.SDD_num + 1) + i);
else
axis = g_strdup_printf("A%d", plat.start_axis_SDD + (unit_num - 1) * (plat.SDD_num + 1) - i);
cairo_text_extents(cr, axis, &te);
if(!downward || ((i != plat.SDD_num) && (unit_num != 1 && i != 0)))
cairo_move_to(cr, x3 - te.width / 2, y3 + te.height + 2);
else
{
if(te.width < downward_width)
cairo_move_to(cr, x3 - te.width / 2, y3 + te.height + downward_height);
else
{
if(i == plat.SDD_num)
cairo_move_to(cr, x3 - te.width, y3 + te.height + downward_height);
else
cairo_move_to(cr, x3, y3 + te.height + downward_height);
}
}
cairo_show_text(cr, axis);
g_free(axis);
cairo_stroke(cr);
for(j = 0, y_axis = plat.Y_axis; y_axis; y_axis = y_axis->next, j++)
{
x1 = x_base;
if(j == 0)
y1 = y_base + y_one_unit * scale;
else
y1 -= plat.fan_section_AY * scale;
if(i == 0)
{
cairo_move_to(cr, x1, y1);
x1 += x_one_unit * scale;
cairo_line_to(cr, x1, y1); /* horizontal grid */
cairo_stroke(cr);
}
if(i != plat.SDD_num && j != plat.row_num) /* fan ring */
{
cairo_arc(cr, x + plat.fan_section_AX / 2 * scale, y1 - plat.fan_section_AY / 2 * scale, plat.fan_ring_opening_D / 2 * scale, 0, 2 * PI);
cairo_stroke(cr);
}
/* columns */
if(plat.col_type == 0) /* 砼悬臂住 */
{
if(plat.SDD_num % 2 == 0)
{
if((i + 1) % 2 == plat.SDD_col_first && (j + 1) % 2 == plat.row_col_first)
{
cairo_arc(cr, x, y1, COLUMN_RADIUS_ASSUME * scale, 0, 2 * PI);
cairo_fill(cr);
cairo_stroke(cr);
}
}
else
{
if(!plat.if_unit_symmetry || unit_num % 2 == 1)
{
if((i + 1) % 2 == plat.SDD_col_first && (j + 1) % 2 == plat.row_col_first)
{
cairo_arc(cr, x, y1, COLUMN_RADIUS_ASSUME * scale, 0, 2 * PI);
cairo_fill(cr);
cairo_stroke(cr);
}
}
else
{
if((i) % 2 == plat.SDD_col_first && (j + 1) % 2 == plat.row_col_first)
{
cairo_arc(cr, x, y1, COLUMN_RADIUS_ASSUME * scale, 0, 2 * PI);
cairo_fill(cr);
cairo_stroke(cr);
}
}
}
}
else if(plat.col_type == 1) /* 钢柱 */
{
cairo_save(cr);
cairo_set_line_width (cr, 2 * NORMAL_LINE_WIDTH);
cairo_move_to(cr, x, y1 - COLUMN_SQUARE_LEN_ASSUME / 2 * scale);
cairo_rel_line_to(cr, 0, COLUMN_SQUARE_LEN_ASSUME * scale);
cairo_move_to(cr, x - COLUMN_SQUARE_LEN_ASSUME / 2 * scale, y1 - COLUMN_SQUARE_LEN_ASSUME / 2 * scale);
cairo_rel_line_to(cr, COLUMN_SQUARE_LEN_ASSUME * scale, 0);
cairo_move_to(cr, x - COLUMN_SQUARE_LEN_ASSUME / 2 * scale, y1 + COLUMN_SQUARE_LEN_ASSUME / 2 * scale);
cairo_rel_line_to(cr, COLUMN_SQUARE_LEN_ASSUME * scale, 0);
cairo_stroke(cr);
cairo_restore(cr);
}
else if(plat.col_type == 2) /* 砼框架柱 */
{
cairo_rectangle(cr, x - COLUMN_SQUARE_LEN_ASSUME / 2 * scale, y1 - COLUMN_SQUARE_LEN_ASSUME / 2 * scale, COLUMN_SQUARE_LEN_ASSUME * scale, COLUMN_SQUARE_LEN_ASSUME * scale);
cairo_fill(cr);
cairo_stroke(cr);
}
/* dim line of AA, AB ... */
if(unit_num == plat.unit_num && i == 0)
{
cairo_move_to(cr, x1 + plat.walkway_Wx_right * scale + 10, y1);
cairo_rel_line_to(cr, 20, 0);
if(j != plat.row_num)
{
cairo_text_align_horizontal_center (cr, AY, 1, 1, -10, -plat.fan_section_AY / 2 * scale);
}
if(j == 0)
{
x2 = x1 + plat.walkway_Wx_right * scale + 10 + 20 - 5;
y2 = y1 + plat.walkway_Wy_bottom * scale;
cairo_move_to(cr, x1 + plat.walkway_Wx_right * scale + 10, y1);
cairo_rel_move_to(cr, 0, plat.walkway_Wy_bottom * scale);
cairo_rel_line_to(cr, 20, 0);
cairo_rel_move_to(cr, -10, 25);
cairo_save(cr);
cairo_rotate(cr, - PI / 2.0);
cairo_show_text(cr, Wy_bottom);
cairo_restore(cr);
}
if(j == plat.row_num)
{
cairo_move_to(cr, x1 + plat.walkway_Wx_right * scale + 10, y1);
cairo_rel_move_to(cr, 0, -plat.walkway_Wy_top * scale);
cairo_rel_line_to(cr, 20, 0);
cairo_rel_move_to(cr, -10, -1);
cairo_save(cr);
cairo_rotate(cr, - PI / 2.0);
cairo_show_text(cr, Wy_top);
cairo_restore(cr);
}
cairo_stroke(cr);
}
else if(unit_num == 1 && i == 0)
{
if(plat.axis_style_row == 0) /* 递增 */
axis = g_strdup_printf("A%c", plat.start_axis_row + j);
else
axis = g_strdup_printf("A%c", plat.start_axis_row - j);
cairo_text_extents(cr, axis, &te);
cairo_move_to(cr, x_base - plat.walkway_Wx_left * scale - 20, y1 + te.height / 2);
cairo_show_text(cr, axis);
g_free(axis);
cairo_stroke(cr);
}
}
}
}
/* walkway line */
x = X_MARGIN - plat.walkway_Wx_left * scale;
y = Y_MARGIN - plat.walkway_Wy_top * scale;
cairo_move_to(cr, x, y);
cairo_rel_line_to(cr, x_total * scale, 0);
cairo_rel_line_to(cr, 0, y_total * scale);
cairo_rel_line_to(cr, -x_total * scale, 0);
cairo_rel_line_to(cr, 0, -y_total * scale);
cairo_stroke(cr);
/* dim total line for A1, A2 ... */
cairo_move_to(cr, X_MARGIN - plat.walkway_Wx_left * scale, Y_MARGIN + (y_one_unit + plat.walkway_Wy_bottom) * scale + arrow_side_length + arrow_tail_length + 10 + 20 - 5);
cairo_rel_line_to(cr, x_total * scale, 0);
cairo_stroke(cr);
/* dim total line for AA, AB ... */
cairo_move_to(cr, x2, y2);
cairo_rel_line_to(cr, 0, -y_total * scale);
cairo_stroke(cr);
g_free(AX);
g_free(AY);
g_free(Wx_left);
g_free(Wx_right);
g_free(Wy_bottom);
g_free(Wy_top);
}
The expose-event signal:
static gboolean ACC_GA_expose (GtkWidget *canvas, GdkEventExpose *event, gpointer user_data)
{
cairo_t *cr;
cr = gdk_cairo_create (canvas->window);
if(plat.if_GA_draw)
{
ACC_GA_draw (cr, canvas->allocation.width, canvas->allocation.height);
}
else
{
char *local = char_to_utf8 ("Press button \"生成GA\" to update!!");
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 0.35);
cairo_move_to(cr, 200, 200);
cairo_show_text(cr, local);
g_free(local);
}
cairo_destroy (cr);
return FALSE;
}
In main() function:
.
.
.
canvas = gtk_drawing_area_new();
g_object_set_data(G_OBJECT(window), "plat_GA_canvas", canvas);
plat.if_GA_draw = 0;
gtk_widget_show(canvas);
gtk_box_pack_start(GTK_BOX(sub_main_box), canvas, TRUE, TRUE, 0);
g_signal_connect(G_OBJECT(canvas), "expose-event", G_CALLBACK(ACC_GA_expose), window);
.
.
.
+++++++++++++++++++++++++++++++++++++++++++++++++++
GCC 3.4.5 and GCC 4.7.2 are ABI incompatible. You need to rebuild all your code.
I found a bug in my program. The bug is that expose-event for a canvas is exposed more than once and it crashed for the second time. But I don't know why the bug didn't come up in gcc3.4.5 or in a pure Linux environment. After I revised my program, it worked for mingw-gcc4.7.2, mingw-gcc3.4.5 and a pure Linux environment.
On the other hand, gcc4.7.2 works for pre-compiled gtk2.10.11 but fails for pre-compiled gtk2.24.10 in my situation. This is maybe due to ABI issue.
I have posted 2 other posts: gtk window moved then crash and compile GTK+ in MinGW, but failed. They are more or less related with this post.

Resources