C++ Draggable Borderless Window Issue - c++

I'm designing a custom window border, and i put a bitmap on the top as a drag bar. This works, however when i try to drag the window, it places itself in two different areas and flickers between the two. Here's a video:
http://dl.dropbox.com/u/85700751/capture-1.avi
When the window is flashing, i'm trying to drag it (it doesn't show my cursor for some reason). Here's my dragging code:
case WM_LBUTTONDOWN: {
int posX = LOWORD(lParam);
int posY = HIWORD(lParam);
if((isDragging==false)&&(posX>4)&&(posX<470)&&(posY>4)&&(posY<24))
{
isDragging = true;
ClipCursor(rect);
oldCursorX = posX;
oldCursorY = posY;
}
}
break;
case WM_LBUTTONUP: {
isDragging = false;
ClipCursor(NULL);
}
break;
case WM_MOUSEMOVE: {
if(isDragging) {
SetWindowPos(hWnd, NULL, LOWORD(lParam)-oldCursorX, HIWORD(lParam)-oldCursorY, 500, 500, NULL);
}
}
break;

It's generally easiest to simply resond to WM_NCHITTEST. For that message, the LPARAM will have the mouse hit X and Y coordinates (same as WM_LBUTTONDOWN). If they're within your draggable area just return HTCAPTION. The system will then automatically handle all the drag logic for you.

The cursor coordinates passed to WM_MOUSEMOVE are relative to the window position. But you keep changing the window position with every WM_MOUSEMOVE recieved.
Convert the coordinates to Screen coordinates using ::ClientToScreen().

Related

Is there a way to resize an already minimized window in width?

I have a window that is minimized and not added to the Taskbar when minimized.
When minimized i want it to be moved to the bottom left corner of my main window. This works pretty good, but it somehow is a little small, so you can see the icon and restore,maximize and close button.
But it seems impossible to resize that window so it shows the window title.
I tried SetWindowPos() and MoveWindow() but in both functions the new width and or hight parameters seem to be ignored.
Moving the minimized window with both functions works fine.
case WM_SIZE:
if (wParam == SIZE_MINIMIZED)
{
WINDOWINFO wi;
wi.cbSize = sizeof(WINDOWINFO);
GetWindowInfo(ghMainWnd, &wi); // gets the coordinates of the main window
MoveWindow(hDlg, wi.rcClient.left, wi.rcClient.bottom - 55, 200, 35, TRUE);
//SetWindowPos(hDlg, NULL, wi.rcClient.left , wi.rcClient.bottom - 55, 200, 35, SWP_NOZORDER | SWP_NOREDRAW);
return FALSE;
}
if (wParam == SIZE_RESTORED)
{
// do some stuff for the restored window
}
break;
Any adviced what could work?

GLFW camera and mouse control

So basically am learning OpenGL and the GLFW libraries from the tutorial on page: http://www.opengl-tutorial.org/beginners-tutorials/tutorial-6-keyboard-and-mouse/
My problems is with this less lesson showing the control of camera movement with mouse.
Basicaly it makes the application to get "FPS" like camera, with disabled cursor being moved on center of screen with each frame. But the camera gets crazy when we lose focus on the window and then it regains. For example if we click on the window to regain focus away from the middle of view, the camera will be moved by big amount. I tried to fix this issue with adding window focus callback:
void window_focus_callback(GLFWwindow* window, int focused){
if (focused)
{
//center mouse on screen
int width, height;
glfwGetWindowSize(window, &width, &height);
glfwSetCursorPos(window, 1024 / 2, 768 / 2);
windowFocused = true;
}
else
{
windowFocused = false;
}
And in the main application loop:
if(windowFocused) computeMatricesFromInputs();
But for some reason this solution doesnt work.
Is there any way to fix this issue using glfw?
Question is a bit old, but I recently suffered a similar issue. So just sharing, more solutions exist.
I use GLFW_CURSOR_DISABLED. In this mode the mouse position is not (yet) updated when you receive the 'on' focus event, so call to GetCursorPos delivers the previous value. The new cursor position arrives in the MouseMove callback AFTER the 'on' focus event.
I solved it by keeping track of the regain of focus and use this int he OnMouseMove callback to either dispatch a MouseInit (to snap the cursor) or a regular MouseMove.
This way I can ALT+TAB out of my window and return with the cursor somewhere else without nasty jumps/rotations of the camera.
void InputManagerGLFW::Callback_OnMouseMove(
GLFWwindow* window,
double xpos, //
double ypos) //
{
if (!mFocusRegained)
{
mMouseBuffer.Move(xpos, ypos);
}
else
{
mFocusRegained = false;
mMouseBuffer.Init(xpos, ypos);
}
}
void InputManagerGLFW::Callback_OnFocus(
GLFWwindow* window,
int focused)
{
if (focused)
{
// The window gained input focus
// Note: the mouse position is not yet updated
// the new position is provided by the mousemove callback AFTER this callback
Log::Info("focus");
// use flag to indicate the OnMouseMove that we just regained focus,
// so the first mouse move must be handled differently
mFocusRegained = true;
// this will NOT work!!!
// double x,y;
// glfwGetCursorPos(window,&x,&y);
// mMouseBuffer.Init(x,y);
}
else
{
// The window lost input focus
Log::Info("focus lost");
}
}

How to continuously select content in TWO RichEdit controls?

I'm currently working on project which will have two RichEdit controls one close to the other: let's say RichEdit1 is on left and RichEdit2 is on the right.
The user scenario I want to enable in the project is:
User mouse LButton down at somewhere in RichEdit1, e.g. before the 3rd char, in total 7 chars.
User drag the mouse to RichEdit2, e.g. after the 6th char, in total 11 chars.
User mouse LButton up.
I want to see both RichEdit1 3rd char to end and RichEdit2 begin to 6th char are selected.
Currently I notice that once mouse LButton down on RichEdit1, after I move the mouse to RichEdit2, the RichEdit2 could not receive mouse event before I release mouse.
Any suggestion will be appreciated. Thank you!
When the mouse button is pressed down on RichEdit1, it captures the mouse, thus subsequent mouse messages are sent to RichEdit1 until the mouse button is released. That is why RichEdit2 does not receive any mouse events while dragging over RichEdit2.
You will have to process the mouse move messages in RichEdit1 and check if their coordinates are outside of RichEdit1's client area. If so, convert them into coordinates relative to RichEdit2's client's area and then send EM_SETSEL/EM_EXSETSEL messages to RichEdit2 as needed. For example:
int RichEdit2StartIndex = -1;
...
// in RichEdit1's message handler...
case WM_MOUSEMOVE:
{
if ((wParam & MK_LBUTTON) == 0)
break;
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
RECT r;
GetClientRect(hwndRichEdit1, &r);
if (xPos < (r.right - r.left))
{
if (RichEdit2StartIndex != -1)
{
SendMessage(hwndRichEdit2, EM_SETSEL, -1, 0);
RichEdit2StartIndex = -1;
}
}
else
{
POINT pt;
pt.x = xPos;
pt.y = yPos;
MapWindowPoints(hwndRichEdit1, hwndRichEdit2, &pt, 1);
POINTL pl;
Pl.x := pt.x;
Pl.y := pt.y;
int idx = SendMessage(hwndRichEdit2, EM_CHARFROMPOS, 0, (LPARAM)&Pl);
if (idx != -1)
{
if (RichEdit2StartIndex == -1)
RichEdit2StartIndex = idx;
SendMessage(hwndRichEdit2, EM_SETSEL, RichEdit2StartIndex, idx);
}
}
break;
}
Vice versa when dragging a selection from RichEdit2 to RichEdit1.
And make sure that both RichEdit controls have the ES_NOHIDESEL style applied so you can see the selection in both controls at the same time.

When panel collapsed, getting rect of button no longer works

I've tried this in several ways. Deriving an object from CBCGPRibbonButton (same as CMFCRibbonButton) and using GetRect() from within the class, and having a click event find the button in the ribbon and get the rect.
What happens is that the rect is relative to the window that it is in. But if the panel is collapsed, then the window it is in is not the ribbon bar so it gets the wrong location.
I need a way of getting the location relative to the ribbon bar. Any ideas?
Ok, so I was trying to figure out what the rect was for the button:
When the panel had collapsed:
This is my solution:
class CMyButton : public CBCGPRibbonButton
{
DECLARE_DYNCREATE(CHeaderFooter)
public:
CMyButton()
{
};
CMyButton(
UINT nID,
LPCTSTR lpszText,
int nSmallImageIndex = -1,
int nLargeImageIndex = -1,
BOOL bAlwaysShowDescription = FALSE)
: CBCGPRibbonButton(nID, lpszText, nSmallImageIndex, nLargeImageIndex, bAlwaysShowDescription)
{
}
BOOL HasMenu() const override
{
return true;
}
CWnd* GetButtonWnd() const
{
CBCGPBaseRibbonElement* pDroppedDown = m_pParent->GetDroppedDown();
CWnd* pWnd;
if (pDroppedDown) // Was popup opened from a collapsed panel from the ribbon?
{
pWnd = pDroppedDown->GetPopupMenu()->GetMenuBar();
}
else
{
pWnd = m_pParent->GetParentRibbonBar();
}
return pWnd;
}
void OnShowPopupMenu() override
{
CRect rect = GetRect();
// pt is the bottom left corner of button relative to the window that
// it is contained in.
CPoint pt(rect.left, rect.bottom);
GetButtonWnd()->ClientToScreen(&pt); // convert pt to screen coordinates
... // do other stuff with that point
}
};
IMPLEMENT_DYNCREATE(CHeaderFooter, CBCGPRibbonButton)
which determines the CWnd that the button is part of so that the rect can be converted correctly to screen coordinates.
Calculate in screen coords.
Get the button rectangle from he ribbon. Use ClientToScreen and you have your screen coordinates now use your buttons parent handle with ScreenToClient and you have the cords relative to the ribbon bar.
PS: Even I don't know why to show a button when the ribbon is collapsed.

Scroll image horizontally

I want to scroll image using scroll bar but when i used scrollwindow() function in OnHScroll method,it only scroll button present in dialog box not image.
I have used bitblt and stretchblt function to enlarge image using device context.I think by using dc information we can scroll image but i donot know i to do it.
Code of OnHScroll function is given below:
void CImgVeiwer::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pcrollBar)
{
// TODO: Add your message handler code here and/or call default
int minpos;
int maxpos;
GetScrollRange(SB_HORZ, &minpos, &maxpos);
maxpos = GetScrollLimit(SB_HORZ);
CurPos = GetScrollPos(SB_HORZ);
switch (nSBCode)
{
case SB_LEFT: // Scroll to far left.
CurPos = minpos;
break;
case SB_RIGHT: // Scroll to far right.
CurPos = maxpos;
break;
case SB_ENDSCROLL: // End scroll.
break;
case SB_LINELEFT: // Scroll left.
if (CurPos > minpos)
CurPos--;
break;
case SB_LINERIGHT: // Scroll right.
if (CurPos < maxpos)
CurPos++;
break;
case SB_PAGELEFT: // Scroll one page left.
{
// Get the page size.
SCROLLINFO info;
GetScrollInfo(SB_HORZ, &info, SIF_ALL);
if (CurPos > minpos)
CurPos = max(minpos, CurPos - (int) info.nPage);
}
break;
case SB_PAGERIGHT: // Scroll one page right.
{
// Get the page size.
SCROLLINFO info;
GetScrollInfo(SB_HORZ, &info, SIF_ALL);
if (CurPos < maxpos)
CurPos = min(maxpos, CurPos + (int) info.nPage);
}
break;
case SB_THUMBPOSITION: // Scroll to absolute position. nPos is the position
CurPos = nPos; // of the scroll box at the end of the drag operation.
break;
case SB_THUMBTRACK: // Drag scroll box to specified position. nPos is the
CurPos = nPos; // position that the scroll box has been dragged to.
break;
}
// Set the new position of the thumb (scroll box).
m_HsrollFlag = TRUE;
SetScrollPos(SB_HORZ,CurPos);
ScrollWindow(-CurPos,0,0,0);
Invalidate();
CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}
Thanks In Advance
Finally ,I got solution to scroll image horizontally.
In above given code,remove the statement
ScrollWindow(-CurPos,0,0,0);
and add following statement in OnPaint() method, m_nWidth and nHeight are width and height of image you want to scroll.
dc.StretchBlt(ZERO - CurPos,FIFTY ,m_nWidth +1000,
nHeight+ 1000,
&memDC,ZERO,ZERO,m_nWidth,
m_nHeight,SRCCOPY);
By calling Invalidate() you cause the entire dialog to be repainted. So the ScrollWindow call is wasted: you are overpainting it in the subsequent WM_PAINT. Normally you would use ScrollWindow to scroll the visible part of the image, and then in WM_PAINT you only need to paint the uncovered edge left behind by the image scroll.
You should provide an lpRect parameter to ScrollWindow, and maybe lpClipRect as well. This will specify the area you want scrolled and also prevent the scrolling of child windows like buttons if they are outside of the image.