Modal window , unmovable and centered at parent.

BlitzMax Forums/BlitzMax Beginners Area/Modal window , unmovable and centered at parent.

Takis76(Posted 2012) [#1]
Hello ,

I would like to ask how to make some window be modal (not allows all other windows around to be selected and make it unmovable)

If I remove the WINDOW_TITLEBAR from window creation the window is unmovable because there is no title bar to handle and move it.

Is it possible and this window to be centered on the parent window , the main application window.

WINDOW_CENTER centers the window according to the screen.

Thank you :)


GfK(Posted 2012) [#2]
So, you're after the equivalent of an MDI child form in C# etc? Don't think it's possible.


shinkiro1(Posted 2012) [#3]
If WINDOW_CENTER doesn't work make your own function (use GadgetX(), GadgetWidth() etc.) and then use ModifyGadget to set it's position. So you could just reset the position to the middle of the screen whenever the user tries to move the window.

Just remember to stick with conventions on your platform.


jsp(Posted 2012) [#4]
Disable all other windows:
DisableGadget(MainWindow)

Either create the modal window or set the shape:
SetGadgetShape( WindowOnTop:TGadget, GadgetX(MainWindow)+GadgetWidth(MainWindow)/2 -GadgetWidth(WindowOnTop)/2, GadgetY(MainWindow)+GadgetHeight(MainWindow)/2 -GadgetHeight(WindowOnTop)/2,w,h )
to center the new window on top of the MainWindow

Show the window you want if not yet visible or hidden underneath under windows:
ShowGadget(WindowOnTop)

But having said that, do use modal dialogs only if absolute needed, most of the time it is not.
If I do use a program it often happens that I want to look up something while the dialog is open and I can't and I really hate that and probably all other user as well...


Takis76(Posted 2012) [#5]
Is it possible to add minimize button to the main window and the maximize button be disabled and only the window will be restored?


Takis76(Posted 2012) [#6]
JSP your function does the work , but you can move (drag) the window and then the window returns to the center position of the parent window.

But the window is still able to be dragged , but return to center when dropped.

If we assume this is not bad. I will remove the caption bar so the window will not able to be moved or not even dragged at all.

I discover and another one problem.
If you select the application from the taskbar , you are loosing the focus of the new window and the parent window the main window covers the window on top. And the parent window is disabled so then you have one disabled window and the application stucks , because the on top window is hidden from the task bar , because is a WINDOW_TOOL.

How do I know if the focus of the window on top was lost to re activate it?


SLotman(Posted 2012) [#7]
Can't you just create 2 windows, then set the parent on the second one as the first one? Just use the API call SetWindowParent.

If I remember well, you could also use Win32 API call ShowWindow(hWnd,SW_MODAL) to make the modal window you want.

(This is only on Windows, so you're asking something for MacOS or Linux, I have no idea if its even possible)


jsp(Posted 2012) [#8]
If you select the application from the taskbar , you are loosing the focus of the new window and the parent window the main window covers the window on top. And the parent window is disabled so then you have one disabled window and the application stucks , because the on top window is hidden from the task bar , because is a WINDOW_TOOL.


Your window create function is wrong.
You need to refer to the main window as parent like this:
CreateWindow:TGadget(name$,x,y,w,h, MainWindow:TGadget ,style)
Having done this your tool window will always stay on top.

Why it is important that the user is not allowed to drag your dialog window?

Last edited 2012


jsp(Posted 2012) [#9]
Is it possible to add minimize button to the main window and the maximize button be disabled and only the window will be restored?


SetMaxWindowSize( window:TGadget,w,h )
Calling this function will disable the Maximize button window hint on Windows, and will limit the window zoom size on Mac OS X.


Takis76(Posted 2012) [#10]
The dialog window must be static , for cosmetic purpose only :P

This dialog window opens my door creation tool for my dungeon.
If you move it , you see trails in the parent window and the trails disappears with to release the mouse.

And if you select the main application window from the task bar , the application window comes in front and covers the dialog window in back.


main_window = CreateWindow(AppTitle, 0, 0, 1018, 700, Null, WINDOW_TITLEBAR | WINDOW_CENTER | WINDOW_MENU)


Is this wrong?

Ahaa I got it.

The correct code on the dialog window

The main window creation
main_window = CreateWindow(AppTitle, 0, 0, 1018, 700, Null, WINDOW_TITLEBAR | WINDOW_CENTER | WINDOW_MENU)



The dialog creation
door_options_window = CreateWindow("Door Creation", 100, 100, 500, 200, main_window, WINDOW_TITLEBAR | WINDOW_CENTER | WINDOW_TOOL)


As a group gadget instead of null I put main_window.

This keeps my dialog window in front without the main_window hides the door_options_window.

The only thing is to make it not movable , I will make it as canvas gadget like the main window.

Or I will remove the caption bar to make it not movable.

Last edited 2012


jsp(Posted 2012) [#11]
Is this wrong?

No, the mainwindow has Null as parent, so that's ok.
Just use the Mainwindow as parent for the dialog window.

If you move it , you see trails in the parent window and the trails disappears with to release the mouse.

If you see trails then the canvas is not redrawn.
I think you had a hook function, when redrawing on windowmove event this would not happen.
Just check that your redraw does not hang up again.


Takis76(Posted 2012) [#12]
I uploaded the new version to see the effect:

https://www.box.com/s/99c823d46963aa2e6b67

How to add canvas redraw during window dragging?

Last edited 2012


jsp(Posted 2012) [#13]
Put this in your init routine:

AddHook EmitEventHook , MyHook

And this function just as it is comfortable:

[bbcode]Function MyHook:Object(iId:Int,tData:Object,tContext:Object)
Local Event:TEvent=TEvent(tData)

If event=Null Return Null

If (Event.ID = EVENT_WINDOWSIZE) Or (Event.ID = EVENT_WINDOWMOVE) Or (Event.ID = Event_APPRESUME) Then
Redraw() '<---- your redraw routine should go here
End If

Return tData
End Function
[/bbcode]

This should trigger a redraw when a window is resized (your editor is not??) , a window is moved (as your tool window on top) and when the application is resumed (and thus was may covered by some other window).


Takis76(Posted 2012) [#14]
Where do I put the

AddHook EmitEventHook , MyHook

I put the function in the main loop and the program lags when I am moving the window.
I put the function just before the main loop and nothing happens.

I put the function AddHook EmitEventHook , MyHook in EVENT_WINDOWMOVE and the progam seems to addhooks and become slow.


	If EventID() = EVENT_WINDOWMOVE Then
		
		
		If editor.door_options_open = 1 Then
		
			If EventSource() = door_options_window
			
			ActivateGadget(main_window)
			AddHook EmitEventHook, MyHook
			SetGadgetShape( door_options_window, GadgetX(main_window)+GadgetWidth(main_window)/2 -GadgetWidth(door_options_window)/2, GadgetY(main_window)+GadgetHeight(main_window)/2 -GadgetHeight(door_options_window)/2,500,200 )
			
			End If
		EndIf
		
	End If



If I put in Redraw() area the

SetGadgetShape(door_options_window, GadgetX(main_window) + GadgetWidth(main_window) / 2 - GadgetWidth(door_options_window) / 2, GadgetY(main_window) + GadgetHeight(main_window) / 2 - GadgetHeight(door_options_window) / 2, 500, 200)


I am very near to make the window not movable.

The Idea might be when I will drag the window the mouse button will be released and not allows the window be moved.

Also I put removehook

	If EventID() = EVENT_WINDOWMOVE Then
		
		
		If editor.door_options_open = 1 Then
		
			If EventSource() = door_options_window
			
			ActivateGadget(main_window)
			AddHook EmitEventHook, MyHook
			SetGadgetShape( door_options_window, GadgetX(main_window)+GadgetWidth(main_window)/2 -GadgetWidth(door_options_window)/2, GadgetY(main_window)+GadgetHeight(main_window)/2 -GadgetHeight(door_options_window)/2,500,200 )
			RemoveHook EmitEventHook, MyHook
			End If
		EndIf
		
	End If



Because add hooks and the becomes slow.

I updated my file:

https://www.box.com/s/99c823d46963aa2e6b67

Source code included.

If I will remode the

SetGadgetShape(door_options_window, GadgetX(main_window) + GadgetWidth(main_window) / 2 - GadgetWidth(door_options_window) / 2, GadgetY(main_window) + GadgetHeight(main_window) / 2 - GadgetHeight(door_options_window) / 2, 500, 200)


From the hook , the window appears well , but I am near to make it not moving.


jsp(Posted 2012) [#15]
Put the AddHook EmitEventHook , MyHook
just somewhere at the start of the program.

It should only run once!, not under an event where it adds more and more hooks, you need only one hook.

The SetGadgetShape is normally not meant to sit in a redraw function, because then it will be called every time you update your display, but you show the door options window only very seldom...
Best to have a canvas redraw routine doing nothing else then take care about the canvas. Also best not to mix logic and render functions, although it works it is a hell to maintain.

A bit too late for today I may have time tomorrow to have a look at the source.


Takis76(Posted 2012) [#16]
Thank you very very much , I see you tomorrow.


jsp(Posted 2012) [#17]
I had a look and sorry to be a pain in the ass, but you should do some more changes to your structure.

I know the program is working for you as it is now, but again it will be very difficult to maintain the stuff while you add additional code.

Some advice, ignore as you like:
Try to have different modules in your program

An init part where you initialize all stuff needed (load fonts, pictures, set variables, define constants and so on)

Then have a logic part and do only logic things here (if mouse clicked then store position (don't draw here), if var door = open then ... )

Then have one draw routine (Function) which does draw everything needed to update your canvas (don't do any logic here, only like if door=open then drawdoor() and so on)

In an application the WaitEvent() Loop is more or less the logic part, every logic is called upon event. The user pressed the left mouse button, you got an event and the logic behind processes it and for example store the mouse position. Whenever your display changes call the draw routine or do it again via an event or if you use animations via a timertick event.
When doing the draw routine just ask for the position of the mouse (stored during the logic step) and draw your mouse frame for example and so on.

So why do I not just come up with a solution and you are done?
The problem is, in the current structure the hook can't be implemented just easy, because there is no redraw function alone but a mixed thing.

It is thus serious that there is an endless loop in your code!

Please put directly after the WaitEvent() command this:
Print CurrentEvent.ToString() 'for testing only of course
You will see a constant GADGETPAINT Loop, this happens because you call a RedrawGadget(graphics_canvas) inside your GADGETPAINT routine.
Actually it is very very seldom needed to redraw a certain gadget. The trick is to just call the draw function which updates the canvas.

First you should fix the endless loop and then it will be much easier to implement new stuff.

So again, ignore me if this all too much, but it would help you in the long run.
And for the moment just remove all references to the hook, we may can come back to it later.


TaskMaster(Posted 2012) [#18]
You shouldn't keep a user from moving a window. It is very irritating. Also, keeping it from showing on the task bar is irritating.


Takis76(Posted 2012) [#19]
I changed to unmovable window
And not shows in the taskbar.


JSP , I am not ignore you and I listen what you say , because you have helped a lot.

As I have understand so far , the GADGETPAINT redraws all canvases.
Infact the flip command updates the graphics of the canvases.

What kind of endless loop do I have?
In the main loop are the events of my game.

The EVENT_MOUSEMOVE events , is in the main loop and I am checking the EventX() and EventY() and I know the courdinates of the pixels in the graphics canvas gadget as you have said to have only one canvas. I have map and my mouse x,y and I update my mouse x and y for every canvas and opened window.

The EVENT_MENUACTION event is on the main game loop to control my menus.

I have the SetGraphics CanvasGraphics() in the game loop to update my canvases.

The type editor.

editor.door_options_open = 1
editor.map_options_open = 1
editor.save_adventure_options_open = 1
editor.adventure_properties_open = 1

These variables takes values from 0 to 1.
Only one of them take 1 and other take value 0.

I use these variables in type editor to know which of options is open in the program.

These options are in the main game loop too.

Each of these options change my graphics canvas to avoid show all options in the main window. Everything in the main window appears in the main canvas , each window or dialog box have only one canvas.

If my Adventure Properties are open the variable editor.save_adventure_options_open takes value=1 and I know if the user opened the Adventure Properties the same with other variables.
:)

Last edited 2012


jsp(Posted 2012) [#20]
As I have understand so far , the GADGETPAINT redraws all canvases.


No, not really. The GADGETPAINT event will be generated when the canvas wanted to be updated.
For example you opened another window and that window was covering the canvas, when you now move or close the window on top the canvas generated that event to tell YOU to update the canvas with whatever you wanted to show.
To make it short you should call your canvas redraw function when this event occurs.
And it is normally wise to call here a function and not to put all draw commands directly, because it will for you easier if you need to call that function yourself.

For example create a redraw function (for every canvas one)
[bbcode]
Function Redraw()
SetGraphics CanvasGraphics(graphics_canvas)
SetViewport 0, 0, GadgetWidth(graphics_canvas), GadgetHeight(graphics_canvas)

'CLS only if needed
'Draw Background (Picture or tiles...)
'If whatever draw on top for example mouseframe
'...

Flip
End Function
[/bbcode]
At the moment you set several times SetGraphics CanvasGraphics(graphics_canvas), but you need it actually only once in this function. The same for the Flip. One Flip and only in that function. Try to keep it simple and don't spread Flips somewhere else.

What kind of endless loop do I have?

As said before put the:
Print CurrentEvent.ToString()
underneath the Waitevent()
The output of the print is the event WaitEvent() just received and is now being processed in your loop.

What you will see immediately is that the GADGETPAINT event will be generated without stopping.
This happens because you have RedrawGadget(graphics_canvas) underneath the GADGETPAINT event in the code. So the event says, please redraw me and while doing this you say plase redraw the gadget which will issue another event to inform you to redraw the canvas.

The point here is that when you rem out the RedrawGadget command then your program does not work correctly because you mixed logic and render.
It's not that bad, you have all the code, it just need to be restructured.

I think, start with a new and fresh Redraw() function and take out step by step all RedrawGadget commands and put this function under the GADGETPAINT event, that would be a good start.
Where you need to update the canvas call only this function.


Takis76(Posted 2012) [#21]
I will make a lots of changes , but I would like to ask,

The hook function does meke the redraw of all gadgets?

Or if I will put the flip and RedrawGadget functions in the hook?

I have one new test code to see if you like the source structure.

https://www.box.com/s/48f338c439d4bfa66371


jsp(Posted 2012) [#22]
The hook function does meke the redraw of all gadgets?

No, your own redraw function will draw everything and on flip the canvas will be updated with what you have drawn during the last flip.
So if you need a redraw for whatever reason, call your own function to do it.

The hook function does have a completely other role. And there are different ones like FlipHook, EmitEventHook (this one we use as seen in the example above).
When an event occurs in the system it is given to all functions who hooked into it via the EmitEventHook ID.
One of those hook functions is also used by BlitzMax itself to build the WaitEvent queue.

That means using a hook functions is a more direct access to an event then using the WaitEvent queue.
But that does not mean that a hook is better, because the WaitEvent queue filters automatically double entries for certain event types (timertick or gadgetaction for example) and helps you not to flood your application with it. Additionally you have some nice commands to use the event queue yourself.

So when using a hook add it only once to the program, normally at the start or program init phase.
And inside the hook check for those events you want a direct response to your program. If you act on a WINDOWMOVE which may distorted the canvas content with trails then call here again your own redraw function. The drawback of this is of course, when your draw function takes very long your program again hangs for some time, because no double event is filtered and every event need to be processed.

I looked into your testcode and it is already much cleaner and you use now Strict (you could even use Superstrict).

Now add step by step what you need inside the event loop.
Add the GADGETPAINT Event again and put the Redraw() underneath, for the moment it is called on every event.

Update all things you want to draw to your redraw function, start with the background and then other stuff on top to keep the z-order.

If a certain event forces you to update the canvas just call the redraw() function (or post a GADGETPAINT event yourself).


Takis76(Posted 2012) [#23]
What is a difference between Strict and Superstrict. What Strict command does?

I saw , all kinds of Strict commands not allows you Goto command in your code. Why , some time I was needed the goto command to bypass something and I wasn't allowed and I removed the Strict command completely.

When I will have some small update I will send a new version.
Is it possible to send the updates in your e-mail?


jsp(Posted 2012) [#24]
SuperStrict means that variables and functions have an explicit type.
Also Integer variables have to be defined.
It's only very little more typing, but saves you a lot of headache during debugging or that some nasty problems don't even happen.

If this is too much use at least Strict, don't go without, your code will also run slightly faster.
The "strictness" also don't allow Goto, because it would result in spaghetti code.
As probably 95% of the user here use Strict or Superstrict you can be sure you don't need a Goto. If you think you need, then the code needs some redesign.

You can send stuff to my email, but it should not be that huge, keep it as small as possible.
You could always send me the download link if you don't want to post it here.


Takis76(Posted 2012) [#25]
I would like to ask and about toolbars.

Today I tried to make some toolbar.
I have one image (long image) with the button icons.

What is the difference between this:

Toolbar = MaxGUI_Driver.CreateGadget(GADGET_TOOLBAR,"",x,y,w,h,group,Style)



And this:

toolbar= CreateToolbar(sourceObject,x,y,w,h,group,style)


As I understood with experiments the source object is one long image with icons which will be the visible buttons.

I created one long image with the graphics of the buttons.


toolbar= CreateToolbar("Toolbar.png",0,0,24,24,main_window,0)


Then I understood each of the images the createtoolbar function create the button according to the width and height of the image.

I have 10 icons in the long image and the button index of the toolbars is from 0 to 9

Then I used this code:

	AddGadgetItem toolbar, "", GADGETITEM_TOGGLE, 0, "Wall Tool"
	AddGadgetItem toolbar, "", GADGETITEM_TOGGLE, 1, "Door Tool"
	AddGadgetItem toolbar, "", GADGETITEM_TOGGLE, 2, "Wall Decoration Tool"
	AddGadgetItem toolbar, "", GADGETITEM_TOGGLE, 3, "Fake Wall Tool"
	AddGadgetItem toolbar, "", GADGETITEM_TOGGLE, 4, "Secret Button Tool"
	AddGadgetItem toolbar, "", GADGETITEM_TOGGLE, 5, "Stairs UP Tool"
	AddGadgetItem toolbar, "", GADGETITEM_TOGGLE, 6, "Stairs DOWN Tool"
	AddGadgetItem toolbar, "", GADGETITEM_TOGGLE, 7, "Keylock Tool"
	AddGadgetItem toolbar, "", GADGETITEM_TOGGLE, 8, "Switch Tool"
	AddGadgetItem toolbar, "", GADGETITEM_TOGGLE, 9, "Alcove Tool"


The option GADGETITEM_TOGGLE make each of the buttons remains down.

when I am pressing some of the buttons the icon of the button change and becomes the graphic of the next icon.

And how to make each of the toggled buttons restore (untoggle) when you pressing one other button from toolbar?

And how to change the image to other image when the button is toggled.

As you have seen some of my code , each selected button becomes green.

This will save some code and I will have less graphics on the graphics canvas.

In the demos you have seen , I used the toolbar as graphical images on the canvas , now is a real toolbar.

I think is time to use the smart buttons I have purchased but I don't have made a research yet.

Last edited 2012


jsp(Posted 2012) [#26]
MaxGUI_Driver.CreateGadget(GADGET_TOOLBAR,"",x,y,w,h,group,Style)

You won't normally use this one, but as difference it specifies the namespace. Only important if you wanted to write your own function with the same name.

CreateToolbar("Toolbar.png",0,0,24,24,main_window,0)

Use this function

The option GADGETITEM_TOGGLE make each of the buttons remains down.
when I am pressing some of the buttons the icon of the button change and becomes the graphic of the next icon.

If you specify GADGETITEM_TOGGLE for a certain icon, it needs two(!) graphics. The first is normally shown and the second when pressed down. Those images can be different or use just twice the same.

And how to make each of the toggled buttons restore (untoggle) when you pressing one other button from toolbar?

The toolbar is not a radio button thing. If you want that behavior you have to write it yourself.
Normally every button can be clicked or toggled independently.


Takis76(Posted 2012) [#27]
I made it.


Takis76(Posted 2012) [#28]
JSP , do you have some idea how to use smart buttons?


And something else , sometimes when I am moving some window on top of the main window the window leave trails and sometimes the window don't leave trails.
Why this happens?

Last edited 2012


jsp(Posted 2012) [#29]
JSP , do you have some idea how to use smart buttons?

SmartButtons are made for Logic Gui so the best method would be to use the tools provided. Although you could create them manually it would take you far more time.

First you could create them with the SmartButton Editor and when done, put them just into the SmartButton folder of Logic Gui. They will be available in the Gadget-TreeView then and can be added to the form like any other gadget.
When added to the form, Logic Gui will produce all needed source code for you.
If you don't create your program in Logic Gui, you can just copy the code you need over.

The SmartButton module itself has complete help available, but first use the manual (version 1.3) for the editor, that should be easier and also the Logic Gui user manual Chapter 7.17

some window on top of the main window the window leave trails and sometimes the window don't leave trails.

If a window leaves trails depends if the movement does generate events you could act on and of course that you act on. For example your own floating window on top generates events and thus you redraw the canvas, but a system requester (loading a file) will not and thus produce trails.