I have searched the web a lot but couldn't find exactly what I want!
suppose that I have a class derived from CWnd. In fact, it is the class COpenGLControl here in codeguru customized by me for my own purposes.
the event handler for the WM_MOUSEMOVE button is written as follows:
void COpenGLControl::OnMouseMove(UINT nFlags, CPoint point)
{
int diffX = (int)(point.x - m_fLastX);
int diffY = (int)(point.y - m_fLastY);
m_fLastX = (float)point.x;
m_fLastY = (float)point.y;
// Left mouse button
if (nFlags & MK_LBUTTON)
{
m_fRotX += (float)0.5f * diffY;
if ((m_fRotX > 360.0f) || (m_fRotX < -360.0f))
{
m_fRotX = 0.0f;
}
m_fRotY += (float)0.5f * diffX;
if ((m_fRotY > 360.0f) || (m_fRotY < -360.0f))
{
m_fRotY = 0.0f;
}
}
// Right mouse button
else if (nFlags & MK_RBUTTON)
{
m_fZoom -= (float)0.1f * diffY;
}
// Middle mouse button
else if (nFlags & MK_MBUTTON)
{
m_fPosX += (float)0.05f * diffX;
m_fPosY -= (float)0.05f * diffY;
}
OnDraw(NULL);
CWnd::OnMouseMove(nFlags, point);
}
But I don't want this event handler to be active or enabled at all times. I want to put three buttons on my dialog named pan,rotate and zoom.
when I click pan I want OnMouseMove get active just for middle button
when I click rotate I want middle button get inactive and left button get active
when I click zoom I want left button get inactive and right one get active and so.
and finally when I click another button like Zoom extent, select and etc, I want the OnMouseMove event handler get inactive in such a way that even if I'm on the opengl window the Maya-style mouse won't be active?
How can I implement something like this whether in my customized COpenGLControl class or in My MFC dialog?
Please give some instructions to me to begin my search to find out more.
------------------------------------------------------------------------------------------ Edited part of my question
I also thought about adding an event-handler manually to my class just like the OnDraw function in the COpenGLControl class so did something like this:
OpenGLContro.h
afx_msg void Pan(UINT nFlags, CPoint point);
OpenGLControl.cpp
void COpenGLControl::Pan(UINT nFlags, CPoint point)
{
int diffX = (int)(point.x - m_fLastX);
int diffY = (int)(point.y - m_fLastY);
if (nFlags & MK_MBUTTON)
{
m_fPosX += (float)0.05f * diffX;
m_fPosY -= (float)0.05f * diffY;
}
OnDraw(NULL);
}
and whenever the button pan is clicked I will call this function but there I'm not still on the OpenGL Window and don't know hat to pass as the parameters to the function Pan?
Add a state/mode member variable to the class and for each "mode" a dedicated handler function. The event handlers you use the mode variable to decide, which of the mode dependent handlers you call from the event handler, passing all the parameters.
Related
The code I wrote is below. I want to make the REGION_1 and REGION_2 buttons from images(or shapes).
I have 2 questions:
I couldn't see a function for addButton that has the image feature. Is there a way to use an image directly as the button itself?
Is there a way to make the buttons in the shape of rings? (No filled circles)
Here is the piece of my code and the screenshot from the UI:
Group RegionGroup = cp5.addGroup("REGIONS")
.setPosition(30,200)
.setWidth(150)
.setHeight(30)
.setFont(font2)
.moveTo(SetupGroup);
background(0);
noStroke();
;
cp5.addButton("REGION_1") // The button
.setPosition(40,10) // x and y relative to the group
.setSize(90, 50) // (width, height)
.setFont(font)
.moveTo(RegionGroup); // add it to the group
loadImage("button1.png"); //????
;
cp5.addButton("REGION_2") // The button
.setPosition(40,70) // x and y relative to the group
.setSize(90, 50) // (width, height)
.setFont(font)
.moveTo(RegionGroup); // add it to the group
loadImage("button2.png"); //?????
;
You should be able to call setImage() on the button instance, for example:
cp5.addButton("REGION_1") // The button
.setPosition(40,10) // x and y relative to the group
.setSize(90, 50) // (width, height)
.setFont(font)
.moveTo(RegionGroup)
.setImage(loadImage("button1.png")); // add it to the group
cp5.addButton("REGION_2") // The button
.setPosition(40,70) // x and y relative to the group
.setSize(90, 50) // (width, height)
.setFont(font)
.moveTo(RegionGroup)
.setImage(loadImage("button2.png")); // add it to the group
If you have four images representing the four button states you could also do something like .setImages(yourPImageArrayHere);
Regarding making the buttons in the shape of a circle, that would be possible via custom views, though the code would slightly more complex. You can use the ControlP5customView example as a starting point. Here's a modified version that displays the rings with no fills:
/**
* ControlP5 Custom View
*
*
* find a list of public methods available for the ControllerDisplay Controller
* at the bottom of this sketch.
*
* by Andreas Schlegel, 2012
* www.sojamo.de/libraries/controlp5
*
*/
import controlP5.*;
ControlP5 cp5;
void setup() {
size(400, 400);
smooth();
cp5 = new ControlP5(this);
cp5.addButton("hello")
.setPosition(50, 100)
.setSize(150,150)
.setView(new CircularButton())
;
cp5.addButton("world")
.setPosition(250, 100)
.setSize(50,50)
.setView(new CircularButton())
;
}
void draw() {
background(ControlP5.BLACK);
}
public void hello(int theValue) {
println("Hello pressed");
}
public void world(int theValue) {
println("World pressed");
}
/**
* to define a custom View for a controller use the ContollerView<T> interface
* T here must be replace by the name of the Controller class your custom View will be
* applied to. In our example T is replace by Button since we are aplpying the View
* to the Button instance create in setup. The ControllerView interface requires
* you to implement the display(PApplet, T) method. Same here, T must be replaced by
* the Controller class you are designing the custom view for, for us this is the
* Button class.
*/
class CircularButton implements ControllerView<Button> {
public void display(PGraphics theApplet, Button theButton) {
theApplet.pushMatrix();
theApplet.noFill();
theApplet.strokeWeight(9);
if (theButton.isInside()) {
if (theButton.isPressed()) { // button is pressed
theApplet.stroke(ControlP5.LIME);
} else { // mouse hovers the button
theApplet.stroke(ControlP5.YELLOW);
}
} else { // the mouse is located outside the button area
theApplet.stroke(ControlP5.GREEN);
}
theApplet.ellipse(0, 0, theButton.getWidth(), theButton.getHeight());
// center the caption label
int x = theButton.getWidth()/2 - theButton.getCaptionLabel().getWidth()/2;
int y = theButton.getHeight()/2 - theButton.getCaptionLabel().getHeight()/2;
translate(x, y);
theButton.getCaptionLabel().draw(theApplet);
theApplet.popMatrix();
}
}
/*
a list of all methods available for the ControllerView Controller
use ControlP5.printPublicMethodsFor(ControllerView.class);
to print the following list into the console.
You can find further details about class ControllerView in the javadoc.
Format:
ClassName : returnType methodName(parameter type)
controlP5.ControllerView : void display(PApplet, T)
*/
This is more complex but also flexible. If this is not something worthwhile you could probably get away with making rings with no fills as transparent png skins for the button (using setImage() / setImages())
When you click on the "dropdown" button of a combobox, the dropped down listbox appears below the combobox, unless there is not enough space below, in which case the listbox appears above.
Now I wonder if there is a possibility to force the lisbox to appear above the combobox, even if there is enough space below.
Illustration
When I click on the combo box, I'd like the "drop down" list box appear always above as on the left screen copy.
Everything is possible, and you don't need to implement the control "from scratch".
First, you can subclass the ListBox part of your ComboBox to get complete control over it, as explained in MSDN. You can create a class, derived from CListBox, using the Class Wizard. You only need to implement WM_WINPOSITIONCHANGING handler in it:
void CTopListBox::OnWindowPosChanging(WINDOWPOS* lpwndpos)
{
CListBox::OnWindowPosChanging(lpwndpos);
if ((lpwndpos->flags & SWP_NOMOVE) == 0)
{
lpwndpos->y -= lpwndpos->cy + 30;
}
}
Here, for simplicity, I am moving the box up by the (heights+30). You can get the height of your ComboBox instead of my 30.
Then you declare a member variable in your dialog class:
CTopListBox m_listbox;
and subclass it like that:
HBRUSH CMFCDlgDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if (nCtlColor == CTLCOLOR_LISTBOX)
{
if (m_listbox.GetSafeHwnd() == NULL)
{
m_listbox.SubclassWindow(pWnd->GetSafeHwnd());
CRect r;
m_listbox.GetWindowRect(r);
m_listbox.MoveWindow(r);
}
}
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
return hbr;
}
Note that I am calling m_listbox.MoveWindow(r) there; it is needed because first WM_CONTROLCOLOR message for that list box comes after it is positioned, so the very first time it would drop down instead of up.
Disclaimer: this is not a very clean solution, as, if you have windows animation enabled, you'd see that the list unrolls from top to bottom.
Alternatively, you should be able to "fool" the combobox that it is too close to the bottom of the screen; then it will drop up by itself. I leave it as an exercise for the readers :)
This would be relatively easy except when combo box has "slide open" effect. If you move the dropdown listbox to the top, and the combo slides open from top-to-bottom, it would look odd. So you have to disable the animation or reverse it.
In this function I call AnimateWindow in OnWindowPosChanging, it doesn't seem to cause any problems but I am not a 100% sure about it!
class CComboBox_ListBox : public CListBox
{
public:
CWnd *comboBox;
void OnWindowPosChanging(WINDOWPOS *wndpos)
{
CListBox::OnWindowPosChanging(wndpos);
if (comboBox && wndpos->cx && wndpos->cy && !(wndpos->flags & SWP_NOMOVE))
{
CRect rc;
comboBox->GetWindowRect(&rc);
//if listbox is at the bottom...
if (wndpos->y > rc.top) {
//if there is enough room for listbox to go on top...
if (rc.top > wndpos->cy) {
wndpos->y = rc.top - wndpos->cy;
BOOL animation;
SystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, &animation, 0);
//if combobox slides open...
if (animation) {
//we have to set the x coordinate otherwise listbox
//is in the wrong place when parent window moves
SetWindowPos(0, wndpos->x, wndpos->y, 0, 0,
SWP_NOSENDCHANGING | SWP_HIDEWINDOW | SWP_NOSIZE);
AnimateWindow(100, AW_VER_NEGATIVE);
}
}
}
}
}
DECLARE_MESSAGE_MAP()
};
Usage:
COMBOBOXINFO ci = { sizeof(COMBOBOXINFO) };
comboBox.GetComboBoxInfo(&ci);
CComboBox_ListBox *listBox = new CComboBox_ListBox;
listBox->comboBox = &comboBox;
listBox->SubclassWindow(ci.hwndList);
Also you can use SetMinVisibleItems to reduce the listbox height and make sure the dropdown list fits on top.
I am trying to implement a simple button in LibGDX 0.9.8 version that would change the screens on TouchUp event. However, Eclipse shows me yellow underlining on my overwrite of TouchUp method saying that it is not used anywhere.
public void resize(int width, int height) {
//Setting up stage failsafe
if(_stage == null){
_stage = new Stage(width, height, true);
}
_stage.clear();
Gdx.input.setInputProcessor(_stage);
TextButtonStyle style = new TextButtonStyle();
style.up = _buttonSkin.getDrawable("buttonUp");
style.down = _buttonSkin.getDrawable("buttonDown");
style.font = _font;
_startButton = new TextButton("START GAME" , style);
_exitButton = new TextButton("EXIT", style);
///
///PLACING BUTTONS
///
//start button
_startButton.setWidth(Gdx.graphics.getWidth() / 3);
_startButton.setHeight(Gdx.graphics.getHeight() / 4);
_startButton.setX((Gdx.graphics.getWidth() / 8) * 3);
_startButton.setY((Gdx.graphics.getHeight() / 5) * 3);
_startButton.setTouchable(Touchable.enabled);
_startButton.addListener(new InputListener(){
public boolean touchUp(InputEvent event, float x, float y, int pointer, int button) {
_game.setScreen(new World(_game));
System.out.print("up");
return true;
}
});
//adding buttons to scene
_stage.addActor(_startButton);
//_stage.addActor(_exitButton);
I did some research on the web and there were couple of posts saying that in some version of LibGDX this event method is absent so I did check the library and found my desired method in there.
In InputListener class :/** Called when a mouse button or a finger touch goes up anywhere, but only if touchDown previously returned true for the mouse
* button or touch. The touchUp event is always {#link Event#handle() handled}.
* #see InputEvent */
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
}
Anyone can see what am I doing wrong ? I am using the textbutton from com.badlogic.gdx.scenes.scene2d.ui.TextButton;
From the libgdx javadocs, it seems that the method you're looking for is.-
public boolean touchUp(int screenX, int screenY, int pointer, int button)
without parameter InputEvent event. Make sure you remove that extra parameter, declare the method as public, and add the tag #Override as #P.T. suggested.-
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
super.touchUp(screenX, screenY, pointer, button);
// Do your stuff here
}
I have Sprite object that is a poker chip. When the user clicks it the bid increase. I am increasing the bid on the MouseUp event. But if the user starts a click outside of the object/chip and then drags the mouse over the chip and does MouseUp, it fires the function mapped to MouseUp. How can I prevent it from firing if the click starts outside of the object.
this.addEventListener(MouseEvent.MOUSE_DOWN, pressChipDown)
this.addEventListener(MouseEvent.MOUSE_UP, pressChipUp)
this.addEventListener(MouseEvent.MOUSE_OUT, pressChipOut)
private function pressChipDown(e:MouseEvent):void
{
super.x = startX + 5;
super.y = startY + 5;
}
private function pressChipUp(e:MouseEvent):void
{
increaseBid();
super.x = startX;
super.y = startY;
}
private function pressChipOut(e:MouseEvent):void
{
if(e.buttonDown) //if mouse button is down, move chip back but dont increase bid
{
pressChipUp(MouseEvent.MOUSE_OUT as MouseEvent)
}
}
Thanks
On roll over, start listening to mouse down and mouse up, if up before down, it's a "fake"
this.addeventlistener(MouseEvent.ROLL_OVER, onOver)
...
Is there a way to limit mouse pointer movement to a specific area in wxWidgets? I know there is an API function ClipCursor() in Windows, but is there a method in wxWidgets for all platforms?
No. There is no such function in wx by all i know. Start up a timer (say 50ms) checking the global mouse position. If the mouse is outside the region, then set it into again.
If you want to restrict the mouse for some certain reason, for example to make some sort of game, then you can capture the mouse (see wxWindow::CaptureMouse). You will get mouse events even if the pointer is outside your window. Then you could react to mouse-motion events and do the check for the position there, without a timer. Downside of this is that the mouse won't be able to be used somewhere else for other programs since they won't receive events.
wxWidgets manual states that OSX guidelines forbid the programs to set the mouse pointer to a certain position programmatically. That might contribute to the reason there is not much support for such stuff in wx, especially since wx tries really hard to be compatible to everything possible.
Small sample. Click on the button to restrict the mouse to area 0,0,100,100. Click somewhere to release it.
#include <wx/wx.h>
namespace sample {
class MyWin : public wxFrame {
public:
MyWin()
:wxFrame(0, wxID_ANY, wxT("haha title")) {
mRestricted = wxRect(0, 0, 100, 100);
mLast = mRestricted.GetTopLeft();
wxButton * button = new wxButton(this, wxID_ANY, wxT("click this"));
}
private:
void OnClicked(wxCommandEvent& event) {
if(!HasCapture()) {
CaptureMouse();
CheckPosition();
}
}
void OnMotion(wxMouseEvent& event) {
CheckPosition();
}
void OnLeft(wxMouseEvent& event) {
if(HasCapture())
ReleaseMouse();
}
void CheckPosition() {
wxPoint pos = wxGetMousePosition();
if(!mRestricted.Contains(pos)) {
pos = ScreenToClient(mLast);
WarpPointer(pos.x, pos.y);
} else {
mLast = pos;
}
}
wxRect mRestricted;
wxPoint mLast;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(MyWin, wxFrame)
EVT_BUTTON(wxID_ANY, MyWin::OnClicked)
EVT_MOTION(MyWin::OnMotion)
EVT_LEFT_DOWN(MyWin::OnLeft)
END_EVENT_TABLE()
class MyApp : public wxApp {
virtual bool OnInit() {
MyWin * win = new MyWin;
win -> Show();
SetTopWindow(win);
return true;
}
};
} /* sample:: */
IMPLEMENT_APP(sample::MyApp)