Hi,
How can I change the color of CustomTextColor method of een button when I move the cursor over the button text?
Change this Castle Game Engine: CastleControls: Class TCastleButton ?
Or perhaps use this Castle Game Engine: CastleControls: Class TCastleButton ?
Perhaps, use it here Castle Game Engine: CastleUIControls: Class TCastleUserInterface
And here Castle Game Engine: CastleUIControls: Class TCastleUserInterface
Thanks for your reply.
Yeah, I read the API but don’t understand it quite without examples.
After some attempts with ChatGPT I got this
procedure MouseMove(const Sender: TObject; const Event: TInputMotion;
const Position: TVector2);
begin
if ViewMain.OptionButton1.RenderRect.Contains(Position) then
ViewMain.OptionButton1.CustomTextColor := Yellow
else
ViewMain.OptionButton1.CustomTextColor := White;
end;
But when I call it with
ViewMain.OptionButton1.OnInternalMouseEnter:= @MouseMove;
I got this error:
Any idea what is wrong here?
what is the text of the error? pictures are very hard to read
Error: Incompatible types: got “<address of procedure(const TObject;const TInputMotion;const TGenericVector2);Register>”expected “procedure variable type of procedure(const TCastleUserInterface) of object;Register>”
Well that is exactly what it says, you try to assign a varible as wrong, incompatible data type.
You have to provide the different procedure and FPC even told you the signature.
You have to create the
procedure TSomeMyObject.SomeProcName(const TCastleUserInterface);
And that procedure you would probably be able to assign to that variable.
https://www.freepascal.org/docs-html/ref/refse17.html
https://docwiki.embarcadero.com/RADStudio/Sydney/en/Procedural_Types_(Delphi)
Thanks for the links but I have no clue. Even chatGPT repeatedly makes a pointer that does not work here:
procedure MouseMove(Sender: TObject; const Event: TInputMotion;
const Position: TVector2);
begin
if Sender is TCastleButton then
begin
if (Position.X >= TCastleButton(Sender).RenderRect.Left) and
(Position.X <= TCastleButton(Sender).RenderRect.Right) and
(Position.Y >= TCastleButton(Sender).RenderRect.Bottom) and
(Position.Y <= TCastleButton(Sender).RenderRect.Top) then
TCastleButton(Sender).CustomTextColor := Yellow
else
TCastleButton(Sender).CustomTextColor := White;
end;
end;
OptionButton1.OnInternalMouseEnter := @MouseMove;
The error Incompatible types: got “<address of procedure(const TObject;const TInputMotion;const TGenericVector2);Register>”expected “procedure variable type of procedure(const TCastleUserInterface) of object;Register>” is when this pointer is used.
chatGPT knows no sense and hence can make no sense, they are just statistical tools, data-miners (to use previous buzz word about it), “even chatGPT” sounds like “even the butterfly on the dandellion out my door” - it is normal they have no clue
You have to learn language basics.
- Data types
- in particular, procedural data types
- object-oriented design
- in particular, “object methods” or “class methods” as a special kind of a procedure, and “procedure (…) of object” as a special kind of procedural type
You have to provide the different procedure and FPC even told you the signature.
You have to create the
procedure TSomeMyObject.SomeProcName(const TCastleUserInterface);
See also
The output of ChatGPT is indeed wrong all over the place. It is similar to the correct answer, but absolutely cannot be used blindly.
Also in this case you don’t need to use OnInternalMouseEnter. It could be used to solve this, but there’s a simpler solution that doesn’t require it in this case.
Assign OnUpdate
handler that watches whether mouse is over the button, and changes the color as you wish. Something like
procedure TMyView.MyButtonUpdate(const Sender: TCastleUserInterface;
const SecondsPassed: Single; var HandleInput: Boolean);
begin
if MyButton.Focused then
MyButton.CustomTextColor := SomeColor
else
MyButton.CustomTextColor := OtherColor;
end;
and assign it in view Start
like
MyButton.OnUpdate := @MyButtonUpdate;
Yes, that’s why I need your expertise.
Thanks for the update procedure, it works fine and I have expanded it with “Pressed” conditons after “Focused”. so I can use this procedure for more actions at once. Thanks!
Glad you’re back
Why the event veing called onINTERNALmouseenter rather than regular OnMouseEnter ?
This naming is suspicious
OnUpdate
solution requires an extra if
which the MouseEnter/MouseLeave solutions do not, so it is not simpler.
Also, i suspect it to be worse on performance:
- OnUpdate would probably get called many times more, that actual entering and exiting would happen.
- Every call would be slower due to having to check the conditions, which can even be delegated to complex callers
- Many redundant calls of .CustomTextColors := same value as before
I see you just want to keep people away from the OnInternalxxxx events, despite those been made exactly for the problem announced (“when I move the cursor over”)
The OnInternalMouseEnter/Leave
have Internal
in the name because some semantics of them are not precisely defined in some edge-cases, and in fact may change in future implementation.
- what happens if you destroy the control over which the mouse was?
- Or move it around – what if you move it suddenly by 1000 pixels or to different parent?
- Or if you animate UI and move it just slightly to right?
- What if view is stopped or paused?
- What if user resizes window by keyboard and causes mouse to no longer be over control this way?
- Also, are the names really OK? They talk about “mouse” but really work based “pointer focus” in CGE and make sense on mobile too.
In all these cases there’s a question should the engine try aggressively make sure that every OnInternalMouseEnter
is matched with OnInternalMouseLeave
, or maybe sometimes this guarantee is not necessary. Making this guarantee in some cases would complicate the code significantly.
… And maybe at some point we’ll just have to do this.
But for now, I decided this is not necessary – I didn’t see a convincing argument where these events are desperately needed.
I indeed don’t encourage people to use internal stuff. “Internal” means it can disappear / change meaning / or be renamed to non-internal at any moment. In the ideal future, there must be a way to do everything without using “internal” stuff.
Performance isn’t very relevant here. It’s just an if. And setter with ignore assignment to the same color. This has practically zero effect on execution speed. So don’t worry about performance, write code that is easy to maintain.
same as with any other event, no? is OnUpdate
any different with regard to sudden Sender.Destroy
?
Well, good implementation would handle it. And i am not saying that is simple to make - it is not.
There is also one more edge case, Alt+Tab to another application
And if-less code is easier, when everything else the same.
Otherwise we would still make the Windows application ussing nested case in a single mega-loop, like it was all but required in Win16 era.
Granted, if the events are not reliable, then “everything else the same” is not held
By “what happens” I meant here “do we emit OnInternalMouseLeave just before the control is destroyed, and then OnInternalMouseEnter immediately afterwards for the control that was underneath”? That is not clarified at this point, and that’s one reason why these events are internal for now, and discouraged from use.
Naturally destroying the controls in Update
will work, but the question is basicallly “how rigorously do we make sure that every possible OnInternalMouseEnter
is matched with OnInternalMouseLeave
on the same control, and how soon it happens (e.g. can it have 1-frame delay in case of Ui animations)”.