Edit control not repainted entirely with chosen brush - c++

I have an edit control which background color depends from validity of user input.
If input is valid edit control should keep default look, else the background color should change to light gray.
I am checking validity in EN_UPDATE handler and if it is invalid I store the HWND of the edit control into vector.
Visual Styles are enabled.
The problem comes when I change the position of the mouse pointer. Let me describe it:
I click on edit control and type invalid input.
I move mouse pointer elsewhere, but edit control still has focus.
Now I delete invalid input by pressing backspace.
As soon as input becomes valid the color changes properly, but borders become thicker/darker.
These pictures illustrate the problem:
Edit control before typing in data:
Edit control when user pastes invalid data ( mouse pointer is in grey area ):
The last character is r.
Now if mouse pointer is out of edit control's client area ( on dialog's client area for example ) and user deletes r here is what I get:
Notice the thicker border.
When mouse pointer hovers above the edit control it gets repainted properly.
Here are the relevant code snippets ( if needed I can submit a small SSCCE ) :
// minimal code snippet for EN_UPDATE
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDC_MYEDIT:
{
if( HIWORD(wParam) == EN_CHANGE )
{
if( /* invalid input */ )
{
// store HWND into vector
}
// InvalidateRect(...); // tried this too...
}
}
break;
// minimal code snippet for WM_CTLCOLOREDIT
case WM_CTLCOLOREDIT:
{
if( /* this control is stored in vector */ )
{
//=== then this is invalid entry->paint it grey ===//
// Needed SetBkMode for text's background transparency
SetBkMode( (HDC)wParam, TRANSPARENT );
// return light gray brush
return (INT_PTR)( (HBRUSH)GetStockObject( LTGRAY_BRUSH ) );
}
else
return DefWindowProc( ... ); // default processing
}
How can I fix this?

I have found a solution to my problem. I just added RedrawWindow instead of InvalidateRect and ordered frame to be redrawn as well :
// minimal code snippet for EN_UPDATE
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDC_MYEDIT:
{
if( HIWORD(wParam) == EN_CHANGE )
{
if( /* invalid input */ )
{
// store HWND into vector
}
// after finishing validation, redraw window INCLUDING THE FRAME
// This solves the problem with edges entirely
RedrawWindow( (HWND)lParam, NULL, NULL,
RDW_ERASE | RDW_FRAME | RDW_INVALIDATE );
}
}
break;

Please try handling case for message CTLCOLOR_MSGBOX as well. Refer to this MSDN article for more details.
How to change the background color of an MFC edit control
Snapshot of sample code given in link
case CTLCOLOR_EDIT:
case CTLCOLOR_MSGBOX:
// Set color to green on black and return the background
brush.
pDC->SetTextColor(RGB(0, 255, 0));
pDC->SetBkColor(RGB(0, 0, 0));
return (HBRUSH)(m_pEditBkBrush->GetSafeHandle());

Related

The entire scrollbar moves in a CWnd when calling ScrollWindowEx with SW_SCROLLCHILDREN

I've added a CScrollBar to my Cwnd named CPanel. But when I scroll the page the whole scrollbar moves. Any idea how I can solve this? Changing CPanel to a CScrollView or CFormView is sadly not an option.
CPanel::CPanel()
{
CreateEx(WS_EX_CONTROLPARENT, _T("Static"), NULL, WS_CHILD | WS_TABSTOP | WS_BORDER, m_clRect, pwndParent, IDC_PANEL_FORM);
ScrollBarInit();
}
void CPanel::ScrollBarInit()
{
//Before this i calculate size of scrollbar and size of scrollarea
m_pclScrollBar = new CScrollBar();
m_pclScrollBar->Create(WS_CHILD | WS_VISIBLE | SBS_VERT | SBS_RIGHTALIGN, clRectScrollbar, this, IDC_SCROLLBAR_FORM);
m_pclScrollBar->SetScrollRange(VSCROLL_RANGE_MIN, VSCROLL_RANGE_MAX);
//After this I add scrollbar info
}
void CPanel::OnVScroll(UINT iSBCode, UINT iPos, CScrollBar* pclScrollBar)
{
switch(pclScrollBar->GetDlgCtrlID())
{
case IDC_SCROLLBAR_FORM:
ScrollBarScroll(iSBCode, iPos, pclScrollBar);
break;
}
}
void CPanel::ScrollBarScroll(UINT iSBCode, UINT iPos, CScrollBar *pclScrollBar)
{
int iScrollPositionPrevious;
int iScrollPosition;
int iScrollPositionOriginal;
iScrollPositionOriginal = m_pclScrollBar->GetScrollPos();
iScrollPosition = iScrollPositionOriginal;
if(m_pclScrollBar != NULL)
{
SCROLLINFO info = {sizeof( SCROLLINFO ), SIF_ALL};
pclScrollBar->GetScrollInfo(&info, SB_CTL);
pclScrollBar->GetScrollRange(&info.nMin, &info.nMax);
info.nPos = pclScrollBar->GetScrollPos();
iScrollPositionPrevious = info.nPos;
switch(iSBCode)
{
case SB_TOP: // Scroll to top
iScrollPosition = VSCROLL_RANGE_MIN;
break;
case SB_BOTTOM: // Scroll to bottom
iScrollPosition = VSCROLL_RANGE_MAX;
break;
case SB_ENDSCROLL: // End scroll
break;
case SB_LINEUP: // Scroll one line up
if(iScrollPosition - VSCROLL_LINE >= VSCROLL_RANGE_MIN)
iScrollPosition -= VSCROLL_LINE;
else
iScrollPosition = VSCROLL_RANGE_MIN;
break;
case SB_LINEDOWN: // Scroll one line down
if(iScrollPosition + VSCROLL_LINE <= VSCROLL_RANGE_MAX)
iScrollPosition += VSCROLL_LINE;
else
iScrollPosition = VSCROLL_RANGE_MAX;
break;
case SB_PAGEUP: // Scroll one page up
{
// Get the page size
SCROLLINFO scrollInfo;
m_pclScrollBar->GetScrollInfo(&scrollInfo, SIF_ALL);
if(iScrollPosition > VSCROLL_RANGE_MIN)
iScrollPosition = max(VSCROLL_RANGE_MIN, iScrollPosition - VSCROLL_PAGE);
break;
}
case SB_PAGEDOWN: // Scroll one page down
{
// Get the page size
SCROLLINFO scrollInfo;
m_pclScrollBar->GetScrollInfo(&scrollInfo, SIF_ALL);
if(iScrollPosition < VSCROLL_RANGE_MAX)
iScrollPosition = min(VSCROLL_RANGE_MAX, iScrollPosition + VSCROLL_PAGE);
break;
}
case SB_THUMBPOSITION: // Scroll to the absolute position. The current position is provided in nPos
case SB_THUMBTRACK: // Drag scroll box to specified position. The current position is provided in nPos
iScrollPosition = iPos;
break;
default:
break;
}
if(iScrollPositionOriginal != iScrollPosition)
{
m_pclScrollBar->SetScrollPos(iScrollPosition);
ScrollWindowEx(0, iScrollPositionOriginal - iScrollPosition, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
}
}
}
Since you specified SW_SCROLLCHILDREN in your call to ScrollWindowEx (see also the Windows API documentation for ScrollWindowEx; it is usually better than MFC's), and requested the entire client area to be scrolled by passing NULL for the lpRectScroll parameter, the system does just that. The scrollbar is a child window as well, so it gets moved like all other child controls.
The solution is hinted to in the documentation for SW_SCROLLCHILDREN:
Scrolls all child windows that intersect the rectangle pointed to by lpRectScroll by the number of pixels specified in dx and dy.
To prevent the scrollbar from moving alongside the other child windows, it must be excluded from the rectangle passed as the lpRectScroll parameter. To do so, query the client area, and subtract the area occupied by the scrollbar. Assuming that the scrollbar is at the right and covers the entire height, the following code will solve your issue:
if(iScrollPositionOriginal != iScrollPosition) {
m_pclScrollBar->SetScrollPos(iScrollPosition);
// Query the window's client area
CRect clientArea;
GetClientRect(clientArea);
// Find the area occupied by the scrollbar
CRect scrollbarArea;
m_pclScrollBar->GetWindowRect(scrollbarArea);
// Adjust the client area to exclude the scrollbar area
CRect scrollArea(clientArea);
scrollArea.DeflateRect(0, 0, scrollbarArea.Width(), 0);
ScrollWindowEx(0, iScrollPositionOriginal - iScrollPosition, scrollArea, NULL,
NULL, NULL, SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
}
Also keep in mind the remark on using the SW_SCROLLCHILDREN flag:
If the SW_SCROLLCHILDREN flag is specified, Windows will not properly update the screen if part of a child window is scrolled. The part of the scrolled child window that lies outside the source rectangle will not be erased and will not be redrawn properly in its new destination. Use the DeferWindowPos Windows function to move child windows that do not lie completely within the lpRectScroll rectangle.
Since you don't have control over the amount of pixels the user will scroll, there will be situations where the screen will not properly update. To work around this, implement a solution following the procedure outlined in the quote above: Replace the call to ScrollWindowEx with a series of calls to DeferWindowPos, repositioning all child windows manually.

Difficulties in changing the background color of edit control

I have edit control in a dialog box which input is checked for validity.
I should indicate validity by changing the background color of an edit control if input is invalid, otherwise I should do nothing.
I am checking the input in EN_CHANGE handler and if input is invalid I store the handle of the edit control in a vector. In the end I call InvalidateRect( (HWND)lParam, NULL, TRUE ); so edit control can be repainted with proper color.
To repaint edit control I am handling WM_CTLCOLOREDIT like this:
case WM_CTLCOLOREDIT:
{
bool IsInvalid = false; // does this edit control hold invalid text ?
// vector InvalidInput contains handles of edit controls
// with invalid input, so we check if our window is stored there
for( vector<HWND>::size_type i = 0;
!IsInvalid && ( i < InvalidInput.size() ); i++ )
{
if( InvalidInput[i] == (HWND)lParam )
IsInvalid = true;
}
// if input is invalid change background color to light gray
if( IsInvalid )
{
// Needed SetBkMode for text background transparency
SetBkMode( (HDC)wParam, TRANSPARENT );
// return light gray brush
return (INT_PTR)( (HBRUSH)GetStockObject( LTGRAY_BRUSH ) );
}
else
return FALSE; // say we didn't handle it
// so dialog procedure can do that for us
}
After I start the program edit control is painted properly.
After I type valid entry edit control is painted properly.
After I type invalid character immediately after, background is colored into light gray and everything seems to work fine.
If I delete the invalid character then the background stays gray instead of returning to default system color.
What am I doing wrong and how should I fix this ?
EDIT:
If I put InvalidateRect() in my WM_COMMAND handler for IDC_MYEDIT then the problem seems to disappear:
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDC_MYEDIT:
{
if( HIWORD(wParam) == EN_CHANGE )
{
//do your validation stuff
}
InvalidateRect(...);
}
break;
// the rest of the code...
The error is here
else
return FALSE; // say we didn't handle it
// so dialog procedure can do that for us
The WM_CTLCOLOREDIT message is listed as one of the special exceptions to the rule that returning FALSE means "not handled". It must be handled. If you don't want to handle it, you can pass the message to DefWindowProc.

Reset cursor in WM_SETCURSOR handler properly

INTRODUCTION AND RELEVANT INFORMATION:
I have made an application that needs to change the look of a cursor into hand when mouse hovers above the static control, but resets it to a normal cursor otherwise.
My initial application was in full screen mode, but recently terms have changed and it must have a resizable window.
This means that my handler for WM_SETCURSOR must be rewritten to reflect newly introduced changes.
Cursors are loaded in WM_CREATE, and I have defined class cursor, like this:
// cursors
case WM_CREATE:
hCursorHand = LoadCursor( NULL, IDC_HAND );
hCursorArrow = LoadCursor( NULL, IDC_ARROW );
// other stuff
In my class:
WNDCLASSEX wc;
// ...
wc.hCursor = hCursorArrow;
//...
This is my old WM_CURSOR handler ( code is simplified for clarity purposes ):
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
SetCursor(hCursorHand);
else
SetCursor(hCursorArrow);
return TRUE;
If cursor hovers above static control, then my handler changes it to hand, else sets it to default cursor ( arrow ).
Bellow is the picture I have sketched in Paint that displays the desired look of the cursor when it hovers above static control, it is on the client area, and when user resizes window.
If additional code snippets are required, ask and I will edit my post, but for now, they are omitted to keep the post short and concise.
I work on Windows XP, using MS Visual Studio C++ and pure Win32 API.
MY EFFORTS TO SOLVE PROBLEM:
Bellow are the code snippets that I have tried, but they all failed:
First snippet:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
else
return DefWindowProc( hWnd, msg, lParam, wParam );
Second Snippet:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
break; // based on MSDN example
Third snippet:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
else
return FALSE;
These set cursor to hand no matter where it is.
If I leave my WM_SETCURSOR handler unchanged, the only problem I get is that instead of sizing arrows, I get regular arrow ( as the cursor’s look ) when I hover over the border, but window can be sized.
If I comment out my WM_SETCURSOR handler, sizing arrows and cursor arrow appear properly, but cursor doesn’t change into hand when hovers above static control ( which is logical, since there is no WM_SETCURSOR handler to change it ).
I have browsed through SO archive, looked on MSDN, CodeProject , DaniWeb, Cprogramming and CodeGuru, but had no success.
Looking through those, I have found an example where people compare low word of the lParam against hit test code.
Looking through MSDN I have found link for hit test values ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms645618%28v=vs.85%29.aspx ) and I have found link for cursor types (http://msdn.microsoft.com/en-us/library/windows/desktop/ms648391%28v=vs.85%29.aspx ).
Currently I am reading them, because I think that I will have to load additional cursor resources, take several comparisons of hit test values, and then use those resources to set cursor look accordingly.
QUESTION:
I really would like my WM_SETCURSOR handler to look like this:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
else
// reset cursor's look to default
so I ask the community to instruct me on how to do this.
If this isn’t possible, then I will consider using multiple if statements to check the hit test code, and set cursor’s look accordingly.
Of course, if there is better solution for my problem, please suggest it, I will consider it as well.
Thank you.
Regards.
In general, if you handle the WM_SETCURSOR message you must either
Call SetCursor() to set the cursor, and return TRUE, or
If the message came from a child window, return FALSE for default processing, or
If the message is from your own window, pass the message through to DefWindowProc()
I think the last two points aren't made quite clear by the MSDN docs.
The window under the mouse pointer gets the first WM_SETCURSOR message. If it handles it and returns at that point, nothing else happens. If however it calls DefWindowProc(), then DWP forwards the message to the window's parent to handle. If the parent chooses not to handle it, it can return FALSE and the DefWindowProc processing will continue.
But this only applies if the message came from a previous call to DWP. If the message originated with the window itself, rather than a child, returning TRUE or FALSE without setting the cursor means the cursor won't be set at all.
Another thing: although your question didn't specify, I'm assuming from your use of GetDlgItem() that your top-level window is a dialog. If that's true, you can't just return TRUE or FALSE for a message - you need to return the value using SetWindowLongPtr() and store the return value in DWLP_MSGRESULT. Returning FALSE from a dialog procedure indicates that you didn't handle the message at all - this is equivalent to passing a message through to DefWindowProc().
So I think the proper handling for your situation is, in your top-level window:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
return TRUE;
}
return FALSE;
If your top-level window isn't in fact a dialog, you would do this:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
Here's my first example, if cursor go to menubar, cursor changes to cursor hand:
HCURSOR cursorHand = LoadCursor(NULL, IDC_HAND);
case WM_SETCURSOR:
if(LOWORD(lParam) == HTMENU)
{
SetCursor(cursorHand);
}
break;
Here's my second example, if cursor goes to button, cursor changes to cursorHand:
HCURSOR cursorHand = LoadCursor(NULL, IDC_HAND);
case WM_SETCURSOR:
if(LOWORD(lParam) == buttonId)//declare you
{
SetCursor(cursorHand);
}
break;
Warning:menubar and button is not created! Create you and please, check my answer example.
The question as I understand it is, given a parent window with one more more child windows (one of which is a static control) how do you set the cursor to the hand when the cursor is over the static control, and the arrow when the cursor is over the client area of the parent window, and let default processing take place when the cursor is over a non-client area of the parent window.
To check things out, I wrote a simple program with a top-level window with a static control as a child window. My first attempt was the following:
1) Set the class cursor of the top-level window to LoadCursor(NULL, IDC_ARROW). This allows the default processing to set the cursor to the arrow when appropriate.
2) Keep track of the position of the mouse cursor by handling the WM_MOUSEMOVE message by calling my HandleWMMouseMove function as follows:
case WM_MOUSEMOVE:
HandleWMMouseMove(lParam);
break;
//ptCurrMousePos is a global variable of type POINT
static void HandleWMMouseMove(LPARAM mousepos)
{
ptCurrMousePos.x = (int)(short)(LOWORD(mousepos));
ptCurrMousePos.y = (int)(short)(HIWORD(mousepos));
}
3) and then all I had to do was handle the WM_SETCURSOR message by calling my HandleWMSetCursor function as follows:
case WM_SETCURSOR:
if (HandleWMSetCursor())
return TRUE;
break;
//hwndFrame is a handle to the top-level window.
//hwndStatic is a handle to the static control.
static BOOL HandleWMSetCursor(void)
{
if (ChildWindowFromPoint(hwndFrame, ptCurrMousePos)==hwndStatic) {
SetCursor(hCursorHand);
return TRUE;
}
return FALSE;
}
this worked fine but I couldn't understand how the code posted in the question was working even partially. So I asked the questioner whether the child window was really a static control. The answer was yes but it was created with the SS_NOTIFY style. So I created my child window with this style and my code stopped working, but the code posted with the question started to work. With the help of the Spy++ program distributed with Visual Studio I learned the following.
Static controls are normally transparent (not in the visual sense, but meaning that even when the mouse is over the transparent window, Windows will consider the mouse to be over the window underneath the transparent window).
When you create a static control with SS_NOTIFY the control is no longer transparent (i.e. it starts to receive an process mouse messages (like WM_MOUSEMOVE), so my code stopped working because it never received WM_MOUSE messages when the cursor was over the static control. On the other hand the code in the question did not work when the static control was created without SS_NOTIFY because without this style the static control was transparent, which meant that the WARAM in the WM_SETCURSOR message was never equal to the static control (in other words Windows never considered the mouse to be over the static control because it was transparent).
It is possible to combine the two approaches by changing the WM_SETCURSOR handler function to the following:
//hwndFrame is a handle to the top-level window.
//hwndStatic is a handle to the static control.
static BOOL HandleWMSetCursor(WPARAM wParam)
{
if (((HWND)wParam == hwndStatic) || (ChildWindowFromPoint(hwndFrame, ptCurrMousePos)==hwndStatic)) {
SetCursor(hCursorHand);
return TRUE;
}
return FALSE;
}

C++ window draggable by its menu bar

So I'm using Visual C++, and I have created a draggable, borderless window. Anyway, there is a toolbar along the top, and i want to be able to drag the window by that toolbar. I still want the toolbar to be functional, but i have no earthly idea how to be able to drag the window by it. This is my current window (see the toolbar on the top):
And this is my current code to make it draggable:
case WM_NCHITTEST: {
LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
if(hit == HTCLIENT) hit = HTCAPTION;
return hit;
}
break;
You are on the right track with hooking WM_NCHITTEST. Now, you need to make change what constitutes a client hit versus a caption hit. If I understand your code right now, anywhere you click within the client area of the window (everything but the border) will allow you to drag the window elsewhere. This will make interacting with your application very difficult. Instead, you should be returning HTCAPTION only after you have determined that the hit was within the menubar area. Specifically, the area of the menubar that does not hold the File/Edit/Help buttons.
case WM_NCHITTEST: {
LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
if (hit == HTCLIENT) { // The hit was somewhere in the client area. Don't know where yet.
// Perform your test for whether the hit was in the region you would like to intercept as a move and set hit only when it is.
// You will have to pay particular attention to whether the user is actually clicking on File/Edit/Help and take care not to intercept this case.
// hit = HTCAPTION;
}
return hit;
break;
}
Some things to keep in mind here:
This can be very confusing to a user that wants to minimize, close, or move your application. Menubars do not convey to the user that you can move the window by dragging them.
If you are concerned with vertical pixels you may consider doing what other applications on Windows are starting to do -- moving the menubar functionality to a single button that is drawn in the titlebar. (See recent versions of Firefox/Opera or Windows explorer in Windows 8 for some idea to move things to the titlebar.
In one of my applications I also wanted to make the window what I call "client area draggable". Unfortunately the mentioned solution (replacing HTCLIENT with HTCAPTION)
does have a serious flaws:
Double-clicking in the client area now shows the same behaviour as
double-clicking the caption (i.e. minimizing/maximizing the window)!
To solve this I did the following in my message handler (excerpt):
case WM_MOUSEMOVE:
// Move window if we are dragging it
if (mIsDragging) // variable: bool mIsDragging;
{
POINT mousePos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
mIsDragging = (ClientToScreen(hWnd, &mousePos) &&
SetWindowPos(hWnd,
NULL,
mDragOrigin.left + mousePos.x - mDragPos.x,
mDragOrigin.top + mousePos.y - mDragPos.y,
0,
0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE));
}
break;
case WM_LBUTTONDOWN:
// Check if we are dragging and safe current cursor position in case
if (wParam == MK_LBUTTON)
{
POINT mousePos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
if (ClientToScreen(hWnd, &mousePos) &&
DragDetect(hWnd, mousePos))
{
// Check if the cursor is pointing to your new caption here!!!!
mIsDragging = true;
mDragPos = mousePos;
GetWindowRect(hWnd, &mDragOrigin);
SetCapture(hWnd);
}
}
break;
// Remove this case when ESC key handling not necessary
case WM_KEYDOWN:
// Restore original window position if ESC is pressed and dragging active
if (!mIsDragging || wParam != VK_ESCAPE)
{
break;
}
// ESC key AND dragging... we restore original position of window
// and fall through to WM_LBUTTONUP as if mouse button was released
// (i.o.w. NO break;)
SetWindowPos(hWnd, NULL, mDragOrigin.left, mDragOrigin.top, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
case WM_LBUTTONUP:
ReleaseCapture();
break;
case WM_CAPTURECHANGED:
mIsDragging = false;
break;
The (pseudo) code omits the return values (default: 0) and variable definitions but
should make the procedure clear anyway!? (If not drop me a line and I'll add more
or all code).
ps: I just found another comprehensive description which also explains the differences
of these two solutions: http://tinyurl.com/bqtyt3q

hardware buffering using SDL, question about how it works

I'm deciding to do my first game, its going to be simple but I want to use c++ and I chose SDL for my learning. So my question is about how the "buffers" are handled when writing code. I'll post my related code at the bottom.
Ok, so basically the way I understand it is that SDL takes care of which buffer is actually being drawn to the screen. When I am writing to a buffer it is always the backbuffer I am writing to, or the buffer currently not being drawn on the screen. So, when I call SDL_Flip(screen) it "blits" my screen surface onto the backbuffer, then moves the pointer to which buffer is being drawn to that buffer which used to be the backbuffer, the one I had been working on, and the old buffer that was showing now becomes the backbuffer. At this point if I call SDL_FillRect(arguments) it will be performed on the now back buffer?
I'm going to post my entire "heartbeat" of my learning game as it may help clarify my question:
//While the user hasn't quit
while( quit == false )
{
//If there's an event to handle
if( SDL_PollEvent( &event ) )
{
//If a key was pressed
if( event.type == SDL_KEYDOWN )
{
//Set the proper message surface
switch( event.key.keysym.sym )
{
case SDLK_UP: message = upMessage; break;
case SDLK_DOWN: message = downMessage; break;
case SDLK_LEFT: message = leftMessage; break;
case SDLK_RIGHT: message = rightMessage; break;
}
}
else if( event.type == SDL_QUIT ) //if the user clicks the little X in the upper right corner.
{
quit = true;
}
}
//If a message needs to be displayed
if( message != NULL )
{
// Clear the back buffer.
SDL_FillRect( SDL_GetVideoSurface(), NULL, 0 );
//Draw the backgroudn to the back buffer.
apply_surface( 0, 0, background, screen );
// Draw the "message" to the back buffer.
apply_surface( ( SCREEN_WIDTH - message->w ) / 2, ( SCREEN_HEIGHT - message->h ) / 2, message, screen );
//Null the surface pointer
message = NULL;
}
//Swap the current and back buffer.
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
}
it highly depends on the your system (ie. X11, Linux frame buffer, Windows), and the backend SDL uses to interact with it. Also which flags you passs to SDL_SetVideoMode. There are basically software surfaces which sit in a region of memory in you program and hardware surfaces which are placed in graphical card's memory. What you describe seems to me to be a double buffer, which is enabled if you pass SDL_HWSURFACE | SDL_DOUBLEBUF to SDL. Just remember this is not supported on all platforms and configurations and you may get something different instead.