Customizing shapes using moving points by mouse - mfc

I want to make 4 clicks using mouse in the client area. Once the 4th click is done, the 4 points should be connected to form a shape.I did this using the following code.(I am using MFC).
void CChildView::OnLButtonDown(UINT nFlags,CPoint point)
{
CDC* pDC=GetDC();
if(m_iPointCount==1)
{
m_FirstPoint.x=point.x;
m_FirstPoint.y=point.y;
pDC->TextOut(m_FirstPoint.x,m_FirstPoint.y,"1");
rgn1.CreateEllipticRgn((m_FirstPoint.x-50),(m_FirstPoint.y-50),(m_FirstPoint.x+50),(m_FirstPoint.y+50));
}
if(m_iPointCount==2)
{
m_SecondPoint.x=point.x;
m_SecondPoint.y=point.y;
pDC->TextOut(m_SecondPoint.x,m_SecondPoint.y,"2");
rgn2.CreateEllipticRgn((m_SecondPoint.x-50),(m_SecondPoint.y-50),(m_SecondPoint.x+50),(m_SecondPoint.y+50));
}
if(m_iPointCount==3)
{
m_ThirdPoint.x=point.x;
m_ThirdPoint.y=point.y;
pDC->TextOut(m_ThirdPoint.x,m_ThirdPoint.y,"3");
rgn3.CreateEllipticRgn((m_ThirdPoint.x-50),(m_ThirdPoint.y-50),(m_ThirdPoint.x+50),(m_ThirdPoint.y+50));
}
if(m_iPointCount==4)
{
m_FourthPoint.x=point.x;
m_FourthPoint.y=point.y;
pDC->TextOut(m_FourthPoint.x,m_FourthPoint.y,"4");
rgn4.CreateEllipticRgn((m_FourthPoint.x-50),(m_FourthPoint.y-50),(m_FourthPoint.x+50),(m_FourthPoint.y+50));
pDC->MoveTo(m_FirstPoint.x,m_FirstPoint.y);
pDC->LineTo(m_SecondPoint.x,m_SecondPoint.y);
pDC->LineTo(m_ThirdPoint.x,m_ThirdPoint.y);
pDC->LineTo(m_FourthPoint.x,m_FourthPoint.y);
pDC->LineTo(m_FirstPoint.x,m_FirstPoint.y);
}
m_iPointCount++;
}
Each time the point count is incremented.I have also created 4 regions around 4 points.What I want to do now is, when I click in any of the regions I created and drag it to a new place the point should move to the new place where the mouse button is released after dragging. So that the shape is changed. This should be applicable to all the 4 regions.
I know I have to use Mousemove and LButtonUp functions but I have no idea how to do it. Pls help .

Hi I finally figured out how to do this.
The OnPaint event is as follows:
void CChildView::OnPaint()
{
CPaintDC dc(this); // device context for painting
{
dc.MoveTo(m_FirstPoint.x,m_FirstPoint.y);
dc.LineTo(m_SecondPoint.x,m_SecondPoint.y);
dc.LineTo(m_ThirdPoint.x,m_ThirdPoint.y);
dc.LineTo(m_FourthPoint.x,m_FourthPoint.y);
dc.LineTo(m_FirstPoint.x,m_FirstPoint.y);
}
}
The LButtonDown is as follows:
void CChildView::OnLButtonDown(UINT nFlags,CPoint point)
{
CDC* pDC=GetDC();
if(m_iPointCount==1)
{
m_FirstPoint.x=point.x;
m_FirstPoint.y=point.y;
pDC->TextOut(m_FirstPoint.x,m_FirstPoint.y,"1");
rgn1.CreateEllipticRgn((m_FirstPoint.x-50),(m_FirstPoint.y-50),(m_FirstPoint.x+50),(m_FirstPoint.y+50));
}
if(m_iPointCount==2)
{
m_SecondPoint.x=point.x;
m_SecondPoint.y=point.y;
pDC->TextOut(m_SecondPoint.x,m_SecondPoint.y,"2");
rgn2.CreateEllipticRgn((m_SecondPoint.x-50),(m_SecondPoint.y-50),(m_SecondPoint.x+50),(m_SecondPoint.y+50));
}
if(m_iPointCount==3)
{
m_ThirdPoint.x=point.x;
m_ThirdPoint.y=point.y;
pDC->TextOut(m_ThirdPoint.x,m_ThirdPoint.y,"3");
rgn3.CreateEllipticRgn((m_ThirdPoint.x-50),(m_ThirdPoint.y-50),(m_ThirdPoint.x+50),(m_ThirdPoint.y+50));
}
if(m_iPointCount==4)
{
m_FourthPoint.x=point.x;
m_FourthPoint.y=point.y;
pDC->TextOut(m_FourthPoint.x,m_FourthPoint.y,"4");
rgn4.CreateEllipticRgn((m_FourthPoint.x-50),(m_FourthPoint.y-50),(m_FourthPoint.x+50),(m_FourthPoint.y+50));
InvalidateRect(0);
}
if(m_iPointCount>4)
{
if(PtInRegion(rgn1,point.x,point.y))
{
m_fflag=true;
}
if(PtInRegion(rgn2,point.x,point.y))
{
m_sflag=true;
}
if(PtInRegion(rgn3,point.x,point.y))
{
m_tflag=true;
}
if(PtInRegion(rgn4,point.x,point.y))
{
m_foflag=true;
}
}
m_iPointCount++;
}
The MouseMove as follows:
void CChildView::OnMouseMove(UINT nFlags,CPoint point)
{
if(m_iPointCount>4)
if((nFlags & MK_LBUTTON)==MK_LBUTTON)
{
if(m_fflag==true)
{
m_FirstPoint=point;
InvalidateRect(0);
}
if(m_sflag==true)
{
m_SecondPoint=point;
InvalidateRect(0);
}
if(m_tflag==true)
{
m_ThirdPoint=point;
InvalidateRect(0);
}
if(m_foflag==true)
{
m_FourthPoint=point;
InvalidateRect(0);
}
}
}
The LButtonUp event is as follows:
void CChildView::OnLButtonUp(UINT nFlags,CPoint point)
{
CDC* pDC=GetDC();
if(m_fflag==true)
{
m_fflag=false;
rgn1.DeleteObject();
rgn1.CreateEllipticRgn((m_FirstPoint.x-50),(m_FirstPoint.y-50),(m_FirstPoint.x+50),(m_FirstPoint.y+50));
}
if(m_sflag==true)
{
m_sflag=false;
rgn2.DeleteObject();
rgn2.CreateEllipticRgn((m_SecondPoint.x-50),(m_SecondPoint.y-50),(m_SecondPoint.x+50),(m_SecondPoint.y+50));
}
if(m_tflag==true)
{
m_tflag=false;
rgn3.DeleteObject();
rgn3.CreateEllipticRgn((m_ThirdPoint.x-50),(m_ThirdPoint.y-50),(m_ThirdPoint.x+50),(m_ThirdPoint.y+50));
}
if(m_foflag==true)
{
m_foflag=false;
rgn4.DeleteObject();
rgn4.CreateEllipticRgn((m_FourthPoint.x-50),(m_FourthPoint.y-50),(m_FourthPoint.x+50),(m_FourthPoint.y+50));
}
}
Here is how this works:
1)An integer m_iPointCount is initialized to 1. This is used to store the number of points.
2) Four flags are initially set to false m_fflag=false;m_sflag=false;
m_tflag=false;m_foflag=false;(Four flags corresponds to four points of the polygon).
3)When the mouse is clicked for first 4 times the 4 points are saved in m_Firstpoint,m_Secondpoint,m_Thirdpoint and m_Fourthpoint.Correspondingly four regions are created(rgn1,rgn2,rgn3,rgn4 near to the 4 points). The 4 points are connected to form a polygon.
4)When the click is made for the 5th time(after we get the polygon),the check is made using if condition to find out the point lies in any one of the 4 regions.Accordingly the flags are set to true.(If the point lies in rgn1 then m_fflag is set to true and so on).
5)Consider the 5th click is made in rgn1 and now m_fflag is true,and the mouse is moved,Here the points used to draw the polygon in the paint message is updated and paint method is called using InvalidateRect(0). The polygon is redrawn.The m_Firstpoint is now updated to the new position.
6)When the mouse button is released after dragging,the flag is set to false and the old region is deleted and created near the new point.So that the region is also updated.
7) I have explained it for the first point, This is applicable for all the points.
Thanks.

Related

Unreal Engine 4: C++ Delegate not being called

I've been working on converting some blueprint logic over to C++. One of the things I have is a button. The button can be pressed in VR and has a delegate that is called to notify any registered functions that the button press occurred. Here is how the delegate is declared in the AButtonItem.h class.
#pragma once
#include "BaseItem.h"
#include "ButtonItem.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FButtonItemPressedSignatrue);
UCLASS()
class AButtonItem : public ABaseItem
{
GENERATED_BODY()
protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Touch)
float myMaxButtonPress;
public:
UPROPERTY(EditAnywhere, Category = Callback)
FButtonItemPressedSignatrue ButtonItem_OnPressed;
};
The delegate's broadcast function is then being called when the button is pressed like so:
ButtonItem_OnPressed.Broadcast();
(This function should defiantly be called because I have a debug statement that prints right before the call. Its also important to note this was all working when it was blueprint logic.)
Here is where I try to register with the delegate and how I declared the function that will be called:
WeaponMaker.h:
UFUNCTION()
void OnNextBladeButtonPressed();
WeaponMaker.cpp:
void AWeaponMaker::BeginPlay()
{
Super::BeginPlay();
TArray<USceneComponent*> weaponMakerComponents;
this->GetRootComponent()->GetChildrenComponents(true, weaponMakerComponents);
for (int componentIndex = 0; componentIndex < weaponMakerComponents.Num(); componentIndex++)
{
if (weaponMakerComponents[componentIndex]->GetName().Equals("NextBladeButton") == true)
{
myNextBladeButton = (AButtonItem*)weaponMakerComponents[componentIndex];
break;
}
}
if (myNextBladeButton != NULL)
{
myNextBladeButton->ButtonItem_OnPressed.AddDynamic(this, &AWeaponMaker::OnNextBladeButtonPressed);
}
}
I put a breakpoint and a print statement in the function OnNextBladeButtonPressed so I should immediately know when it works but its never happening. I also re-created the blueprint itself from scratch but still no luck. Sometimes on compile I get a crash due to the InvocationList being invalid but I haven't found much info on that issue either. Bottom line is, OnNextBladeButtonPressed is not getting called when it should be.
Edit: Here is where I call the broadcast function in my AButtonItem code. It seems to be getting called since i see the UE_LOG output in the console:
void AButtonItem::Tick(float deltaTime)
{
FTransform buttonWorldTransform;
FVector buttonLocalSpacePos;
FVector ownerLocalSpacePos;
FVector localDiff;
float buttonPressAmount;
if (myHasStarted == true)
{
Super::Tick(deltaTime);
if (myButtonComponent != NULL)
{
if (myPrimaryHand != NULL)
{
//Get the world space location of the button.
buttonWorldTransform = myButtonComponent->GetComponentTransform();
//Convert the location of the button and the location of the hand to local space.
buttonLocalSpacePos = buttonWorldTransform.InverseTransformPosition(myInitialOverlapPosition);
ownerLocalSpacePos = buttonWorldTransform.InverseTransformPosition(myPrimaryHand->GetControllerLocation() + (myPrimaryHand->GetControllerRotation().Vector() * myPrimaryHand->GetReachDistance()));
//Vector distance between button and hand in local space.
localDiff = ownerLocalSpacePos - buttonLocalSpacePos;
//Only interested in the z value difference.
buttonPressAmount = FMath::Clamp(FMath::Abs(localDiff.Z), 0.0f, myMaxButtonPress);
localDiff.Set(0.0f, 0.0f, buttonPressAmount);
//Set the new relative position of button based on the hand and the start button position.
myButtonComponent->SetRelativeLocation(myButtonInitialPosition - localDiff);
//UE_LOG(LogTemp, Error, TEXT("buttonPressAmount:%f"), buttonPressAmount);
if (buttonPressAmount >= myMaxButtonPress)
{
if (myHasBeenTouchedOnce == false)
{
//Fire button pressed delegate
if (ButtonItem_OnPressed.IsBound() == true)
{
ButtonItem_OnPressed.Broadcast();
AsyncTask(ENamedThreads::GameThread, [=]()
{
ButtonItem_OnPressed.Broadcast();
});
}
myHasBeenTouchedOnce = true;
myButtonComponent->SetScalarParameterValueOnMaterials("State", 1.0f);
Super::VibrateTouchingHands(EVibrationType::VE_TOUCH);
}
}
}
else
{
//Slowly reset the button position back to the initial position when not being touched.
FVector newPosition = FMath::VInterpTo(myButtonComponent->GetRelativeTransform().GetLocation(), myButtonInitialPosition, deltaTime, 10.0f);
myButtonComponent->SetRelativeLocation(newPosition);
}
}
}
}
First of all:
UPROPERTY(EditAnywhere, Category = Callback)
FButtonItemPressedSignatrue ButtonItem_OnPressed;
This should be:
UPROPERTY(BlueprintAssignable, Category = Callback)
FButtonItemPressedSignatrue ButtonItem_OnPressed;
For convenience.
Secondly the tick function may be called before begin play is executed for a number of reasons. Your even't won't be broadcasted if the game hasn't begin play yet. So to avoid just add a check in your tick function.
if(bHasBegunPlay)
{
// .. your logics ...
}
Sometimes on compile I get a crash due to the InvocationList being invalid but I haven't found much info on that issue either. Bottom line is, OnNextBladeButtonPressed is not getting called when it should be.
I don't see any issue in the code from the question. At my glance, the issue could be in different location. I would suspect that AWeaponMaker had been deleted at moment of broadcasting.

How do I assign a value in an array when a mouse is pressed SFML C++

I am trying to make a program where you are allowed to select between an option of shapes, and then drawing it. To allow for multiple shapes I created a vector of a class which creates shapes (Shapes are set up with the chosen function). My problem is the mouse click is too long, so it assigns it to everything in the vector, so you can't create a new shape. Is there a problem in my logic, or is there a problem in the code?
Here is my attempt:
for (auto& it : onCanvas) {
if (Mouse::isButtonPressed(Mouse::Left)) {
if (mousepointer.getGlobalBounds().intersects(circleOption.getGlobalBounds())) {
it.chosen(circles);
}
if (mousepointer.getGlobalBounds().intersects(rectOption.getGlobalBounds())) {
it.chosen(rectangle);
}
if (mousepointer.getGlobalBounds().intersects(triOption.getGlobalBounds())) {
it.chosen(triangles);
}
if (mousepointer.getGlobalBounds().intersects(it.shape.getGlobalBounds()) || it.dragging) {
it.shape.setPosition(mousepointer.getPosition());
it.dragging = true;
}
}
if (!Mouse::isButtonPressed) {
it.dragging = false;
}
win.draw(it.shape);
}
Your source-code is a bit incomplete (what is onCanvas and mousepointer). But I guess the problem is that this snippet is called multiple times while your mouse is clicked. To avoid that you can do two thing.
In the first solution you use events, so you only add shapes when the state of the mousebutton changes (you can additionally listen to the MouseButtonReleased to simulate a full click):
if (event.type == sf::Event::MouseButtonPressed)
{
if (event.mouseButton.button == sf::Mouse::Left)
{
// Hit Detection
}
}
or second solution you remember the last state of the button (probably do the mouse check once outside of the for loop):
bool mouse_was_up = true;
if (mouse_was_up && Mouse::isButtonPressed(Mouse::Left)) {
mouse_was_up = false;
for (auto& it : onCanvas) {
// Hit Detection
}
}
else if (!Mouse::isButtonPressed(Mouse::Left))
mouse_was_up = true;
I would rather stick to the first solution because when your click is too short and your gameloop is in another part of the game logic, you can miss the click.

MFC CControlBar

How do you figure out/determine (either from a control bar, or from the frame it is attached to) which side of the frame a CControlBar is attached to?
I know you can:
determine whether a controlbar is floating via BOOL IsFloating( ) const;
tell a controlbar which side of a frame it is allowed to connect to CBRS_ALIGN_TOP, AFX_IDW_DOCKBAR_TOP
But I don't know how to retrieve which side it has been docked to. Hope there is a method like CurrentlyDockedTo() which would return either CBRS_ALIGN_TOP, AFX_IDW_DOCKBAR_TOP ...
I am looking for the fastest way to figure out how much gray space is left in the main window ... the size of the gray rectange
You should be able to use GetBarStyle:
https://msdn.microsoft.com/en-us/library/6y1e7ff1.aspx
I found a very simple solution to my question. Exactly the answer I needed. The initial hint which led me on the correct path was found in the following post:
Detecting when a CControlBar's docking state has changed
The code which I was asking for was the following:
CPtrList& list = this->m_listControlBars;
POSITION pos = list.GetHeadPosition();
int total_cntrl_bars_found = 0;
while(pos)
{
CControlBar* pBar = (CControlBar*)list.GetNext(pos);
if(pBar)
{
if(!pBar->IsFloating())
{
total_cntrl_bars_found++;
int total_matched_styles = 0;
DWORD bar_style = pBar->GetBarStyle();
if(bar_style & CBRS_ORIENT_VERT)
{
// Then the bar is vertially oriented
// Will additionally also pass either the
// right oriented or left oriented check depending
total_matched_styles++;
}
if(bar_style & CBRS_ORIENT_HORZ)
{
// Then the bar is vertially oriented
total_matched_styles++;
}
if(bar_style & CBRS_ALIGN_RIGHT)
{
// Then the bar is right aligned
total_matched_styles++;
}
if(bar_style & CBRS_ALIGN_LEFT)
{
// Then the bar is left aligned
total_matched_styles++;
}
// There is also a check for top align
// and bottom aligned
}
}
}
here is some more info on GetBarStyle()
https://msdn.microsoft.com/en-us/library/6y1e7ff1.aspx

Clearing Scene And Flushing Variables in OpenGL

I have made a game in OpenGL, and also have added a menu item. when I right click on the OpenGL Screen, the menu item is displayed and I have added an option "Reset Game" in it. How Can I clear all the variables involved in the game by clicking on this (Any clear or flush function?).
Here is my code
glutCreateMenu(menu);
glutAddMenuEntry("Reset Game", 1);
void menu(int item)
{
switch (item)
{
case 1:
{
//Adding a function here to clear all the variables
}
break;
}
}
You just need to code up the routine to reset all your variables to their default values.
void Reset()
{
score = 0;
lives = 3;
// etc.
}
OpenGL doesn't know what these are so you have to do it yourself.

qslider sliderReleased value

I m trying to make a media player . The time status of the track is shown using QSlider. Track seek should happen when the user releases the slider somewhere on the QSlider. I had a look on the list of QSlider signals. The one that seems to fit is sliderReleased() which happens when the user releases the slider, but it does not get the latest value of where slider is. So to get sliders latest value I used sliderMoved() and stored reference.
Signal and slot connection
connect(this->ui->songProgress, SIGNAL(sliderMoved(int)), this,
SLOT(searchSliderMoved(int)));
connect(this->ui->songProgress, SIGNAL(sliderReleased()), this,
SLOT(searchSliderReleased()));
Functions
void MainWindow::searchSliderMoved(int search_percent)
{
value=this->ui->songProgress->value();
std::cout<<"Moved: Slider value"<<value<<std::endl;
}
Now I am Using the "value" variable inside searchSliderReleased for seeking
void MainWindow::searchSliderReleased()
{
std::cout<<"Released: Slider value"<<value<<std::endl;
emit search(value);//seek the track to location value
}
But the problem with above technique is that sliderMoved signal does not give the value where the slider is dropped but it give the location from where the slider was moved. How do I obtain the value where the slider was dropped?
You can use the valueChanged(int) signal of the slider, but set the flag
ui->horizontalSlider->setTracking(false);
Just finished building a DiectShow media player with QSlider here at work. Here's a few slot snippets on how I did it.
Widget::sliderPressed()
{
if( isPlaying() )
{
m_wasPlaying = true;
pause();
}
else
{
m_wasPlaying = false;
}
// Set a flag to denote slider drag is starting.
m_isSliderPressed = true;
}
Widget::sliderReleased()
{
if( m_wasPlaying )
{
play();
}
m_wasPlaying = false;
m_isSliderPressed = false;
}
Widget::valueChanged( int value )
{
if( m_isSliderPressed )
{
// Do seeking code here
}
else
{
// Sometime Qt when the user clicks the slider
// (no drag, just a click) Qt will signals
// pressed, released, valueChanged.
// So lets handle that here.
}
}
Had the same problem and calling sliderPosition() instead of value() directly when handling sliderReleased() worked for me.
I prefer to save the last value set by our app, like this pseudocode:
// Save our last value
lastSoftwareVal = 0;
// Set value from program
slider_set_value(value){
lastSoftwareVal = value;
slider.setValue(value)
}
// Slider on change callback
slider_on_change(value){
if(value == lastSoftwareVal){
// Value was changed by our app
return false;
}
// User has changed the value, do something
}