Reputation: 3962
I have a button, and I want it to react according to the actions of the user. Here it is:
You can see that it has 4 different states. A first one is when no perticular action is performed (NONE
), a second one is when the mouse pointer hovers the button (HOVER
), a third one when the mouse is currently clicking on the button (ONCLICK
), and the last one when the button has been clicked (SELECTED
).
Even if we don't care that much, the button map is as following:
These states are presenting as an enum:
enum button_states { NONE, HOVER, ONCLICK, SELECTED, BSTATE_LAST };
Now I tried some code to change the state of the button, code which is executed in an infinite loop. I have a variable prevState
that hold the state before the last click, and a variable previouslyClicked
that worth 1 if the click was active last loop iteration and worth 0 else.
if (CursorIsOnTheButton()) {
if (LeftClickIsActive()) {
if (actualState != ONCLICK)
prevState = actualState ;
previouslyClicked = 1;
actualState = ONCLICK;
}
else if (prevState == SELECTED && previouslyClicked) {
actualState = HOVER;
prevState = NONE;
previouslyClicked = 0;
}
else if (prevState == HOVER && previouslyClicked) {
actualState = SELECTED;
prevState = NONE;
previouslyClicked = 0;
}
else
actualState = HOVER;
}
else if (actualState != SELECTED)
actualState = NONE;
It works fine except for the SELECTED state: the button never goes into that state.
What did I do wrong?
Upvotes: 0
Views: 5666
Reputation: 23226
Your code is written to exclude SELECTED from ever being used in either block:
if (CursorIsOnTheButton()) {
if (LeftClickIsActive()) {
//if execution flow ever goes into this section...
//(i.e. if SELECTED is set here, because you are in this block, it cannot be recognized by the
//else if block, because it can only go in there if it did NOT go into this one.)
}
}
//...it will never go into the else if
else if (actualState != SELECTED)
actualState = NONE;
Modify your code to include the SELECTED state in the same block as other states.
Would adding this code section to the if block:
else if (actualState == SELECTED) {
//do something
}
Solve the problem?
Upvotes: 1
Reputation: 16540
you have 4 event states to handle, plus the external -force- to 'none'
the following should give you a very good guide as to how to handle the state changes
if state is 'none'
switch event
case mousein:
set state = 'hover'
break
case mousedown:
set state = 'onclick'
break
case mouseup:
set state = 'selected'
break
case mouseout:
break
default:
break
end switch
elseif state is 'hover'
switch event
case mouseout:
set state = 'none'
break
case mousedown:
set state = 'onclick'
break
case mouseup:
break
case mousein:
break
default:
break
end switch
elseif state is 'onclick'
switch event
case mouseout:
set state = 'selected'
set all other button state values to 'none'
break
case mouseup:
set state = 'selected'
set all other button state values to 'none'
break
case mousedown:
break
case mousein:
break
default:
break
end switch
elseif state is 'selected'
switch event
case mousein:
break
case mousedown:
break
case mouseup:
break
case mouseout:
break
default:
break
end switch
endif
Upvotes: 0
Reputation: 2420
Create a function like this... and whenever you mark something to selected you call it passing the recent selected buttong as the 3rd parameter
void ClearOthers("Array of buttons" buttons[], int amountOfButtons, int selected)
{
for(int i = 0; i < amountOfButtons; i++)
if(i != selected)
button[i].State = NONE
}
I think you can simplify your problem...
Use 2 booleans, the actualState starts as false (not selecteded)
A button is either selected or not...
If you click it (and stop the click with mouse over it still) then it changes to selected
Any animation you want to do... you just need to use the 4 possible combinations of those booleans...
if (CursorIsOnTheButton())
{
if (LeftClickIsActive())
beingClicked = true;
// If the user was clicking and released the click with the mouse
// still hovering the button, beingclicked will be true and the button will be
// marked as clicked
else if (beingClicked)
{
beingClicked = false;
actualState = true;
}
}
else
beingClicked = false;
Upvotes: 1
Reputation: 29126
Well, I'll have a go, too. I suggest a reorganisation of state variables. Get rid of the actual and previous states and just use one state
for the button appearance, which will be set in our pseudocode snippet. Get rid of previouslyClicked
(which is equivalent to state == ONCLICK
) and introduce pressed
which is true if the button is pressed and false if it isn't:
if (CursorIsOnTheButton()) {
if (LeftClickIsActive()) {
if (state != ONCLICK) pressed = !pressed;
state = ONCLICK;
} else {
state = (pressed) ? SELECTED : HOVER;
}
} else {
state = (pressed) ? SELECTED : NONE;
}
The ONCLICK
state does double duty here; it marks the state "clicking just now" and also ensures that the button isn't flipped on and off during one long mouse-button press. All other states are determined by a simple logic:
pressed? in button? clicking? state
------------ ------------ ------------ ------------
true dontcare dontcare SELECTED
false true true ONCLICK
false true false HOVER
false false dontcare NONE
This approach has the advantage that you can check the button's depression state with pressed
, wheras otherwise you'd have to check for the states.
It's still only pseudocode, which means I haven't tested it, of course.
Upvotes: 1
Reputation: 3962
Based on vmp answer and all of your great help, I solved that problem.
I used vmp's variables actualSelected
and beingClicked
, but not as boolean, to store the ID of both selected and clicked buttons.
Let me explain, I think I didn't left enough informations to you to solve this thing. I've not only one button but an array of them, buttons[NBUTTONS]
is their states, and they should act exactly like radiobuttons.
for (int i = 0; i < NBUTTONS; i++) {
if (IsMouseOnButton(button[i]) {
if (LeftClickIsActive()) {
beingClicked = i;
buttons[i] = ONCLICK;
}
else if (beingClicked == i) {
actualSelected = i;
beingClicked = -1;
for (int j = 0; j < NBUTTONS; j++)
buttons[i] = NONE;
buttons[i] = SELECTED;
}
else if (actualSelected != i) {
buttons[i] = HOVER;
}
}
else if (selected != i)
buttons[i] = NONE;
}
Upvotes: 0