How to get the title bar height and width for aero and basic design - winapi

I am using GetSystemMetrics(SM_CXSIZEFRAME) for the width of the border, it works with the basic design, but not with aero, how can I improve it, so it works with aero?
I am using GetSystemMetrics(SM_CYCAPTION) for the height of the title bar but the value is too small for both, basic and aero design, what am I doing wrong here?

In unthemed Windows, GetSystemMetrics(SM_CYCAPTION) is the height of the text in the title bar; you need to add in the size of the frame and border padding (GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYEDGE) * 2).
For themed Windows (which is the default these days), GetThemeSysSize is most likely the function you're looking for; in particular, GetThemeSysSize(SM_CXBORDER) for the border width, and GetThemeSysSize(SM_CYSIZE) + GetThemeSysSize(SM_CXPADDEDBORDER) * 2 for the title bar.

I had a similar problem, where I needed to subtract the title bar height from the mouse Y to render a cursor in the window.
After looking around, and looking at functions like GetSystemMetrics, I ended up just using GetWindowRect and ClientToScreen.
I got the screen position of the client area using ClientToScreen with point 0,0.
Then subtracted that from the window top retrieved through GetWindowRect. Result is the distance from the top of the window to the inside of the window. Or the titlebar height.

int getWindowHeadSize()
{
RECT Rect;
GetWindowRect(hWnd, &Rect);
POINT point = { 0, 0 };
ClientToScreen(hWnd, &point);
return point.y - Rect.top + GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYEDGE) * 2;
}

Related

TEXTMETRIC is giving wrong height when resizing text with mouse wheel

I'm calculating the number of lines in a rich edit control.
Currently I'm using next code
TEXTMETRIC tm; {
HDC hdc = GetDC(hwndRichEdit);
GetTextMetrics(hdc, &tm);
ReleaseDC(hwndRichEdit, hdc);
}
RECT editRect;
GetClientRect(hwndRichEdit, &editRect);
long int countLines = (editRect.bottom - editRect.top) / (tm.tmHeight + tm.tmExternalLeading);
The code yields out the right number of lines until I start to change the size of the text via mouse wheel + ctr.
Is it possible to get the right text height even if the text is resized with mouse wheel?
N.B. I'm recalculating the number of lines with EN_UPDATE notification.
You can send an EM_GETZOOM message to the control to retrieve the current zoom ratio. Dividing the countLines value by the zoom ratio should yield the correct line count. Use the MulDiv API call to implement the division.

UI Elements not scaling while using Canvas Scaler

I'm trying to make my UI elements work and remain the same for every different resolution. I added a Canvas Scaler to my Canvas and played around with the settings until it looked finished.
I then tried building the game and running it at few different resolutions to confirm that it was working. However, the Canvas Scaler doesn't seems to work.
http://prntscr.com/d1afz6
Above is some random resolution but that's how big my editor screen is and that's what I'm using as my reference resolution. That's also the hierarchy for this specific Canvas http://prntscr.com/d1aggx. It takes almost the whole screen when ran at 640x480. I have no clue why this is not working. I've read most of the unity guides on that but none of them seem to have that problem.
Ok, to fit something no matter the size of the screen, you have to use a separate coordinate system than Unity's absolute system. One of Unity's models is the View. The View is coordinates 0,0 at the top left, and 1,1 at the bottom right. Creating a basic Rect that handles that, is the following.
using UnityEngine;
namespace SeaRisen.nGUI
{
public class RectAnchored
{
public float x, y, width, height;
public RectAnchored(float x, float y, float width, float height)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public static implicit operator Rect(RectAnchored r)
{
return new Rect
{
x = r.x * Screen.width,
y = r.y * Screen.height,
width = r.width * Screen.width,
height = r.height * Screen.height
};
}
}
}
Here, we take the normal Rect floats, the x,y coordinates along with a width and height. But these are in the values [0..1]. I don't clamp it, so it can be tweened on and off the screen with animation, if desired.
The following is a simple script that create's a button in the lower right corner of the screen, and resizes as the screen grows or shrinks.
void MoveMe()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, -Vector3.up, out hit, float.MaxValue)
|| Physics.Raycast(transform.position, Vector3.up, out hit, float.MaxValue))
transform.position = hit.point + Vector3.up * 2;
}
void OnGUI()
{
if (GUI.Button(new RectAnchored(.9f, .9f, .1f, .1f), "Fix me"))
{
MoveMe();
}
}
The X is .9 to the right and Y .9 from the top, and width and height of .1, so the button is 1/10th of the screen in height and width, positioned in the bottom 1/10th of the screen.
Since OnGUI is rendered every frame (or so), the button rect updates with the screen resize automatically. The same would work in a typical UI, if you are using Update() to render your windows.
I hope this explains the difference between what I meant with absolute coordinates. Setting say the previous example (using absolutes) in 640x480, it'd be something like new Rect(576, 432, 64, 48) and it wouldn't scale. By using new RectAnchored(.9f, .9f, .1f, .1f) and have it rendered into UI space based on Screen size, then it scales automatically.

Are the coordinates in WINDOWPOS on WM_WINDOWPOSCHANGED in parent coordinates or screen coordinates?

Quick and simple one this time. I have a subclassed tab control that handles WM_WINDOWPOSCHANGED to, when not SWP_NOSIZE, resize its content. It passes the WINDOWPOS lParam's cx and cy fields to TCM_ADJUSTRECT to get the content rect size.
I need to do this on command as well (after changing tabs, say). However, I can't just do a dummy resize to the same size; even with an explicit SetWindowPos(), real Windows seems to add SWP_NOSIZE itself if the size doesn't change. So I want to write the analogous code to my WM_WINDOWPOSCHANGED handler.
My question is: what coordinate system are the coordinates given to WM_WINDOWPOSCHANGED given in, parent coordinates or screen coordinates? GetWindowRect() returns screen coordinates, so I'd like to know if I need to convert the coordinates to get the same values that I would get in WM_WINDOWPOSCHANGED. The documentation for WM_WINDOWPOSCHANGED doesn't say; neither does the documentation for WINDOWPOS.
Thanks.
WINDOWPOS, GetWindowRect, GetCursorPos, etc. give screen coordinates. When you use SetWindowPos you have to supply coordinates in relation to parent. This is straight forward for main window and popup windows which use screen coordinates. For moving child windows, you can use ScreenToClient and ClientToScreen for conversion.
For example, this will find the coordinates of OK button in relation to top-left corner of dialog box:
RECT rcOK;
HWND hitem = ::GetDlgItem(m_hWnd, IDOK);
GetWndRect(rcOK, hitem, m_hWnd);
void GetWndRect(RECT &rect, HWND item, HWND parent)
{
::GetWindowRect(item, &rect);//screen coordinates of OK button
POINT offset{ 0 };
ClientToScreen(parent, &offset); //Top-left (0,0) of client area of dialog -> screen coordinates
rect.left -= offset.x;
rect.right -= offset.x;
rect.top -= offset.y;
rect.bottom -= offset.y;
//client coordinates of OK button in relation to Dialog's Top-Right
}
Now we can move up the OK button by 10px:
rc.top -= 10;
rc.bottom -= 10;
::SetWindowPos(hitem, 0, rc.left, rc.top, 0, 0, SWP_NOSIZE);

GUI Button for all screen resolutions

I am using OnGUI Buttons on a car game and attached forward and backward buttons on it. But they keep on adjusting on all screens badly.
I have tried various online solutions, but failed. I am using this:
GUI.RepeatButton (new Rect (Screen.width - 780, Screen.height - 130, 120, 120), LeftBtnTexture, TransparentStyle)
I know this is wrong, what will be alternative width and height setting for all screens. :(
Take a look at Screen.dpi - http://docs.unity3d.com/ScriptReference/Screen-dpi.html
It will allow you to specify button size in inches. But be aware that dpi could be unavailable (equals zero) or maybe even incorrect, therefore you should do some sanity check. For example:
public float sizeInInches = 0.5;
float dpi = Screen.dpi;
if (dpi < 25 || dpi > 800) {
dpi = 150;
}
float sizeInPx = sizeInInches * dpi;
As an alternative for some cases, you may want to set GUI element size in percent of screen dimensions, like sizeInPx = Screen.width * 0.1;

Parallax scrolling in Sprite LibGDX

I want to parallax scroll a Texture behind a Sprite with fixed width and height.
The problem is i need to just scroll the Texture in a given width and height and not to the end of the screen. I need something like a window view on this texture.
i could overlay the rest of the screen with black areas but there has to be a better solution i guess ;-)
currently im doing this
sprite.setX(sprite.getX() + (OVERLAY_ANIMATION_SPEED * delta));
sprite2.setX(sprite2.getX() + (OVERLAY_ANIMATION_SPEED * delta));
and reset the sprite where x is bigger than the screen width. But i have a smaller area inside the screen in which the scrolling should appear not from the beginng to the end of the screen.
Hope somebody has a hint for me how to achive this.
I'm using a glViewport to achieve something similar:
public void setViewPort(float dx, float dy, float sx, float sy)
{
Gdx.gl.glViewport((int) (screenWidth * dx), (int) (screenHeight * dy),
(int) (screenWidth * sx), (int) (screenHeight * sy));
}
So:
setViewPort(0, 0, 1, 1);
would render fullscreen and:
setViewPort(0.2f, 0.2f, 0.6f, 0.6f);
would render a 60% sized 'sub'window-viewport at 20% position
(thus centered), nothing is rendered outside that window (clipped by OpenGL). Hope this helps someone!

Resources