Using OnScreenMenu with TCastleControl


#1

I’m trying to use OnScreenMenu on TCastleControl in Lazarus and the menu won’t appear. In the documentation the examples are just with TCastleWindow. I can’t figure what I’m doing wrong.


#2

Hi, Slender!
Hmm… It works for me:

procedure TForm1.FormCreate(Sender: TObject);
var
  MyMenu: TCastleOnScreenMenu;
  MenuItem: TCastleOnScreenMenuItem;
begin
  MyMenu := TCastleOnScreenMenu.Create(CastleControl1);
  MenuItem := TCastleOnScreenMenuItem.Create(MyMenu);
  MenuItem.Caption := 'Ku-Ku!';
  MyMenu.Add(MenuItem);
  CastleControl1.Controls.InsertFront(MyMenu);
end; 

2019-02-10-144743_1366x768_scrot


#3

Hi eugeneloza, I’m using lazarus components. Firstly I tried using TCastleButton, but then I tried using TCastleMenuButton but still not showing. I want to use button because I need the OnClick event to make a main menu screen for my school project. If you want I could give you the source code. Thanks for the reply anyway.


#4

First of all, use Castle Game Engine “unstable” from https://github.com/castle-engine/castle-engine/ if you play with TCastleOnScreenMenu. There has been a number of improvements to it in CGE 6.5. It now uses TCastleVerticalGroup inside.

As Eugene writes, you should place TCastleOnScreenMenuItem inside. TCastleOnScreenMenuItem has an OnClick event, exactly to capture the clicks on it, it is similar to TCastleButton in this regard.

It is possible to add other components to TCastleOnScreenMenu, even TCastleButton, like

Button := TCastleButton.Create(...);
MyOnScreenMenu.MenuItems.Insert(Button);

but you will in 90% cases want to add TCastleOnScreenMenuItem.

Note that (in CGE 6.5) you can also just resign from using TCastleOnScreenMenu, and instead use directly TCastleVerticalGroup with a number of TCastleButton as children. This will look differently (like a column of buttons), but also work perfectly, and TCastleButton can be styled to look in various ways.

Engine example examples/lazarus/model_3d_with_2d_controls (both in CGE 6.4 and 6.5) shows using TCastleOnScreenMenu on Lazarus form.


#5

P.S. When upgrading from CGE 6.4 to “unstable” 6.5, be sure to read https://github.com/castle-engine/castle-engine/wiki/Upgrading-to-Castle-Game-Engine-6.6 .

In particular, if you were dropping components from the component palette on LCL form, you may want to put {$define CASTLE_REGISTER_ALL_COMPONENTS_IN_LAZARUS} in the src/castleconf.inc, to avoid troubles.


#6

Thanks for the reply. I upgraded CGE and I tried the TCastleVerticalGroup method but still can’t figure out the problem :frowning: . Here’s a picture. sorry for bothering you so much…


#7

I’ll try to check the issue more carefully in some time (maybe not today). But the first thing that catches my attention is that you don’t add MenuItem to MainMenu - you just get a “transparent” TCastleVerticalGroup. You need to MainMenu.InsertFront(MenuItem); somewhere.
You’ll also get a memory leak this way (it’s very convenient to hunt for memory leaks by creating “debug” mode in Project Options).
P.S. I see you’re creating a Form which is fully covered by TCastleControl and no other LCL elements. I might suggest it’s more convenient to use TCastleWindow in this case (less distracting elements in program).


#8

I added MainMenu.InsertFront(MenuItem); but is still not appearing. And I’m using the Form method because I like to work with the object inspector and components, and I’m also using the LCL timer.
Also the code is a mess, I just want to make the core of the ‘game’(is more of a mini-game :sweat_smile:) and then cleaning the code.
I’ll wait for your reply and tell me if you need more info. Thanks again.


#9

Oh… I think I get it. Sorry for leading you a bit astray :slight_smile:
The actual problem is not in FormCreate, but in CastleControl1Render. When you mix Castle Controls and GL images you may get an unexpected result - this is what has happened.
Namely you add Castle Controls (i.e. MainMenu) to the CastleControl1, but it is rendered before calling CastleControl1Render, so you just draw your Background and Image on top of it, effectively hiding it below.
The solution is to use either one way or another (maybe @michalis will have a better idea). You should either use Castle Controls for everything or TGLImages. Here you can use TCastleImageControl instead of TGLImage for Background and Image (and all others). Then InsertFront (or InsertBack) would define the drawing order - make sure that Background is in the back, and MainMenu is somewhere closer to the front.


#10

Ok. I will try to convert all the images with TCastleImageControl instead and I think I will also downgrade to CGE 6.4 because in 6.5 I saw that some of the components in the Castle component palette are missing and I was used to work that way.

Thanks for your support.


#11

You can follow @michalis advice to restore them:

In particular, if you were dropping components from the component palette on LCL form, you may want to put {$define CASTLE_REGISTER_ALL_COMPONENTS_IN_LAZARUS} in the src/castleconf.inc , to avoid troubles.

It’s much better to use 6.5 version now, as it has a lot of new useful features (in improving UI elements, such as menu, images, buttons too) and is sufficiently stable.


#12

You can mix TGLImage with our UI controls without a problem, after all many UI components internally use TGLImage for rendering :slight_smile: But you cannot just put your rendering in one OnRender, this has no choice but to draw over the UI controls.

The solution is to create a descendant of TUIControl (better called TCastleUserInterface in CGE 6.5) and put your custom rendering in overridden TMyControl.Render. The manual page https://castle-engine.io/manual_2d_ui_custom_drawn.php shows exactly this. Then you add your instance of TMyControl at any place (in front/behind) as you need.

An alternative to remake your rendering to just use TCastleImageControl for rendering is also reasonable. It’s more work, but in the end it may be simpler.

Don’t downgrade to CGE 6.4 because of missing components on a palette, use the advice from my post to restore them:) They were removed because they were confusing to many, and in CGE 6.5 we have a new editor to design UI. So, CGE 6.5 is way better, and will soon become new stable CGE 6.6;)


#13

Thanks for your solutions and overall support. I will try them and hopefully make them work :grinning:


#14

Hello again, I have one more problem. I used {$define CASTLE_REGISTER_ALL_COMPONENTS_IN_LAZARUS} code to restore the components but they are broken.


#15


#16

Can you post here your .lfm file? You can attach or paste it here. Complete, or just a section inside

  object CastleButton1: TCastleButton
    CustomTextColorUse = False
    Caption = 'CastleButton1'
    ....
  end

This error should not happen if you upgrade CGE 6.4->6.5. But it may happen if you upgrade to CGE 6.5, change the form, save it, and then downgrade to CGE 6.4.


#17

I didn’t downgrade from CGE 6.5 to 6.4. I don’t know how to attach it so here’s a screenshot.


#18

Hm, you have weirdly small value at TUIControl_RealLeft there: 7.2...e-43. That’s a really really really tiny number. It’s almost as small as the smallest (positive) number you can put in Pascal Single, which is MinSingle = 1.5e-45.

I don’t know how this happened… In CGE 6.5, the Left (recorded as TUIControlPos_RealLeft) indeed changed from Integer to Single, but this change should go smoothly when upgrading from CGE 6.4 to 6.5 (LFM reader will read Integer OK in my tests, and just write it as Single next time). If you can reproduce this in a clean project, please submit a bugreport.

In any case, solution for now is simple: just edit this lfm file and remove the

TUIControl_RealLeft = 7.2...e-43

line. It will change to simple 0 at next read.


#19

Ok, now I had time to try this and it’s not working for me. I removed the line and at the next read nothing is replaced and the error still appears and when I create a new component from the component palette the same value is attributed. Maybe I did something wrong when I updated to CGE 6.5 ?


#20

I tried to use TCastleUserInterface to put a button in front but I can’t get it to work. I read the manual page but I still can’t understand what I’m doing wrong. If you could get a peek at the screenshots would be perfect.