{"id":10707,"date":"2020-07-07T13:45:25","date_gmt":"2020-07-07T13:45:25","guid":{"rendered":"https:\/\/fhug.org.uk\/kb\/?post_type=kb_article&#038;p=10707"},"modified":"2020-12-11T14:08:37","modified_gmt":"2020-12-11T14:08:37","slug":"iup-gui-builder-hints-and-tips","status":"publish","type":"kb_article","link":"https:\/\/www.fhug.org.uk\/kb\/kb-article\/iup-gui-builder-hints-and-tips\/","title":{"rendered":"IUP GUI Builder Hints and Tips"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>IUP is a very powerful tool for building graphical user interfaces (GUI), but it&#8217;s fairly unforgiving and the <a href=\"http:\/\/www.tecgraf.puc-rio.br\/iup\/\">IUP Documentation<\/a> is a little sparse especially when used with Lua. This page contains handy tips for the various options of dialogue building.<\/p>\n<p>When you are working on developing dialogues, always save before running, as if you get it wrong the dialogue will not appear and you will need to kill <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>, using task manager to reset it.<\/p>\n<p>Dialogues are built using a fairly simple nested table containing the controls. A control can be any of a selection of items, including labels, input boxes, buttons and many others.<\/p>\n<h2>Import Family Historian 7 note<\/h2>\n<p>For Plugins that use Lua to work correctly, you must include the following in your code before any IUP functionality is called:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">require(\"iuplua\");\r\niup.SetGlobal(\"CUSTOMQUITMESSAGE\",\"YES\");<\/pre>\n<h2>Building Blocks<\/h2>\n<p>When building a dialogue, it&#8217;s best to sketch what you want on a sheet of paper, or a wireframe tool like\u00a0<a href=\"http:\/\/framebox.org\/\">framebox.org<\/a>\u00a0or\u00a0<a href=\"http:\/\/balsamiq.com\/\">balsamiq.com<\/a>, that way you can see the components you need to add.<\/p>\n<p>Here is an example dialogue, that was drawn in framebox:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-10719 size-full lazyload\" data-src=\"https:\/\/fhug.org.uk\/kb\/wp-content\/uploads\/2020\/07\/2013-10-03_082502.png\" alt=\"\" width=\"505\" height=\"368\" data-srcset=\"https:\/\/www.fhug.org.uk\/kb\/wp-content\/uploads\/2020\/07\/2013-10-03_082502.png 505w, https:\/\/www.fhug.org.uk\/kb\/wp-content\/uploads\/2020\/07\/2013-10-03_082502-300x219.png 300w, https:\/\/www.fhug.org.uk\/kb\/wp-content\/uploads\/2020\/07\/2013-10-03_082502-150x109.png 150w\" data-sizes=\"(max-width: 505px) 100vw, 505px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 505px; --smush-placeholder-aspect-ratio: 505\/368;\" \/><\/p>\n<p>There are 9 visual controls on the dialogue, consisting of three labels, two single line text boxes, a multiline text box and three buttons.<\/p>\n<p>For each control you need to get information from, or interact with, you need to give them a name, but for other items you simply need to use the constructor.<\/p>\n<p>In your plugin you need to define the inner most items first; a bit like building a set of Russian dolls, you need to put the smallest ones together first.<\/p>\n<h2>Creating Components Part 1<\/h2>\n<p>So lets define the 3 buttons:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">local btn_ok = iup.button{name=\"ok\", title=\"OK\",\r\n    action = function(self)\r\n        res=self.name\r\n        return iup.CLOSE\r\n    end}\r\nlocal btn_cancel = iup.button{name=\"cancel\", title=\"Cancel\",\r\n    action = function(self) res=self.name return iup.CLOSE\r\n    end}\r\nlocal btn_help = iup.button {name=\"help\", title=\"Help\",\r\n    action = function (self) iup.Message('Help','Help Goes Here')\r\n    end}<\/pre>\n<p>For each button we have defined the text for the button and the action to take when the button is pressed. Note that both the OK and Cancel button return\u00a0<code>iup.CLOSE<\/code>\u00a0which will cause the dialog to close when the button is pressed, where as the Help button simply shows a message.<\/p>\n<p>If you prefer the actions for buttons can be defined separately using the following syntax:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">function btn_ok:action()\r\n\u00a0 \u00a0 res=self.name\r\n\u00a0 \u00a0 return iup.CLOSE\r\nend<\/pre>\n<p>Note the : in the function name, this means the first parameter for the function is the button itself and it can be accessed using\u00a0<code>self<\/code>.<\/p>\n<p>When using the <code>iup.dialog<\/code> to build a dialog you will need to use the\u00a0<code>iup.vbox<\/code>\u00a0and\u00a0<code>iup.hbox<\/code>\u00a0to arrange the controls on the dialog. In our example, we need to add a\u00a0<code>vbox\u00a0<\/code>and three\u00a0<code>hbox\u00a0<\/code>controls to control the layout, as shown below:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-10720 size-full lazyload\" data-src=\"https:\/\/fhug.org.uk\/kb\/wp-content\/uploads\/2020\/07\/framebox2.png\" alt=\"\" width=\"512\" height=\"357\" data-srcset=\"https:\/\/www.fhug.org.uk\/kb\/wp-content\/uploads\/2020\/07\/framebox2.png 512w, https:\/\/www.fhug.org.uk\/kb\/wp-content\/uploads\/2020\/07\/framebox2-300x209.png 300w, https:\/\/www.fhug.org.uk\/kb\/wp-content\/uploads\/2020\/07\/framebox2-150x105.png 150w\" data-sizes=\"(max-width: 512px) 100vw, 512px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 512px; --smush-placeholder-aspect-ratio: 512\/357;\" \/><\/p>\n<p>Now we have 3 buttons we can add a little more code so we can display the dialog:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">local res\r\nlocal btn_ok = iup.button{name=\"ok\", title=\"OK\"}\r\n \r\nfunction btn_ok:action()\r\n    res=self.name\r\n    return iup.CLOSE\r\nend\r\nlocal btn_cancel = iup.button{name=\"cancel\", title=\"Cancel\", action = function (self) res=self.name return iup.CLOSE end}\r\nlocal btn_help = iup.button {name=\"help\", title=\"Help\", action = function (self) iup.Message('Help','Help Goes Here') end}\r\ndlg = iup.dialog{iup.hbox{btn_ok,btn_cancel,btn_help};\r\n                          title=\"Sample\",size=\"320x240\",padding='10px',gap='5px', \r\n                          close_cb=function() res='closed' return iup.CLOSE end}\r\ndlg:show()      -- Show the dialog\r\niup.MainLoop()  -- Process the dialog\r\nprint(res)      -- Print the pressed button<\/pre>\n<p>In the code above the\u00a0<code>iup.dialog<\/code>\u00a0takes a table of tables and values which control the layout. The three buttons we created earlier are wrapped in\u00a0<code>iup.hbox<\/code>\u00a0which means that they will be shown horizontally across the layout. If you were to simply include the three buttons without the\u00a0<code>hbox\u00a0<\/code>they would all appear vertically one above the another.<\/p>\n<p>Note the semi-colon between the fields for the dialog and the values. This is common practice to show where the controls end and the values start, but could equally be a comma. Another readability trick is the use of\u00a0<code>{}<\/code>\u00a0on their own to pass a table to a function\u00a0<code>iup.button{}<\/code>\u00a0is the same as\u00a0<code>iup.button({})<\/code><\/p>\n<p>The\u00a0<code>close_cb<\/code>\u00a0function is called when the window close button is pressed. It&#8217;s good practice to use the return\u00a0<code>iup.CLOSE<\/code>\u00a0when this is pressed and set some sort of return code, especially when more than one dialog is in use as not doing so can have unexpected results.<\/p>\n<p>If you run the code above in the editor, the dialog will display and you can press any of the buttons to see the results.<\/p>\n<h2>Adding the Text Boxes<\/h2>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">-------------------------------------------------------- Define Text Fields\r\nlocal inp_title = iup.text{name='title',expand='HORIZONTAL' }\r\nlocal inp_tags  = iup.text{name='tags',  expand='HORIZONTAL' }\r\nlocal inp_memo  = iup.text{name='memo',  expand='HORIZONTAL', multiline = 'YES',visiblelines = 10}<\/pre>\n<p>This code defines three input boxes, to keep it simple the expand option is used to tell the boxes to fill any available width on the dialog.<\/p>\n<p>The memo field has its\u00a0<code>multiline\u00a0<\/code>option set to\u00a0<code>YES\u00a0<\/code>and the number of lines set to\u00a0<code>10<\/code>.<\/p>\n<p>The\u00a0IUP\u00a0documentation always uses capital letters for attribute keywords e.g\u00a0<code>MULTILINE<\/code> and their values e.g.\u00a0<code>YES<\/code>, but in Lua you may use lowercase e.g.\u00a0<code>multiline<\/code> and\u00a0<code>yes<\/code> or mixed case e.g.\u00a0<code>Multiline<\/code>\u00a0and\u00a0<code>Yes<\/code>. But when these values are interrogated they will always be returned in UPPERCASE.<\/p>\n<p>Call back functions such as\u00a0<code>action<\/code>\u00a0and\u00a0<code>close_cb<\/code>\u00a0must always be in lowercase.<\/p>\n<p>The names following\u00a0<code>iup<\/code>.\u00a0must use the correct letter case:<\/p>\n<ul>\n<li>Tables such as\u00a0<code>iup.button { }<\/code>\u00a0and\u00a0<code>iup.hbox { }<\/code>\u00a0with curly brackets must be in lowercase.<\/li>\n<li>Constants such as <code>iup.CLOSE<\/code> and <code>iup.CENTER<\/code> without any brackets must be in UPPERCASE.<\/li>\n<li>Functions such as <code>iup.Message( )<\/code> and <code>iup.MainLoop( )<\/code> with parentheses must be in MixedCase.<\/li>\n<\/ul>\n<p>When defining the controls, the sequence they are added effects which controls can see others. So the text controls are best placed before the buttons in the source, so that they can be accessed when we come to add some validation to the form.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">dlg = iup.dialog{ \r\n            iup.vbox{ \r\n                     iup.hbox{iup.label{title='Title',size='20'},inp_title},\r\n                     iup.hbox{iup.label{title='Tags',size='20'}, inp_tags},\r\n                     iup.label{title='Memo'},inp_memo,\r\n                     iup.hbox{btn_ok,btn_cancel,btn_help;padding='10',gap='5'}\r\n                     ;padding='5',gap='5',nmargin='20x20'\r\n                     },\r\n             title='Sample',padding='10',gap='5', size='320',\r\n             close_cb=function() res='closed' return iup.CLOSE end}<\/pre>\n<p>Next update the dialog to include the new fields. As mentioned earlier we have added\u00a0vbox\u00a0and additional\u00a0hbox\u00a0controls to put the labels and the\u00a0iup.label\u00a0which is a simple control is added directly to provide titles for the text boxes.<\/p>\n<h2>Adding Some Validation<\/h2>\n<p>When prompting the user for input, it&#8217;s very useful to check all the values before closing the form. This can be done on pressing the OK button using the\u00a0<code>action<\/code>\u00a0function.<\/p>\n<p>To highlight the field we will turn the background of the field in error to red and put out a red message on the dialogue. When using colours on a dialog it can be helpful to define the colours as variables or a table to they can be reused easily.<\/p>\n<p>For our validation we need to colours a &#8216;red&#8217; and a pink for the background. At the start of the code add<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">local color = {error = '255 200 200',red = '255 0 0'}<\/pre>\n<p>The\u00a0<code>color<\/code>\u00a0table can easily have additional colours added for other uses.<\/p>\n<p>Next we need to add a\u00a0<code>iup.label<\/code>\u00a0to the form and this time it needs a name as we need to change the value after the form is displayed. Add the following after the definitions of the input controls.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">local lab_message = iup.label{title=' ',fgcolor=color.red, expand='HORIZONTAL'}<\/pre>\n<p>Add the lab_message into the\u00a0<code>dialog<\/code>\u00a0table, before the buttons.<\/p>\n<p>Next we can add some logic to the\u00a0<code>btn_ok:action<\/code>\u00a0to check that the title field is not blank and show a message if it is.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">function btn_ok:action()\r\n    res=self.name\r\n    if inp_title.value =='' then\r\n       inp_title.bgcolor = color.error\r\n       lab_message.title = 'Please Enter Title'\r\n    else\r\n    return iup.CLOSE\r\n    end\r\nend<\/pre>\n<p>If you now run the code and don&#8217;t enter a value for the title the field will go red and an error come up. However if you then enter the title it will stay red. To avoid this we can add a function on the title field so that when it is changed the error status is reset<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">-------------------------------------------------------- Reset Error Markers\r\nfunction inp_title:action() self.bgcolor = DLGBGCOLOR lab_message.title = '' end<\/pre>\n<p>This needs too be added after both\u00a0<code>inp_title<\/code>\u00a0and\u00a0<code>lab_message<\/code>\u00a0are defined.<\/p>\n<h2>Using the Values<\/h2>\n<p>Once your user has pressed OK, all the values you require are stored against the controls. So you can access the title using\u00a0<code>inp_title.value<\/code>, these values are available until you issue a\u00a0<code>destroy<\/code>\u00a0against the dialogue. If you are calling a dialog in a function and wanting the return the values you will therefore need to copy the values to temporary variables before calling the\u00a0<code>destroy<\/code>\u00a0function.<\/p>\n<h2>The Finished Example<\/h2>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">local res,sTitle,sTags, sMemo\r\nlocal color = {error = '255 200 200',red = '255 0 0'}\r\n-------------------------------------------------------- Define Text Fields\r\nlocal inp_title = iup.text{name='title',expand='HORIZONTAL' }\r\nlocal inp_tags  = iup.text{name='tags',  expand='HORIZONTAL' }\r\nlocal inp_memo  = iup.text{name='memo',  expand='HORIZONTAL', multiline = 'YES',visiblelines = 10}\r\ninp_tags.value = 'sample,tag,values'\r\nlocal lab_message = iup.label{title=' ',fgcolor=color.red, expand='HORIZONTAL'}\r\n-------------------------------------------------------- Reset Error Markers\r\nfunction inp_title:action() self.bgcolor = DLGBGCOLOR lab_message.title = '' end\r\n-------------------------------------------------------- Define Buttons\r\nlocal btn_ok = iup.button{name='ok', title='OK'}\r\nfunction btn_ok:action()\r\n    res=self.name\r\n    if inp_title.value =='' then\r\n       inp_title.bgcolor = color.error\r\n       lab_message.title = 'Please Enter Title'\r\n    else\r\n    return iup.CLOSE\r\n    end\r\nend\r\nlocal btn_cancel = iup.button{name='cancel', title='Cancel', action = function (self) res=self.name return iup.CLOSE end}\r\nlocal btn_help = iup.button {name='help', title='Help', action = function (self) iup.Message('Help','Help Goes Here') end}\r\n-------------------------------------------------------- Define Dialog\r\ndlg = iup.dialog{ \r\n            iup.vbox{ \r\n                     iup.hbox{iup.label{title='Title',size='20'},inp_title},\r\n                     iup.hbox{iup.label{title='Tags',size='20'}, inp_tags},\r\n                     iup.label{title='Memo'},inp_memo,lab_message,\r\n                     iup.hbox{btn_ok,btn_cancel,btn_help;padding='10',gap='5'}\r\n                     ;padding='5',gap='5',nmargin='20x20'\r\n                     },\r\n             title='Sample',padding='10',gap='5', size='320',\r\n             close_cb=function() res='closed' return iup.CLOSE end}\r\n-------------------------------------------------------- Show Dialog\r\ndlg:show()      -- Show the dialog\r\niup.MainLoop()  -- Process the dialog\r\nprint(res)      -- Print the pressed button\r\nif res == 'ok' then\r\n  sTitle = inp_title.value\r\n  sTags  = inp_tags.value\r\n  sMemo  = inp_memo.value\r\nend\r\ndlg:destroy()   -- Clean up the dialog, note all dialog controls are destroyed as well\r\nprint(sTitle,sTags,sMemo)<\/pre>\n<h2>Centre a Set of Buttons or other items in the Window<\/h2>\n<p>To do horizontal centring you need to use the <code>iup.fill<\/code> object. Placing one on each side of the code you want centred.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">require( \"iuplua\" )\r\n\u00a0\r\nb1 = iup.button {title='button 1'}\r\nb2 = iup.button {title='button 2'}\r\n\u00a0\r\ndlg = iup.dialog {\r\niup.hbox { iup.fill {},b1,b2,iup.fill {}}\r\n;\r\nmargin=20,padding=10, size='400x100', title = \"Centered Buttons\"\r\n}\r\ndlg:show()\r\niup.MainLoop()<\/pre>\n<p>N.B Do not use <code>EXPANDCHILDREN='YES'<\/code> on the container for the <code>hbox<\/code> or the centring will not work.<\/p>\n<h2>More Examples<\/h2>\n<p>There are lots of examples of building dialogues on <a href=\"http:\/\/www.tecgraf.puc-rio.br\/iup\/en\/basic\/\">A Basic Guide to using IupLua<\/a><\/p>\n","protected":false},"template":"","fh_version":[14,15,739],"skill_level":[18,17],"topic":[73],"class_list":["post-10707","kb_article","type-kb_article","status-publish","hentry","fh_version-v5","fh_version-v6","fh_version-v7","skill_level-advanced","skill_level-intermediate","topic-writing-plugins"],"_links":{"self":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/kb_article\/10707","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/kb_article"}],"about":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/types\/kb_article"}],"wp:attachment":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/media?parent=10707"}],"wp:term":[{"taxonomy":"fh_version","embeddable":true,"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/fh_version?post=10707"},{"taxonomy":"skill_level","embeddable":true,"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/skill_level?post=10707"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/topic?post=10707"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}