How to draw texture at mouse coords using keyboard - c++

Its like the title suggests, i want to draw a "1" texture at mouse coords using a keyboard key press.
I am using switch statements for input:
switch (e.type)
{
case SDL_QUIT:
{
quit = true;
break;
}
case SDL_MOUSEBUTTONDOWN:
{
switch (e.button.button)
{
case SDL_BUTTON_LEFT:
{
SDL_Rect rect = {e.motion.x - 10, e.motion.y - 10, 20, 20};
SDL_RenderCopy(gRenderer, gT[0], NULL, &rect);
printf("nod\n");
break;
}
}
break;
}
case SDL_KEYDOWN:
{
switch (e.key.keysym.sym)
{
case SDLK_c:
{
SDL_SetRenderDrawColor(gRenderer, 255, 255, 255, 255);
SDL_RenderClear(gRenderer);
printf("tot ecranul\n");
break;
}
case SDLK_1:
{
SDL_Rect rect = {e.motion.x - 8, e.motion.y - 8, 16, 16};
SDL_RenderCopy(gRenderer, gT[3], NULL, &rect);
printf("1\n");
break;
}
}
break;
}
}
I tried some random things, and no success so far.
gT[3] is the "1" texture.

e.motion only makes sense when e is a mouse event.
Call SDL_GetMouseState to get the current mouse position.

Related

Texture drawn at wrong coordinates?

I tried drawing a '1' texture at mouse coordinates when I press the 1 key:
switch (e.type)
{
case SDL_QUIT:
{
quit = true;
break;
}
case SDL_KEYDOWN:
{
switch (e.key.keysym.sym)
{
case SDLK_1:
{
SDL_Rect rect = {e.motion.x - 8, e.motion.y - 8, 16, 16};
SDL_RenderCopy(gRenderer, gT[3], NULL, &rect);
printf("1\n");
break;
}
}
break;
}
}
I cannot comprehend why this doesn't work.
gT[3] is the texture of the '1'.
I thought maybe it is because its e.key.keysym.sym but I'm not sure.
SDL_Event::motion is only valid when SDL_Event::type is SDL_MOUSEMOTION.
Stop trying to use SDL_Event::motion when SDL_Event::type is SDL_KEYDOWN, perhaps by recording the X and Y coordinates of the most recent SDL_MOUSEMOTION event and using those instead.

Vertical scrollbar for a dialog in a CPropertySheet not working

I am a beginner in MFC. I have a dialog embedded in a property sheet.
Since the dialog is bigger than property sheet, some portion get cropped.
So I am planning to add a vertical scrollbar. I have tried two ways.
Added a scrollbar control from the toolbox in the dialog itself.
Created a control variable.
DDX_Control(pDX, IDC_SCROLLBAR, m_ctlScrollBar);
Added message map as below:
ON_WM_VSCROLL(IDC_SCROLLBAR,OnVScroll)
Added below code in OnInitDialog():
SCROLLINFO ScrollInfo;
ScrollInfo.cbSize = sizeof(ScrollInfo);
ScrollInfo.fMask = SIF_ALL;
ScrollInfo.nMin = 0;
ScrollInfo.nMax = 100;
ScrollInfo.nPage = 40;
ScrollInfo.nPos = 50;
ScrollInfo.nTrackPos = 0;
m_ctlScrollBar.SetScrollInfo(&ScrollInfo,TRUE);
OnVScroll() function overridden as below:
void CFeesPage::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
SCROLLINFO ScrollInfo;
m_ctlScrollBar.GetScrollInfo(&ScrollInfo);
switch (nSBCode)
{
case SB_BOTTOM: //Scrolls to the lower right.
break;
case SB_ENDSCROLL: //Ends scroll.
break;
case SB_LINEDOWN: //Scrolls one line down.
m_ctlScrollBar.SetScrollPos(m_ctlScrollBar.GetScrollPos() + 1,TRUE);
break;
case SB_LINEUP: //Scrolls one line up.
m_ctlScrollBar.SetScrollPos(m_ctlScrollBar.GetScrollPos() - 1,TRUE);
break;
case SB_PAGEDOWN: //Scrolls one page down.
m_ctlScrollBar.SetScrollPos(m_ctlScrollBar.GetScrollPos() + ScrollInfo.nPage, TRUE);
break;
case SB_PAGEUP: //Scrolls one page up.
m_ctlScrollBar.SetScrollPos(m_ctlScrollBar.GetScrollPos() - ScrollInfo.nPage, TRUE);
break;
case SB_THUMBPOSITION:
break;
case SB_THUMBTRACK:
m_ctlScrollBar.SetScrollPos(nPos, TRUE);
break;
case SB_TOP: //Scrolls to the upper left.
break;
}
}
In this case scrollbar moving, but child controls doesn't?
On another way, I have enabled scrollbar control for property sheet as below in OnInitDialog:
CScrollBar* test = this->GetScrollBarCtrl(SB_VERT);
Set SCROLLINFO as above.
The OnVScroll written as below:
void CSubTranSheet::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
SCROLLINFO ScrollInfo;
GetScrollInfo(SB_VERT, &ScrollInfo);
switch (nSBCode)
{
case SB_BOTTOM: //Scrolls to the lower right.
break;
case SB_ENDSCROLL: //Ends scroll.
break;
case SB_LINEDOWN: //Scrolls one line down.
SetScrollPos(SB_VERT, GetScrollPos(SB_VERT) + 1, TRUE);
break;
case SB_LINEUP: //Scrolls one line up.
SetScrollPos(SB_VERT, GetScrollPos(SB_VERT) - 1, TRUE);
break;
case SB_PAGEDOWN: //Scrolls one page down.
SetScrollPos(SB_VERT, GetScrollPos(SB_VERT) + ScrollInfo.nPage, TRUE);
break;
case SB_PAGEUP: //Scrolls one page up.
SetScrollPos(SB_VERT, GetScrollPos(SB_VERT) - ScrollInfo.nPage, TRUE);
break;
case SB_THUMBPOSITION:
break;
case SB_THUMBTRACK:
SetScrollPos(SB_VERT, nPos, TRUE);
break;
case SB_TOP: //Scrolls to the upper left.
break;
}
}
In this case also scrollbar moving but child dialog doesn't?
Please help me on this. I am not sure which method is right. Thanks in advance.
PropertySheet will pick the largest page dialog and it will resize itself so that all of the page dialogs are shown. Scrolling is not needed unless there is override for PropertySheet's size, or additional controls have been added in CMyPropertyPage::OnInitDialog
Moreover, the end-user's screen may have lower resolution, in which case parts of the propertysheet will be obscured. You just have to make smaller dialog pages, no taller than 1000 pixels, or about 300 dialog points.
The code shown in question is an attempt to update the scroller. In addition to updating the scroller, you have to scroll the dialog itself.
The link from #AndrewTruckle shows how to use ScrollWindow to achieve this.
Alternatively you can manually move all the child controls as shown below. This is somewhat easier because you can resize the dialog and adjust the scroller range without worrying about the child controls' alignment.
#include <map>
class CMyPropertyPage : public CPropertyPage
{
std::map<CWnd*, CRect> rc_children;
CRect rc_max;
void OnSize(UINT flags, int cx, int cy);
void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
DECLARE_MESSAGE_MAP()
};
void CMyPropertyPage::OnSize(UINT flags, int cx, int cy)
{
CPropertyPage::OnSize(flags, cx, cy);
CRect rc;
if(!rc_max.bottom)
{
//initialize once:
for(CWnd *p = GetWindow(GW_CHILD); p; p = p->GetWindow(GW_HWNDNEXT))
{
//save the rectangles for all child controls
p->GetWindowRect(&rc);
ScreenToClient(&rc);
rc_children[p] = rc;
//find the lowest point in dialog
if(rc.bottom > rc_max.bottom)
rc_max.bottom = rc.bottom;
}
}
GetClientRect(&rc);
SCROLLINFO info = { sizeof(info) };
info.fMask = SIF_ALL;
info.nMin = 0;
info.nMax = (rc_max.bottom + 100); //100 pixels below the lowest control
info.nPage = rc.bottom;
SetScrollInfo(SB_VERT, &info, TRUE);
}
void CMyPropertyPage::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
CPropertyPage::OnVScroll(nSBCode, nPos, pScrollBar);
SCROLLINFO info = { sizeof(SCROLLINFO) };
GetScrollInfo(SB_VERT, &info, SIF_ALL);
//update scroller
switch(nSBCode)
{
case SB_LEFT: info.nPos = info.nMin; break;
case SB_RIGHT: info.nPos = info.nMax; break;
case SB_LINELEFT: info.nPos--; break;
case SB_LINERIGHT: info.nPos++; break;
case SB_PAGELEFT: info.nPos -= info.nPage; break;
case SB_PAGERIGHT: info.nPos += info.nPage; break;
case SB_THUMBPOSITION: info.nPos = info.nTrackPos; break;
case SB_THUMBTRACK: info.nPos = info.nTrackPos; break;
}
SetScrollInfo(SB_VERT, &info, TRUE);
if(info.nPos < 0 || info.nPos > rc_max.bottom)
return;
//find how many child controls we have
int count = 0;
for(CWnd *p = GetWindow(GW_CHILD); p; p = p->GetWindow(GW_HWNDNEXT))
count++;
//go through all child controls and move them:
HDWP hdwp = BeginDeferWindowPos(count);
for(CWnd *p = GetWindow(GW_CHILD); p; p = p->GetWindow(GW_HWNDNEXT))
{
CRect rc;
p->GetWindowRect(&rc);
ScreenToClient(&rc);
if(rc_children.find(p) != rc_children.end())
{
int y = info.nPos - rc_children[p].top;
DeferWindowPos(hdwp, p->m_hWnd, NULL, rc.left, -y, 0, 0,
SWP_NOSIZE | SWP_NOACTIVATE);
}
}
EndDeferWindowPos(hdwp);
}
BEGIN_MESSAGE_MAP(CMyPropertyPage, CPropertyPage)
ON_WM_VSCROLL()
ON_WM_SIZE()
END_MESSAGE_MAP()

SDL 2.0 Key repeat and delay

I'm having a problem with SDL 2.0 keyboard input in pong-like game. When I order to move to the left by pressing left arrow, it is processed by SDL_PollEvents() and responds correctly if the key was pressed once. However, if I keep the key pressed, I get a short delay (as long as Windows key repeat delay) before moving continuously.
Here is function processing events:
void Event::PlayerEvent (Player &player)
{
while (SDL_PollEvent (&mainEvent))
{
switch (mainEvent.type)
{
case SDL_KEYDOWN :
switch (mainEvent.key.keysym.sym)
{
case SDLK_ESCAPE :
gameRunning = false;
break;
case SDLK_LEFT :
player.moving = player.left;
break;
case SDLK_RIGHT :
player.moving = player.right;
}
break;
case SDL_QUIT :
gameRunning = false;
}
}
}
EDIT: After all, I managed to fix this issue by calling
SystemParametersInfo (SPI_SETKEYBOARDDELAY, 0, 0, 0) at the start of the program and SystemParametersInfo (SPI_SETKEYBOARDDELAY, 1, 0, 0) at the end, to return to standard key repeat delay.
For game movement, you would typically not use events, but rather use states.
Try using SDL_GetKeyboardState() outside of the event loop:
const Uint8* keystates = SDL_GetKeyboardState(NULL);
...
if(keystates[SDL_SCANCODE_LEFT])
player.moving = player.left;
else if(keystates[SDL_SCANCODE_RIGHT])
player.moving = player.right;
using SPI_SETKEYBOARDDELAY is not a good approach. This way your game will not be protable anymore since its only available on Windows.
Instead you should use like menthiond in an answer before SDL_GetKeyboardState.
Howeve be aware that you still have to collect the SDL_PollEvent. Otherwise SDL_GetKeyboardState will be always empty.
So it should be like this:
//...
SDL_Event sdlEvent;
while (SDL_PollEvent(&sdlEvent)) {
if (sdlEvent.type == SDL_QUIT) {
//..
}
}
const Uint8* keystates = SDL_GetKeyboardState(NULL);
if(keystates[SDL_SCANCODE_LEFT]) {
//...
}
if(keystates[SDL_SCANCODE_RIGHT]) {
/...
}
//...
simple as that
int vertical = 0;
int horizontal = 0;
float x = 500;
float y = 500;
float speed = 5.0;
in your sdl loop:
if (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_KEYDOWN:
{
switch (event.key.keysym.sym)
{
case SDLK_LEFT: horizontal=-1; break;
case SDLK_RIGHT: horizontal = 1; break;
case SDLK_UP: vertical=-1; break;
case SDLK_DOWN: vertical=+1; break;
}
break;
}
case SDL_KEYUP:
{
switch (event.key.keysym.sym)
{
case SDLK_LEFT: horizontal = 0; break;
case SDLK_RIGHT: horizontal = 0; break;
case SDLK_UP: vertical = 0; break;
case SDLK_DOWN: vertical = 0; break;
}
break;
}
}
}
x += horizontal * speed;
y += vertical * speed;
Use the SDL_GetKeyboardState capturing outside of - while (SDL_PollEvent (&mainEvent)), that works fine.

Error during compilation of SDL test

I'm learning to programming with SDL2. Currently, I'm making a basic exercise. My program load a background image, and a complete sprite sheet on the background. But I'm having problems while executing the program. When I execute the binary, the program window closes immediately by itself; I cant see anything. I think it is a problem with the main loop, but it looks right for me. This is my code
#include "SDL.h"
void main () {
int gameover = 0;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* TheWindow;
SDL_Renderer* RenderEngine;
SDL_Surface* LoadedSurface;
SDL_Surface* LoadedImage;
SDL_Texture* CharacterImg;
SDL_Texture* BackgroundImg;
TheWindow = SDL_CreateWindow("Character Test",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 580, SDL_WINDOW_RESIZABLE);
RenderEngine = SDL_CreateRenderer( TheWindow, -1, SDL_RENDERER_ACCELERATED);
LoadedSurface= SDL_LoadBMP("./maptest.bmp");
BackgroundImg = SDL_CreateTextureFromSurface( RenderEngine, LoadedSurface);
SDL_FreeSurface(LoadedSurface);
LoadedImage = SDL_LoadBMP("./sprite.bmp");
CharacterImg = SDL_CreateTextureFromSurface( RenderEngine, LoadedImage);
SDL_FreeSurface(LoadedImage);
SDL_Event event;
while (!gameover)
{
if (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
gameover = 1;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
case SDLK_q:
gameover = 1;
break;
}
}
break;
}
SDL_RenderClear(RenderEngine);
SDL_RenderCopy(RenderEngine, BackgroundImg, NULL, NULL);
SDL_RenderCopy(RenderEngine, CharacterImg, 120, 80);
SDL_RenderPresent(RenderEngine);
}
SDL_Quit();
}
Your code will quit the while-loop if any SDL_PollEvent happens:
while (!gameover)
{
if (SDL_PollEvent(&event)) //Any SDL_PollEvent that gets into if...
{
switch (event.type)
{
case SDL_QUIT:
gameover = 1;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
case SDLK_q:
gameover = 1;
break;
}
}
break; //...will eventually hit this break if it didn't break before
}
SDL_RenderClear(RenderEngine);
SDL_RenderCopy(RenderEngine, BackgroundImg, NULL, NULL);
SDL_RenderCopy(RenderEngine, CharacterImg, 120, 80);
SDL_RenderPresent(RenderEngine);
}

Overlapped text in an edit box WIN32

I've painted the background color of an edit box with WM_CTLCOLOREDIT and now when inputting/adding text , it is overlapping. How avoid this?
case WM_CTLCOLOREDIT:
{
if(IDC_TEXT1 == GetDlgCtrlID((HWND)lParam))
{
textArea1Brush = CreateSolidBrush(RGB(198, 226, 255));
SetBkMode((HDC)wParam, TRANSPARENT);
return(LONG)textArea1Brush;
}
break;
}