How can I copy a dialogs position coordinates into another dialogs? - c

I have a few unique push buttons and I only want to show one of them at a time. I want them to be centered, so I have the first push button centered on the dialog. If I want to show the 3rd push button, I want to give it the first buttons coordinates and hide the 1st button.
How can I copy a buttons coordinates and set another buttons coordinates to the copied values?
Ex. Lets say I have...
PB_ONE
PB_TWO
How can I grab PB_ONE's coordinates and set PB_TWO's coordinates to PB_ONE?
RECT rcButton;
GetWindowRect(GetDlgItem(hDlg, PB_ONE), &rcButton);
The above code grabs the dialog item I want to copy the coordinates from. Is there a simple command that sets another dialog button to this dialogs coordinates?
something like SetDlgItem()?
UPDATED WITH THE NEW CODE I TRIED BASED OFF THE ANSWER
GetWindowRect(GetDlgItem(hDlg, PB_ONE), &rcButton);
ClientToScreen(hDlg, &p);
OffsetRect(&rcButton, -p.x, -p.y);
SetWindowPos(GetDlgItem(hDlg, PB_TWO), 0, rcButton.left, rcButton.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
ShowWindow(GetDlgItem(hDlg, PB_TWO), SW_SHOW);
have to current replace rcButton.left and rcButton.top with p.x and a hard value for rcButton.top to get the button to position on the dialog screen.
This returns an error in SetWindowPos where parameter 3 cannot convert a LONG * into an INT.

GetWindowRect gives the rectangle in screen coordinates. You can convert this to client coordinates using ScreenToClient(HWND hWnd, LPPOINT lpPoint).
Edit:
RECT rcButton;
HWND hbutton1 = GetDlgItem(hDlg, PB_ONE);
HWND hbutton2 = GetDlgItem(hDlg, PB_TWO);
//if(!hbutton1 || !hbutton2) {error...}
GetWindowRect(hbutton1, &rcButton);
//Test
char buf[50];
sprintf(buf, "%d %d", rcButton.left, rcButton.top);
MessageBoxA(0, buf, "screen coord", 0);
//Note, this will only convert the top-left corner, not right-bottom corner
//but that's okay because we only want top-left corner in this case
ScreenToClient(hDlg, (POINT*)&rcButton);
//Test
sprintf(buf, "%d %d", rcButton.left, rcButton.top);
MessageBoxA(0, buf, "client coord", 0);
ShowWindow(hbutton1, SW_HIDE);
SetWindowPos(hbutton2, 0, rcButton.left, rcButton.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
A slightly simpler way is to use ClientToScreen(HWND hWnd, LPPOINT lpPoint) as follows:
RECT rcButton;
GetWindowRect(GetDlgItem(hDlg, PB_ONE), &rcButton);
POINT p{ 0 };
ClientToScreen(hDlg, &p);
//p is now (0,0) of parent window in screen coordinates
OffsetRect(&rcButton, -p.x, -p.y);
rcButton is now the coordinates relative to top-left of parent window. You can use that in SetWindowPos.

Related

Blank screen after rendering text

I have opened a window which shows two rects on the screen then using SDL_TTF to show the mouse position on the screen.
The bit I am having hard time understanding is why after rendering text the the two rects before it do not show up.
I am using SDL_RenderFillRect to draw two rects on screen
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderFillRect(renderer, rect1);
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL_RenderFillRect(renderer, rect2);
Code for rendering the text is
// define string with mouse x, y coords
sprintf(someString, "x: %d, y: %d", mouse.x, mouse.y);
SDL_Point textPos = {10, 10};
WriteText(renderer, font, someString, textPos, (SDL_Color){255, 255, 255, 255});
SDL_Surface *fontSurface = TTF_RenderText_Blended(font, someString, COLOR_BLACK); // create font surface
SDL_Texture *fontTexture = SDL_CreateTextureFromSurface(renderer, fontSurface); // create the texture
// get clip width and height from fontsurface clip rect
SDL_Rect *fontRect = &fontSurface->clip_rect;
fontRect->x = pos.x;
fontRect->y = pos.y;
SDL_RenderCopy(renderer, fontTexture, NULL, fontRect); // copy text to the renderer
// delete surface and texture
SDL_FreeSurface(fontSurface);
SDL_DestroyTexture(fontTexture);
It to shows the mouse positon top left corner of the window. However this makes the rest of the window blank.
To prevent this my work around is having to draw something on the screen after calling SDL_RendererCopy (and weirdly before calling SDL_DestroyTexture too) For example drawing single point
...
SDL_RenderCopy(renderer, fontTexture, NULL, fontRect); // copy text to the renderer
// why is this needed??
SDL_RenderDrawPoint(renderer, 0, 0);
// delete surface and texture
SDL_FreeSurface(fontSurface);
SDL_DestroyTexture(fontTexture); // have to draw a point before this
...
This then shows the two rects rendered before the text
If I set dstRect to NULL when calling SDL_RenderCopy then the text spans the whole window but I can see what was rendered before underneath the text.
Why am I having to draw a point after calling SDL_RenderCopy to stop what was rendered before from not showing up?
NOTE: Link to full source code https://pastebin.com/tRSFT0PV
This is a bug in SDL 2.0.10. It's fixed by https://hg.libsdl.org/SDL/rev/6ee12b88beed and this fix will ship with 2.0.11. Sorry about that!

Getting the width and height of the client area of a window

The accepted answer in this question says the following about getting the width and height of the client area of a window:
RECT rect;
if(GetWindowRect(hwnd, &rect))
{
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
}
But I don't understand why not just do the following:
RECT rect;
if(GetWindowRect(hwnd, &rect))
{
int width = rect.right;
int height = rect.bottom;
}
Since the documentation for GetClientRect() says the following:
Because client coordinates are relative to the upper-left corner of a
window's client area, the coordinates of the upper-left corner are
(0,0).
My guess is that this is just a general example of how to get the width and height from a RECT, or maybe I am missing something!
The example you give calls GetWindowRect rather than GetClientRect. And so returns screen coordinates rather than client coordinates. Hence it would be wrong to assume that the top left was at 0, 0.
Note therefore that the code you present calculates the window width and height rather than the client area width and height.
If you want the dimensions of the client area then call GetClientRect instead. And, as you observe, the returned rectangle will have top left at 0, 0.

Xlib: resize window containing a pixmap

Related to how-to-resize-a-pixmap-with-xlib.
As it was concluded in the abovementioned topic, it's impossible to resize a pixmap. What about window, after pixmap is copied into it? In the example below, everything is good up to the point where the window is being resized. The icon is drawn after it's copied into the window, but is lost after the window is resized. Am I missing something here or there really is no way whatsoever to resize pixmap content?
Context: trying to add the client icons into the tabs for the dwm's tab patch.
unsigned int px_w, px_h, dummy_i;
Window icon_w, dummy_w;
Pixmap getWindowIcon (Window *w) {
XWMHints *wmh;
Pixmap pxmp = NULL;
if(wmh = XGetWMHints(dpy, w)) {
pxmp = wmh->icon_pixmap;
XFree(wmh);
}
return pxmp;
}
Pixmap client_icon = getWindowIcon(current_window); // current_window is already existing Window instance
// find the pixmap dimensions and store in px_w, px_h:
XGetGeometry(dpy, client_icon, &dummy_w, &dummy_i, &dummy_i, &px_w, &px_h, &dummy_i, &dummy_i );
icon_w = XCreateSimpleWindow(dpy, root_window, 0, 0, px_w, px_h, 0, 0, color);
XMapRaised(dpy, icon_w);
// copy pixmap to the newly created win:
XCopyArea(dpy, client_icon, icon_w, cellDC.gc, 0, 0, px_w, px_h, 0, 0);
// resize - after which the pixmap is lost in the window:
XResizeWindow(dpy, icon_w, px_w+1, px_h+1);

Is it possible to create an XOR pen like DrawFocusRect()?

The Win32 GDI DrawFocusRect(HDC, const RECT*) function draws the dotted outline of a rectangle on the desired devince context. The cool thing about this function is it draws the dots using an XOR function so that when you call it a second time on the same device context and rectangle, it erases itself:
RECT rc = { 0, 0, 100, 100 };
DrawFocusRect(hdc, &rc); // draw rectangle
DrawFocusRect(hdc, &rc); // erase the rectangle we just drew
I want to achieve the same dotted line effect as DrawFocusRect() but I just want a line, not a whole rectangle. I tried doing this by passing a RECT of height 1 to DrawFocusRect() but this doesn't work because it XORs the "bottom line" of the rectange on top of the top line so nothing gets painted.
Can I create a plain HPEN that achieves the same effect as DrawFocusRect() so I can draw just a single line?
As #IInspectable commented, you want to use SetROP2(). The other half of the battle is creating the correct pen. Here is how the whole thing shakes out:
HPEN create_focus_pen()
{
LONG width(1);
SystemParametersInfo(SPI_GETFOCUSBORDERHEIGHT, 0, &width, 0);
LOGBRUSH lb = { }; // initialize to zero
lb.lbColor = 0xffffff; // white
lb.lbStyle = BS_SOLID;
return ExtCreatePen(PS.GEOMETRIC | PS.DOT, width, &lb, 0, 0);
}
void draw_focus_line(HDC hdc, HPEN hpen, POINT from, POINT to)
{
HPEN old_pen = SelectObject(hdc, hpen);
int old_rop = SetROP2(R2_XORPEN);
MoveToEx(hdc, from.x, from.y, nullptr);
LineTo(hdc, to.x, to.y);
SelectObject(hdc, old_pen);
SetROP2(old_rop);
}

Printing inside window, not on borders

I'm trying to write something inside a curses window, but it seems to write on borders too. How can I fix the code below?
win_self = newwin(LINES / 2, COLS, 0, 0);
box(win_self, 0, 0);
wrefresh(win_self);
wprintw(win_self, "foobar");
In curses, the borders generated by box() are inside borders. As far as I can tell, there's no way to simply say "don't overwrite my border".
Nevertheless, there are three solutions that I can think of right now:
don't overwrite the border characters (use move())
draw the box after you draw window contents, then refresh() the screen (you're probably still overwriting something, but at least it's not the border characters)
create a "border window" with borders and a "content window" inside of it, which of course starts at (border_window_start_y + 1, border_window_start_x + 1) and is two lines/columns smaller than the "border window"
Just to make it more clear: the box() function doesn't add the property "this window has visible borders" to the window, it just prints border characters around the window.
You are:
free to overwrite those border characters
supposed to be cautious if you don't want them overwritten
I'd say the easiest way is to create a window inside of the window borders and print in that window.
win_self = newwin(LINES / 2, COLS, 0, 0);
box(win_self, 0, 0);
derwin_self = derwin(win_self, LINES / 2 - 2, COLS - 2, 0, 0);
wprintw(derwin_self, "foobar");

Resources