* iup Buttons example

For users to report plugin bugs and request plugin enhancements; and for authors to test new/new versions of plugins, and to discuss plugin development (in the Programming Technicalities sub-forum). If you want advice on choosing or using a plugin, please ask in General Usage or an appropriate sub-forum.
Post Reply
User avatar
Mark1834
Megastar
Posts: 2458
Joined: 27 Oct 2017 19:33
Family Historian: V7
Location: South Cheshire, UK

iup Buttons example

Post by Mark1834 »

I'm a great fan of not over-complicating things, so use the simpler iup functions if that is all I need, rather than construct a full interface from first principles. Sooner or later, I will outgrow them, so I had a go at replicating my fact changing plugin menu. Basic layout is not that complicated (but very tedious... :(), and reasonably easy to follow from the documentation and KB examples. I'm happy with this result - it is neat and uncluttered, and has an extra button if I need it later.
Capture.PNG
Capture.PNG (7.19 KiB) Viewed 4001 times
The bit I struggled with was getting the buttons to do something useful. The documentation examples are clear, but too simple and stop frustratingly short of calling useful functions. I found the KB examples less easy to follow than the description of layouts, as there is a lot of other detail in the scripts, including potentially new features such as using self in function calls. As a result, I found it difficult to pull out the key parts that I needed.

I think the KB would benefit from a simple introductory example that concentrated on button actions. I put this example together to illustrate. Three simple buttons, with two clickable actions and a close button. The close button demonstrates an action that closes the window and ends the plugin, while the other two can be called repeatedly in a loop.

Code: Select all

require('iuplua');
iup.SetGlobal('CUSTOMQUITMESSAGE','YES');

function main()
	-- define three buttons with a minimum of formatting

	btn1 = iup.button{title='1',size='40x'}
	btn2 = iup.button{title='2',size='40x'}
	btnCancel = iup.button{title='Cancel',size='40x'}

	-- define what the buttons do when clicked

	function btn1:action()
		dlg:hide()
		btn1_Click()
		dlg:show()
	end

	function btn2:action()
		dlg:hide()
		btn2_Click()
		dlg:show()
	end

	function btnCancel:action()
		return iup.CLOSE
	end

	-- define the form layout

	buttons = iup.hbox{btn1, btn2, btnCancel}

	dlg = iup.dialog{buttons}

	dlg:show()
	iup.MainLoop()
end

function btn1_Click()
	fhMessageBox('1 clicked!')
end

function btn2_Click()
	fhMessageBox('2 clicked!')
end

main()
My question to those more skilled in this art is whether I have over-simplified to the point of it being incorrect or misleading? I found it easier to follow, perhaps as it is analogous to VBA menus, or even the excellent Borland hobbyist products of 20 years ago.

Curiously, if I don't hide the menu while the simple fhMessageBox() illustrations are waiting for an answer, it stays active, so I can have two modal dialogue boxes open at the same time! I don't know if that is just a curious quirk or a warning of something sinister in the code.
Mark Draper
User avatar
tatewise
Megastar
Posts: 28341
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: iup Buttons example

Post by tatewise »

Yes, that is a neat example.
Instead of using dlg:hide() and dlg:show() use dlg.active="NO" and dlg.active="YES" which keeps the dialogue displayed but inhibits its use. Then only one button can be used at the same time.

The thing to remember is that IUP is its own multitasking OS. So multiple button actions can be running in parallel.
That is no accident and is by design.
Try this variant that lets both buttons be used but inhibits a button while in use although the button actions are nested:

Code: Select all

	function btn1:action()
		btn1.active="NO"
		btn1_Click()
		btn1.active="YES"
	end

	function btn2:action()
		btn2.active="NO"
		btn2_Click()
		btn2.active="NO"
	end
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
ColeValleyGirl
Megastar
Posts: 5465
Joined: 28 Dec 2005 22:02
Family Historian: V7
Location: Cirencester, Gloucestershire
Contact:

Re: iup Buttons example

Post by ColeValleyGirl »

Not certain it's related but the FH API documentation says about fhMessage:
hParentWnd Requires version 7 or later. Optional parent window handle('light userdata'). If you are calling the function from a dialog box, such as an IUP dialog box, you must pass in the window handle of the dialog box - see second example below.
Try following the second example in the help file and see if that stops two windows being active at once.

Re simplicity, it seems simple enough (except for the hopefully redundant hide/show pairs) -- but then so does the example at https://webserver2.tecgraf.puc-rio.br/i ... rial2.html and I'm not convinced we ought to be writing our own tutorials for the kb when there are some good ones online already.
User avatar
ColeValleyGirl
Megastar
Posts: 5465
Joined: 28 Dec 2005 22:02
Family Historian: V7
Location: Cirencester, Gloucestershire
Contact:

Re: iup Buttons example

Post by ColeValleyGirl »

You could also popup a modal iup message dialog rather than use fh message if you don't want two dialogues open at onv. Easier for users to understand
User avatar
Mark1834
Megastar
Posts: 2458
Joined: 27 Oct 2017 19:33
Family Historian: V7
Location: South Cheshire, UK

Re: iup Buttons example

Post by Mark1834 »

Interesting - adding the extra parameter in FH7 does make the Message Box fully modal again, so it looks like CP have deliberately enhanced the fhMessageBox() function to suppress that odd behaviour.

That’s really only a peripheral point, though. The Message Box is just there as a prompt, it could just as easily be a simple print() statement.

I was offering feedback as a student that some of what is currently on the KB might not be ideal for teaching (purely IMO of course), but if you’re happy with it, that’s fine. My script can just stay here on the forum for people to find if they are searching.
Mark Draper
User avatar
tatewise
Megastar
Posts: 28341
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: iup Buttons example

Post by tatewise »

Yes, the use of fhMessageBox() is simply to give the buttons something to do in the demo.
In actual cases, the buttons would perform something completely different.

There are also lots of sample scripts at https://www.tecgraf.puc-rio.br/iup/examples/Lua/
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
ColeValleyGirl
Megastar
Posts: 5465
Joined: 28 Dec 2005 22:02
Family Historian: V7
Location: Cirencester, Gloucestershire
Contact:

Re: iup Buttons example

Post by ColeValleyGirl »

Mark1834 wrote: 29 Jul 2021 20:13 I was offering feedback as a student that some of what is currently on the KB might not be ideal for teaching (purely IMO of course), but if you’re happy with it, that’s fine. My script can just stay here on the forum for people to find if they are searching.
I'm not happy with it, Mark, but I'm just not convinced the KB needs to duplicate the advice in the IUP guidance. If it does, then it should be folded into the Writing Plugins for Beginners article that Shosh was planning -- which I still hope to see when she has time/head space.

Or are you planning a complete rewrite of the article on IUP? A redo from the viewpoint of a real beginner could make sense, and complement anything Shosh is planning.
User avatar
Mark1834
Megastar
Posts: 2458
Joined: 27 Oct 2017 19:33
Family Historian: V7
Location: South Cheshire, UK

Re: iup Buttons example

Post by Mark1834 »

No, a substantial rewrite wouldn’t be a priority for me. I’ve already offered to contribute to the “Plugins for Beginners” if that ever happens, so let’s not start a parallel work stream.
Mark Draper
User avatar
ColeValleyGirl
Megastar
Posts: 5465
Joined: 28 Dec 2005 22:02
Family Historian: V7
Location: Cirencester, Gloucestershire
Contact:

Re: iup Buttons example

Post by ColeValleyGirl »

Mark, I agree about parallel workstreams -- far better to fit it into "Plugins for Beginners".
User avatar
Mark1834
Megastar
Posts: 2458
Joined: 27 Oct 2017 19:33
Family Historian: V7
Location: South Cheshire, UK

Re: iup Buttons example

Post by Mark1834 »

One question please - the IUP documentation seems to switch between two syntax styles without explanation. Consider this simple prototype consisting of two buttons, one in each style.

Code: Select all

require('iuplua')
iup.SetGlobal('CUSTOMQUITMESSAGE','YES')

function printstuff(n)
	print('Button ' .. n  .. ' clicked')
end

-- define the callback, then the control

function btn_exit_cb(self)
	printstuff(1)
	return iup.CLOSE
end

b1 = iup.button{title = '1', size=40, action = btn_exit_cb}

-- define the control first, then its action

b2 = iup.button{title = '2', size=40}

function b2:action()
	printstuff(2)
	return iup.CLOSE
end

hbox = iup.hbox{b1, b2}
dlg = iup.dialog{hbox}
dlg:show()
iup.MainLoop()
Are the two formats equivalent, or is there a reason to choose one over the other in particular circumstances? I see an analogy here between these two styles and using the string library, such as S1 = string.find(S2, foo) versus S1 = S2:find(foo). In both cases, the colon acts to pass the first function argument automatically, so no need to use self for button 2. Am I on the right lines?
Mark Draper
User avatar
ColeValleyGirl
Megastar
Posts: 5465
Joined: 28 Dec 2005 22:02
Family Historian: V7
Location: Cirencester, Gloucestershire
Contact:

Re: iup Buttons example

Post by ColeValleyGirl »

As far as I know, Mark, it's just a stylistic difference. There's a third option as well:

Code: Select all

b3 = iup.button{title='3',size=40,action = function(self) printstuff(3) return iup.CLOSE end}
I tend to use this style for buttons, because it keeps everything about the button in a single declaration, but it's personal choice. I might use one of the other styles if for example the callback function was declared as part of some boilerplate code elsewhere in the plugin.

P.S. The x:y structure is 'syntactic sugar':
Syntactic sugar is a computer science term that refers to syntax within a programming language that is designed to make things easier to read or to express, while alternative ways of expressing them exist.
User avatar
tatewise
Megastar
Posts: 28341
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: iup Buttons example

Post by tatewise »

Yes, the two formats are equivalent.
Yes, you are on the right lines regarding the colon.

It is effectively the difference between a 'function' and a 'method'.
A 'function' without the colon needs an initial parameter to define the value to operate with.
A 'method' with the colon is applied to the value in front of the colon.
There are similar examples in the FH API, i.e. the Function Index versus the Objects that have methods.
e.g. strTag = fhGetTag(ptr) versus ptr:MoveNext()

There is a variant of IUP method 1:
b1 = iup.button{title = '1', size=40, action = function (self) printstuff(1) return iup.CLOSE end}

The only consequence of the two IUP methods is where you can define local items.
If you want printstuff(n) to be a 'local function' it must appear before the button action functions.
You may also want the IUP controls to be local items.
So if any function needs to involve other IUP controls then it must appear after those controls.
i.e. Such functions must be between the controls and the action functions so they are all in scope.

I might not have explained that too well, but if you start defining items as local you will see what I mean.
[posted at same time as Helen]
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
Mark1834
Megastar
Posts: 2458
Joined: 27 Oct 2017 19:33
Family Historian: V7
Location: South Cheshire, UK

Re: iup Buttons example

Post by Mark1834 »

Excellent, thank you both. I've identified 3 key learnings over the past 24 hours that make using IUP a lot clearer to me:
  1. There are multiple syntax styles, so always be aware that one example may look different to another. I think I'm leaning towards the greater simplicity and clarity of the function button:action() style, but I'll use all of them to increase my familiarity.
  2. Controls themselves are actually tables, so all the complex {parameter=value} stuff is basically just assigning values to table elements. Control.parameter = value is an alternative, and foo = control.value is again just standard table syntax.
  3. iup.MainLoop() is there to pause the script while the user interacts with the iup form, and calling iup.Close resumes execution at the step following iup.MainLoop().
Mark Draper
User avatar
tatewise
Megastar
Posts: 28341
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: iup Buttons example

Post by tatewise »

Yes, you are correct.
Here is an example that only works with your preferred function button:action() style.
Assume you want to encapsulate the IUP GUI stuff within a function GUI() so that all controls are local.
Some control callback actions need to modify other controls, e.g. b1 & b2 need to disable the dialog as discussed before.
That is only possible with your preferred style.
e.g. This cannot use the first style of callback unless everything is global:

Code: Select all

require('iuplua')
iup.SetGlobal('CUSTOMQUITMESSAGE','YES')

function GUI()
	local b1 = iup.button{ title = '1'; size=40; }
	local b2 = iup.button{ title = '2'; size=40; }
	local hbox = iup.hbox{ b1; b2; }
	local dlg = iup.dialog{ hbox; }

	local function printstuff(b)	-- Uses either button
		print(b.title)
	end

	function b1:action() -- b1 disables dialogue
		dlg.active="NO"
		printstuff(b1)
		fhSleep(5000)
		dlg.active="YES"
	end

	function b2:action() -- b2 disbales dialogue
		dlg.active="NO"
		printstuff(b2)
		fhSleep(5000)
		dlg.active="YES"
	end

	dlg:show()
	iup.MainLoop()
end

GUI()
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
User avatar
Mark1834
Megastar
Posts: 2458
Joined: 27 Oct 2017 19:33
Family Historian: V7
Location: South Cheshire, UK

Re: iup Buttons example

Post by Mark1834 »

Interesting possibilities there - for example, disabling an OK button until a valid selection is made from a list or data entered into the form. I'll make sure I understand the basics properly before getting too carried away though!
Mark Draper
User avatar
ColeValleyGirl
Megastar
Posts: 5465
Joined: 28 Dec 2005 22:02
Family Historian: V7
Location: Cirencester, Gloucestershire
Contact:

Re: iup Buttons example

Post by ColeValleyGirl »

Mark1834 wrote: 31 Jul 2021 11:28 disabling an OK button until a valid selection is made from a list or data entered into the form.
That's a technique I (and I suspect Mike) deploy quite regularly -- and it can equally be applied to other controls such as lists or text fields -- only enable address after place has been specified. I use it so often, I have a boilerplate routine for enabling or disabling a list of controls (passed in as a table).
User avatar
tatewise
Megastar
Posts: 28341
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: iup Buttons example

Post by tatewise »

Yes, many of my plugins with a GUI have a function that analyses the values of various controls and decides which controls should be active and which not.
e.g.
See 'Change Any Fact Tag' where the Delete and Change buttons only become active when Tag Names are chosen.
See 'Map Life Facts' where the buttons on the 'Geocode Location Plots' tab only become active when the fields on the left contain appropriate data.

Each button callback invokes a single function that checks control values and uses the Active attribute to enable or disable the necessary buttons.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry
Post Reply