Jump to content
Developer Wiki and Function Reference Links ×

Simple Custom Dialog examples?


SamIWas

Recommended Posts

I've done plenty of Vectorscript, having written several dozen including my own custom Vectorworks to lighting console 3d/patch exporter.  So I'm no stranger to coding.

 

I am trying to learn to make some basic custom dialogs , but every example I look at just melts my brain.  I can't even figure out what relates to what and how the information in the fields gets passed to the rest of the script.  I've read over all the ones listed on the developer page and tried to break them down, to no avail.  I've used the Dialog Builder, but it's not the layout I have issues  with.

 

All I'm looking for is to create a dialog with a few text edit boxes, maybe a checkbox or two, and possibly a drop-down with basic user-entry info.  I've succeeded in creating the layout with the fields and tested those out, and gotten a report on whether I clicked "Cancel" or "OK".  

 

Now, I just need to figure out how to pass the information that is typed into a text box or selected in a drop down to a simple variable.  But it seems that even something that simple involves all sorts of complicated coding.  Is there something I'm missing here?

Link to comment

Have you written the dialog event handler?  This is what you pass to RunNamedDialog that tells VW how to respond to each UI event. 

 

You use GetItemText to set a variable to the value in a text field. You generally get all dialog data in the event handler when the user presses the ok button. Use global variables to access the data outside the handler. 

 

Is there a specific example we can help you parse?

 

-Josh 

Link to comment
2 hours ago, JBenghiat said:

Have you written the dialog event handler?  This is what you pass to RunNamedDialog that tells VW how to respond to each UI event. 

 

You use GetItemText to set a variable to the value in a text field. You generally get all dialog data in the event handler when the user presses the ok button. Use global variables to access the data outside the handler. 

 

Is there a specific example we can help you parse?

 

-Josh 

 

Hey Josh,

 

I have not written the handler.  That's where I get confused looking at others' scripts, trying to figure out their handler and function parts and how it all relates.

 

Here is my code so far.  I can clean up the layout later, and this was just something to learn.  But all I want to do from here is pass 6 to the Universe field in the Lighting Device record, and pass 7 to the Address field.  And if 8 is checked (want to make this the default but still looking into that), it will run 7 through a script to format it.  I think if I can get those basics down, I can then dig into the meat of it all.

 

Thanks for any help...I know you're the master at this stuff!

 

Procedure DIALOG;

VAR
    id : LONGINT;
    result : LONGINT;
    
BEGIN

    id:=CreateLayout('Assign Address',FALSE,'Apply','Cancel');
    
    CreateStaticText(id,4,'Assign Universe:',-1);
    CreateStaticText(id,5,'Assign Address:',-1);
    CreateEditInteger(id,6,0,6);
    CreateEditInteger(id,7,0,6);
    CreateCheckBox(id,8,'Use three digits for address');
    
    SetFirstLayoutItem(id,4);
    SetRightItem(id,4,6,0,0);
    SetBelowItem(id,4,5,0,0);
    SetRightItem(id,5,7,0,0);
    SetBelowItem(id,5,8,0,0);
    
    SetHelpText(id,6,'Enter universe here');
    SetHelpText(id,7,'Enter DMX address here');
    SetHelpText(id,7,'Check if DMX address should have 3 digits. Exaample: DMX 45 = 045');
    
    result:=RunLayoutDialog(id,NIL);
    
    Message(result);
    
END;
RUN(DIALOG);

 

 

dialog.jpg

Link to comment

As far as one to parse the meaning of, here's a simple dialog to create a rectangle.  It may have come from this site somewhere...

 

In red is what is confusing....

 

Procedure DialogTest;

TYPE
U_RECT = STRUCTURE
    a: REAL;
    b: REAL;
END;

VAR
gRectObj: U_RECT;

FUNCTION SetUpDialog(rectObj: U_RECT): LONGINT;
VAR
    ID: LONGINT;
BEGIN
ID:= CreateLayout('Rect Dimensions',TRUE,'OK','Cancel');

{Text fields}
CreateStaticText( ID, 05, 'Value-a', 15);
CreateStaticText( ID, 06, 'Value-b', 15);

{Box fields}
CreateEditReal( ID, 15, 1, rectObj.a, 10);
CreateEditReal( ID, 16, 1, rectObj.b, 10);

{Text layout}
SetFirstLayoutItem( ID, 05);
SetBelowItem( ID, 05, 06, 0, 0);

{Box layout}
SetRightItem( ID, 05, 15, 0, 0);
SetRightItem( ID, 06, 16, 0, 0);

SetHelpText(ID, 1,'Click to accept values');
SetHelpText(ID, 2,'Click to cancel operation');
SetHelpText(ID, 15,'Enter width');
SetHelpText(ID, 16,'Enter height');

SetUpDialog:= ID;
END;


FUNCTION GetRect(VAR rectObj: U_RECT): BOOLEAN;
VAR
    a,b: REAL;
    ID,dlogResult: LONGINT;

    PROCEDURE DriveDialog(VAR item:LONGINT; data:LONGINT);
    VAR
        i,choiceNo: INTEGER;
        foundName: BOOLEAN;
    BEGIN
    CASE item OF
        SetupDialogC:
            BEGIN
            END;
        1: {OK}
            BEGIN
            IF GetEditReal(ID,15,1,a) THEN
                rectObj.a:= a;
            IF GetEditReal(ID,16,1,b) THEN
                rectObj.b:= b;
            END;
        2: {Cancel}
            BEGIN
            END;
        END;
    END;

BEGIN
GetRect:= FALSE;
ID:= SetUpDialog(rectObj);
IF VerifyLayout(ID) THEN
    BEGIN
    dlogResult:= RunLayoutDialog(ID,DriveDialog);
    IF dlogResult = 1 THEN
        GetRect:= TRUE;
    END
ELSE
    AlrtDialog('Cannot create the dialog');

END;

BEGIN
gRectObj.a:= 1.25;
gRectObj.b:= 2.64;
IF GetRect(gRectObj) THEN
BEGIN

Rect(0,0,gRectObj.a,gRectObj.b);
END;
END;
Run(DialogTest);

Link to comment

I've tabbed the code to make it easier to read:

 

Procedure DialogTest;
TYPE
	U_RECT = STRUCTURE
    	a: REAL;
    	b: REAL;
	END;

VAR
	gRectObj: U_RECT;

FUNCTION SetUpDialog(rectObj: U_RECT): LONGINT;
	VAR
	    ID: LONGINT;

		BEGIN
			ID:= CreateLayout('Rect Dimensions',TRUE,'OK','Cancel');
			{Text fields}
			CreateStaticText( ID, 05, 'Value-a', 15);
			CreateStaticText( ID, 06, 'Value-b', 15);
			{Box fields}
			CreateEditReal( ID, 15, 1, rectObj.a, 10);
			CreateEditReal( ID, 16, 1, rectObj.b, 10);
			{Text layout}
			SetFirstLayoutItem( ID, 05);
			SetBelowItem( ID, 05, 06, 0, 0);
			{Box layout}
			SetRightItem( ID, 05, 15, 0, 0);
			SetRightItem( ID, 06, 16, 0, 0);
			SetHelpText(ID, 1,'Click to accept values');
			SetHelpText(ID, 2,'Click to cancel operation');
			SetHelpText(ID, 15,'Enter width');
			SetHelpText(ID, 16,'Enter height');
			SetUpDialog:= ID;
		END;

FUNCTION GetRect(VAR rectObj: U_RECT): BOOLEAN;
	VAR
	    a,b: REAL;
	    ID,dlogResult: LONGINT;

    PROCEDURE DriveDialog(VAR item:LONGINT; data:LONGINT);
	    VAR
	        i,choiceNo: INTEGER;
	        foundName: BOOLEAN;
	    BEGIN
		    CASE item OF
		        SetupDialogC:
		            BEGIN
		            END;
		        1: {OK}
		            BEGIN
			            IF GetEditReal(ID,15,1,a) THEN
			                rectObj.a:= a;
			            IF GetEditReal(ID,16,1,b) THEN
			                rectObj.b:= b;
		            END;
		        2: {Cancel}
		            BEGIN
		            END;
		        END;
    	END;

	BEGIN
		GetRect:= FALSE;
		ID:= SetUpDialog(rectObj);
		IF VerifyLayout(ID) THEN
		    BEGIN
		    dlogResult:= RunLayoutDialog(ID,DriveDialog);
		    IF dlogResult = 1 THEN
		        GetRect:= TRUE;
		    END
		ELSE
		    AlrtDialog('Cannot create the dialog');
	END;

BEGIN
	gRectObj.a:= 1.25;
	gRectObj.b:= 2.64;
	IF GetRect(gRectObj) THEN
		BEGIN
			Rect(0,0,gRectObj.a,gRectObj.b);
		END;
END;

Run(DialogTest);

 

(1)

'gRectObj' is a user-defined variable type. Declared a couple lines up:

TYPE
U_RECT = STRUCTURE
    a: REAL;
    b: REAL;
	END;

 

(2)

The GetEditReal(ID,15,1,a) and GetEditReal(ID,16,1,b) calls are retrieving data from the dialog item (15, 16), storing each in 'a' and 'b' respectively. and the "IF" statement in those lines are basically saying, if there is a real number stored in those dialog items, store them in as the rectObj.a, and rectObj.b variables. As you can see the custom/user defined variable U_RECT has two components to it a,b. So rectObj is a U_RECT type of variable, having these two components.

More info on GetEditReal : http://developer.vectorworks.net/index.php/VS:GetEditReal

 

(3)

	BEGIN
		GetRect:= FALSE;
		ID:= SetUpDialog(rectObj);
		IF VerifyLayout(ID) THEN
		    BEGIN
		    dlogResult:= RunLayoutDialog(ID,DriveDialog);
		    IF dlogResult = 1 THEN
		        GetRect:= TRUE;
		    END
		ELSE
		    AlrtDialog('Cannot create the dialog');
	END;

This is the main code of the FUNCTION > GetRect(VAR rectObj: U_RECT): BOOLEAN

 

(4)

	IF GetRect(gRectObj) THEN
		BEGIN
			Rect(0,0,gRectObj.a,gRectObj.b);
		END;

This is basically saying if the function GetRect returns TRUE then draw the rectangle.

 

Hope this helps

Tui

 

 

Link to comment

Just to comment on the overall code structure as well, when you run the dialog, you provide the ID of the dialog and the name of a procedure for handling the dialog events (DriveDialog).  This procedure runs every time the user interacts with the dialog, looping until the user has selected OK or cancel.  The procedure uses two variables that get set to the ID of the item with which the user has interacted, and sometimes additional information (in this case item and data).  VS has two special constants, SetupDialogC and SetDownDialogC, that let the procedure know the dialog is about to display and is about to close, respectively.  This SetUpDialogC is where you would set any default values.

 

Because the dialog handler is a self-contained procedure, you need global variables (simply a variable defined in the scope of the main program) for storing any results you want to access outside of the dialog handler.  Usually, you set these values during the OK event (item = 1).

 

HTH,

Josh

Link to comment

Just to comment on the overall code structure as well, when you run the dialog, you provide the ID of the dialog and the name of a procedure for handling the dialog events (DriveDialog).  This procedure runs every time the user interacts with the dialog, looping until the user has selected OK or cancel.  The procedure uses two variables that get set to the ID of the item with which the user has interacted, and sometimes additional information (in this case item and data).  VS has two special constants, SetupDialogC and SetDownDialogC, that let the procedure know the dialog is about to display and is about to close, respectively.  This SetUpDialogC is where you would set any default values.

 

Because the dialog handler is a self-contained procedure, you need global variables (simply a variable defined in the scope of the main program) for storing any results you want to access outside of the dialog handler.  Usually, you set these values during the OK event (item = 1).

 

HTH,

Josh

  • Like 1
Link to comment
19 minutes ago, twk said:

Interesting @JBenghiat.. I never knew of the SetDownDialogC. What is that normally used for? or How would you use that?

 

Thanks

Tui

 

I really don't use it much, but that would be the place to do things like save the dialog position.  There is also a ResizeDilogC for when the user has resized the dialog.

 

-Josh

  • Like 1
Link to comment
  • 2 weeks later...

I've been experimenting some more, and decided that the examples I was working with were too complicated to learn from.  So I found a much simpler one, but still have a question or two...

 

-------------------------------------------------------------

Procedure test; 

 

var

    gValue : integer;

 

function Mydialog(var lValue:integer):boolean; VAR

 

  id :INTEGER;

  result  :INTEGER;

 

 

 

PROCEDURE Dialog_Handler(VAR item :LONGINT; data :LONGINT);

    var Bool: boolean; 

    

    BEGIN

 

        GetBooleanItem(id, 5, Bool); if Bool THEN lValue := 0;

        GetBooleanItem(id, 6, Bool); if Bool THEN lValue := 2;

        GetBooleanItem(id, 7, Bool); if Bool THEN lValue := -1;

    END;

 

BEGIN

 

    id := CreateLayout('Set Visibility', FALSE, 'OK', 'Cancel');

    CreateGroupBox(id,4,'Visibility:',true);

    CreateRadioButton(id,5,'Show');

    CreateRadioButton(id,6,'Grey');

    CreateRadioButton(id,7,'Hide');

 

    SetFirstLayoutItem(id,4);

    SetFirstGroupItem(id,4,5);

    SetBelowItem(id,5,6,0,0);

    SetBelowItem(id,6,7,0,0);

 

    result := RunLayoutDialog(id, Dialog_Handler);

 

    if result = 2 then Mydialog := false else Mydialog := true;

END; {Mydialog}

 

begin {main} 

 

    if Mydialog(gValue) then

 

        begin

        message(concat(gValue));

 

   end;

end; {main} 

 

run(test);

 

-------------------------------------------------------------

So, the part that is blue is a no-brianer.  Not worried about that at all.  I'll start with questions...

 

gValue is specified as a variable for procedure "test" as an integer.  But, nowhere in the script is gValue given a value.  During a function, a value is given to variable lValue.  But at the end of the script, a message displays gValue with the value given to lValue.   Where is gValue being given its value from lValue?  

 

In Procedure Dialog_Handler, I know i can add in GetItemText calls to retrieve strings from CreateEditText boxes and GetEditInteger/Real calls to retrieve numbers from CreateEditInteger/Real boxes in the layout.  I assume that I need extra variables of String, Integer, and Real types to collect the info.  So, let's say I do the following (changes in red)

 

function Mydialog(var lValue:integer;univ:string):boolean; VAR

 

  id :INTEGER;

  result  :INTEGER;

 

PROCEDURE Dialog_Handler(VAR item :LONGINT; data :LONGINT);

    var Bool: boolean; 

    

    BEGIN

        GetItemText(id, 8, univ);

        GetBooleanItem(id, 5, Bool); if Bool THEN lValue := 0;

        GetBooleanItem(id, 6, Bool); if Bool THEN lValue := 2;

        GetBooleanItem(id, 7, Bool); if Bool THEN lValue := -1;

    END;

 

 

How does univ get passed down?  Did I even put univ in the right place?  At some point, something is going to click, and I'll be able to fully grasp what is going on start writing more complex dialogs.

Link to comment

First off, this example is a little non-standard, and the dialog handler really isn't a proper handler, and will only work for demonstration purposes.  This may not actually be a great example to try and emulate.

 

The argument in Mydialog() has the keyword VAR in front of it, and would be a pointer in other programming languages: lValue doesn't actually store a LONGINT, but rather the address of another LONGINT variable.  In this case, when you pass gValue to Mydialog, Mydialog effectively substitutes the variable name gValue every time you see lValue.  It's a bit of a cleaner way to deal with scope, though because the dialog handler takes specific arguments, lValue really becomes a global in Mydialog.

 

The answer to your question of fetching the text value depends on the scope where you need it.  Let's say you want to just extend this example 

 

In the scope of test, define the variable:

gTxtValue :STRING;

 

Define the function Mydialog as:

function Mydialog(VAR lValue :integer; VAR lTxtValue :STRING) :boolean;

 

Call mydialog:

...Mydialog(gValue, gTxtValue)...

 

and of course retrieving the field value would be:

GetItemTextID(id, 8, lTxtValue);

 

The dialog handler here is fairly incomplete, as you constantly retrieve values for every dialog event.  You really want a CASE statement so that the right part of the code executes for each "item" with which the user interacts.  Retrieving the values into your globals would only be in the case that the user clicks the OK button, item = 1.

 

Your questions seem to be more related to VectorScript variables and scope rather than dialogs specifically, so I highly recommend starting here for the language fundamentals: http://developer.vectorworks.net/images/7/72/VectorScriptGuide.pdf  VS is based on Pascal, so you can also investigate Pascal basics, though note that VS is a proprietary version of the language.  If you are new to programming in general, I recommend learning Python instead.  The VS and Python API have identical commands, but with Python you are learning a contemporary programming language with a simpler syntax.

 

HTH,
Josh

Link to comment
3 hours ago, JBenghiat said:

First off, this example is a little non-standard, and the dialog handler really isn't a proper handler, and will only work for demonstration purposes.  This may not actually be a great example to try and emulate.

 

The argument in Mydialog() has the keyword VAR in front of it, and would be a pointer in other programming languages: lValue doesn't actually store a LONGINT, but rather the address of another LONGINT variable.  In this case, when you pass gValue to Mydialog, Mydialog effectively substitutes the variable name gValue every time you see lValue.  It's a bit of a cleaner way to deal with scope, though because the dialog handler takes specific arguments, lValue really becomes a global in Mydialog.

 

The answer to your question of fetching the text value depends on the scope where you need it.  Let's say you want to just extend this example 

 

In the scope of test, define the variable:

gTxtValue :STRING;

 

Define the function Mydialog as:

function Mydialog(VAR lValue :integer; VAR lTxtValue :STRING) :boolean;

 

Call mydialog:

...Mydialog(gValue, gTxtValue)...

 

and of course retrieving the field value would be:

GetItemTextID(id, 8, lTxtValue);

 

The dialog handler here is fairly incomplete, as you constantly retrieve values for every dialog event.  You really want a CASE statement so that the right part of the code executes for each "item" with which the user interacts.  Retrieving the values into your globals would only be in the case that the user clicks the OK button, item = 1.

 

Your questions seem to be more related to VectorScript variables and scope rather than dialogs specifically, so I highly recommend starting here for the language fundamentals: http://developer.vectorworks.net/images/7/72/VectorScriptGuide.pdf  VS is based on Pascal, so you can also investigate Pascal basics, though note that VS is a proprietary version of the language.  If you are new to programming in general, I recommend learning Python instead.  The VS and Python API have identical commands, but with Python you are learning a contemporary programming language with a simpler syntax.

 

HTH,
Josh

 

Thanks for the info Josh...I'll keep plugging along using your help above.  

 

I knew it probably wasn't the best example, but simpler examples have been hard to find.  And what you see above is after I cleaned up the spacing, tabs, and lines!

 

Not really new to programming.  I've written over 100 VectorScripts so far to do all sorts of things, including my own custom GrandMA exporter (because I don't like the official one).   So far, I've used the standard built-in dialogs.  There's just something about the way this custom dialog thing works that isn't connecting in my brain.  Seems like it could be so much simpler!

 

Link to comment

Okay...I'm 95% comfortable with what's going on now.   I've got variables passing between the main part and the dialog handler, and reporting at the end.  The only exception is the text field, ID 6 (it's a text field just for testing purposes).  It doesn't pass to the message at the end.   Everything else works as intended, and I think I have the dialog handler written more correctly.

 

So, if you can point me where I'm going wrong on the text field, I will owe you my eternal gratitude, and hopefully put this thread to a close!

 

Procedure AssignInfo; 

var
	gValue,gAddr: integer;
	gUniv:STRING;

function Mydialog(var lValue,lAddr:integer;lUniv:STRING):boolean;

VAR

	id :INTEGER;
	result  :INTEGER;


	PROCEDURE Dialog_Handler(VAR item :LONGINT; data :LONGINT);
		var Bool: boolean; 
		tUniv:String;
		tAddr:integer;

		BEGIN
		CASE item OF
			SetupDialogC:
				BEGIN
					SetItemText(id,6,'0');
					SetEditInteger(id,7,0);
					SetBooleanItem(id,8,TRUE);
				END;
			1:
				BEGIN
					GetItemText(id,6,lUniv);
					If GetEditInteger(id,7,TAddr) then lAddr:=TAddr;
					GetBooleanItem(id, 8, Bool); if Bool THEN lValue := 1;
				END;
			2:
				BEGIN
				END;
		END; {case}
	END; {Dialog Handler}

BEGIN
	id:=CreateLayout('Assign Address',TRUE,'Apply','Cancel');
	
	CreateStaticText(id,4,'Assign Universe:',-1);
	CreateStaticText(id,5,'Assign Address:',-1);
	CreateEditText(id,6,'0',6);
	CreateEditInteger(id,7,0,6);
	CreateCheckBox(id,8,'Use three digits for address');
	
	SetFirstLayoutItem(id,4);
	SetRightItem(id,4,6,0,0);
	SetBelowItem(id,4,5,0,0);
	SetRightItem(id,5,7,0,0);
	SetBelowItem(id,5,8,0,0);
	
	SetHelpText(id,6,'Enter Universe');
	SetHelpText(id,7,'Enter DMX Address  ');
	SetHelpText(id,8,'Convert DMX address to 3 digits. Example: 45 = 045');

	result := RunLayoutDialog(id, Dialog_Handler);

	if result = 2 then Mydialog := false else Mydialog := true;
END; {Mydialog}

begin {main} 

	if Mydialog(gValue,gAddr,gUniv) then
		begin

		message('Universe is ',gUniv,' / Address is ',gAddr,' / Checkbox value is ',gValue);

   end;
end; {main} 

run(AssignInfo);

 

Link to comment

Hello Sam,

   You need to make IUniv a variable parameter in your function declaration of MyDialog().

 

change:

function Mydialog(var lValue, lAddr :integer; lUniv :STRING) :boolean;

to:

function Mydialog(var lValue, lAddr :integer; var lUniv :STRING) :boolean;

 

   That's it.

 

Raymond

 

Link to comment
15 minutes ago, MullinRJ said:

Hello Sam,

   You need to make IUniv a variable parameter in your function declaration of MyDialog().

 

change:

function Mydialog(var lValue, lAddr :integer; lUniv :STRING) :boolean;

to:

function Mydialog(var lValue, lAddr :integer; var lUniv :STRING) :boolean;

 

   That's it.

 

Raymond

 

 

Holy crap.  That did it.  I would have never figured that out.  Didn't realize you had to declare VAR again for each new type.  Weird that the compiler doesn't catch that.

 

Thank you so much everyone!  I think I have the basics down and can get started making some new dialogs!

Link to comment
8 hours ago, SamIWas said:

Weird that the compiler doesn't catch that.

 

Actually, it's not an error, but a feature of the language. It's how you declare passed variables to be local or modifiable. If you don't use the "var" before a variable group, then a copy of the variables are used when the function executes and no changes made to them are returned. When you use "var" before a variable group, then any change you make to them in the routine is returned.

 

Consider the following:

procedure Example (with a, b, and c as passed parameters);

Begin

a := a + 1;

b := 3*a + 1;

c := a^2 + 2*a*b + c;

End;

 

If your procedure declaration is:  procedure Example (a, b, c :integer);

then no changes to a, b, or c are returned.

 

If your procedure declaration is:  procedure Example (var a, b, c :integer);

then any changes to a, b, and c are returned;

 

If you only want changes to c returned:  procedure Example (a, b :integer; var c :integer);

then a and b are local parameters and c will be returned. Of course you could also make "Example" a function and return c as the result.

 

But if you want to return two variables, this would be one way to do it: procedure Example (a :integer; var b, c :integer);

Now changes to b and c are returned and a remains unchanged when "Example" terminates.

 

HTH,

Raymond

Link to comment
  • 6 years later...
On 1/27/2017 at 1:39 AM, JBenghiat said:

 

I really don't use it much, but that would be the place to do things like save the dialog position.  There is also a ResizeDilogC for when the user has resized the dialog.

 

-Josh

Hey, @JBenghiat

I want to set the deafult position of a dialog but i don't know in wich part of dialog handler i need to do this?
I see a lot about the "kEventDialogPrep" but what item is this?
Hope you can help me out here 😄 

image.png.89b5f936f5c44fe8cfd41a98ef90ee16.png

 

Edited by koenr
Link to comment

Hello @koenr,

   I always save my dialog's position when I exit the event loop, either when item==kOK, or when item==kCancel. As long as you are in the dialog the user can move it, so it doesn't make sense to save the position until the dialog handler is done and things are shutting down.

 

   As to your second question, "I see a lot about the "kEventDialogPrep" but what item is this?", I have no idea. Where do you typically see this? The value kEventDialogPrep = 9 looks like a user defined dialog item. 

 

Raymond

Link to comment

Hello @MullinRJ,

I think you missunderstood me but still thanks for your opinion. I'm pretty new to the dialog boxes but i begin to get the hang of it. I tried a lot of thing yesterday evening and i found a solution to my problem.

To explain again what the problem was:
i made a plugin that zooms to objects one by one and puts those in the midle of the screen.
Than i must enter a specific value for that object in my dialogbox (wich appears in the middle of the screen aswell)
Now my dialog opens at the topleft corner of my screen so i can see the object that is selected.

In vectorscript there is such a thing as:

BEGIN
	CASE item OF
		SetupDialogC:
			BEGIN
				SetLayoutDialogPosistion(dialog, x, y);
			END;
		1: {OK}
			BEGIN
				............
  			END
		................

This constant value "SetupDialogC" doesn't work if you write your code in Python like i do.
I needed the integer that would result in this event like "1 → OK".


Solution was:

Get rid of that case and write all your preparation in the begining of the dialoghandler.
Correct me if this is a wrong way of doing things but it seems to work.

 

def DialogHandler(item, data):
  _b = vs.SetLayoutDialogPosition(dialog, 200, 150)
  
  if item == kselect:
    vint1 = 0
    # p = vs.GetPt()
    # h = vs.PickObject(p)
    # vint1 = int(vs.GetDimText(h))
    vs.SetEditInteger(dialog, kint1, vint1)
    
  if item == kOK:
    _b, rundialog.maatlijn = vs.GetEditInteger(dialog, kint1)
      
  return item

 

Link to comment

Hello @koenr,

    It would not be the first time I misread something, and I suspect it will not be the last. Sorry, I thought you wanted to SAVE the dialog's position, not SET its position. My bad! If you do both you can have the dialog open where you left it last time. That is what I typically do. To have persistent parameters, write the positions to an XML file that VW maintains using vs.SetSavedSetting(category, setting, value) and vs.GetSavedSetting(category, setting)  return (boolean, value). You create the category and the setting strings as they pertain to your script. You can save lots of things in the saved settings file and the values will persist between open files and even between VW sessions (assuming VW shuts down properly and does not crash.) It is always advised not to store critical data in the settings file as it is meant for convenience, not security.

 

   If you are interested in trapping the kSetupDialogC item, use kSetupDialogC=12255 in your constant declarations. This event# is where you want to position your dialog, and it will only happen once, so if you move the dialog it won't jump back with your next key or mouse event. There is another constant but it is little used, kSetdownDialogC=12256 and it will be generated just before the dialog closes. You could put cleanup code there, but I have never found a need to use it. Still, it's nice to know it exists.

 

   You are correct, there is no case statement equivalent in Python, so you need to use a series of if statements, as you have done, or if / elif / elif / ... / else. They are functionally the same as the Pascal case statement. You're on the right path. 

 

HTH,

Raymond

Link to comment

@koenr, You're welcome.

 

Here is a very rudimentary Python script to save dialog's position. Lightly tested. Modify it any way you like.

 

kOK = 1
kCancel = 2
kSetupDialogC = 12255
dialogName = "DUMMY DIALOG"
scriptName = "myScriptName"


def SaveDialogPos(dlogID):
	(_b, X1, Y1, X2, Y2) = vs.GetLayoutDialogPosition(dlogID)
	if _b:
		vs.SetSavedSetting(scriptName, 'PosX', vs.Concat(X1))
		vs.SetSavedSetting(scriptName, 'PosY', vs.Concat(Y1))
	pass


def SetDialogPos(dlogID):
	(_b, defaultX, defaultY, dummyX, dummyY) = vs.GetLayoutDialogPosition(dlogID)
	(_b, S) = vs.GetSavedSetting(scriptName, 'PosX')
	if _b:
		X = vs.Str2Num(S)
		(_b, S) = vs.GetSavedSetting(scriptName, 'PosY')
		if _b:
			Y = vs.Str2Num(S)
			_b = vs.SetLayoutDialogPosition(dlogID, X, Y)
		else: 
			_b = vs.SetLayoutDialogPosition(dlogID, defaultX, defaultY)
	else: 
		_b = vs.SetLayoutDialogPosition(dlogID, defaultX, defaultY)
	pass


def DialogHandler(item, data):

	if item == kSetupDialogC:
		SetDialogPos(dlogID)

	elif item == kOK:
		SaveDialogPos(dlogID)

	elif item == kCancel:
		SaveDialogPos(dlogID)
		vs.SysBeep()
	
	return item


###   MAIN   ###
dlogID = vs.CreateLayout(dialogName, False, "OK", "Cancel")
vs.CreateStaticText(dlogID, 10, 'WUMPUS', 30)
vs.SetFirstLayoutItem(dlogID, 10)

result = vs.RunLayoutDialog(dlogID, DialogHandler)

 

Raymond

  • Like 1
  • Love 1
Link to comment

In theory, all VectorScript constants are available in the vs namespace, so vs.SetupDialogC should work. 
 

4 hours ago, MullinRJ said:

There is another constant but it is little used, kSetdownDialogC=12256 and it will be generated just before the dialog closes. You could put cleanup code there, but I have never found a need to use it. Still, it's nice to know it exists.


This event runs for both the ok and cancel case, so in Raymond’s example above, you wouldn’t need to call SaveDialogPos() in two different cases. 
 

6 hours ago, koenr said:

Solution was:

Get rid of that case and write all your preparation in the begining of the dialoghandler.
Correct me if this is a wrong way of doing things but it seems to work.


Vectorworks calls the dialog handler for every user interaction with the dialog, so it can run dozens of times with each dialog session. That means that you will be constantly repositioning the dialog, and if the user drags the dialog to a new position, it will snap back to the  coded location. 

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...