I know how difficult it is to learn how to use the SketchUp Ruby HtmlDialog Class. Especially when the examples on the API documentation are so minimal. I hope this helps some beginner like myself.
The code snippet gets some user input from a web dialog and draws a box in SketchUp. I wrote this example myself so forgive me any programming mortal sins I’ve committed in it, I’m entirely to blame.
dialog = UI::HtmlDialog.new(
{
:dialog_title => "Dialog Example",
:scrollable => true,
:resizable => true,
:width => 500,
:height => 300,
:left => 200,
:top => 200,
:min_width => 50,
:min_height => 50,
:max_width =>1000,
:max_height => 500,
:style => UI::HtmlDialog::STYLE_DIALOG
})
html = "
<!DOCTYPE html>
<html>
<head>
<title>FMS Test Dialog
</title>
</head>
<h1>Draw a Box from a HtmlDialog</h1>
<script>
function sendDataToSketchUp() {
var user_input1 = document.getElementById('id1');
var user_input2 = document.getElementById('id2');
var user_input3 = document.getElementById('id3');
sketchup.getUserInput(user_input1.value, user_input2.value, user_input3.value)
}
</script>
<body>
<p>An example using SketchUp Ruby HtmlDialog</p>
<form>
length: <input id='id1' type='number' name='length' value=50 required><br>
breadth: <input id='id2' type='number' name='breadth' value=75 required><br>
depth: <input id='id3' type='number' name='depth' value=25 required>
</form>
<button onclick='sendDataToSketchUp()'>Draw Box</button>
</body>
</html>
"
dialog.set_html(html)
dialog.show
dialog.add_action_callback("getUserInput"){|action_context, user_input1, user_input2, user_input3|
puts("JavaScript said user_input1 is #{user_input1}, user_input2 is #{user_input2} and user_input3 is #{user_input3}.")
width = user_input1.to_f
breadth = user_input2.to_f
depth = user_input3.to_f
model = Sketchup.active_model
entities = model.active_entities
pts = []
pts[0] = [0, 0, 0]
pts[1] = [width, 0, 0]
pts[2] = [width, breadth, 0]
pts[3] = [0, breadth, 0]
# Add the face to the entities in the model
face = entities.add_face(pts)
face.pushpull depth
}
Try to follow convention and prefix your thread with “[code]” or “[Example]” as others have done in the proper category. Since done, thanks.
The local reference dialog that your example uses is only persistent at the top level, which is in Object.
Coders in a shared environment need to code within their own namespaces. (Defining things in the global ObjectSpace makes them percolate into everyone else’s objects, including API objects, modules and classes.)
Your example code would usually be implemented within a method, and using a local reference would go out of scope when the method ends and the dialog would close. See topic thread:HtmlDialog closing by itself
The first 2 statements in your action callback block serve no purpose …
javaScript="var inpObj1 = document.getElementById('id1').value; var inpObj2 = document.getElementById('id2').value; var inpObj3 = document.getElementById('id3').value;"
dialog.execute_script(javaScript)
… these were executed on the JavaScript side prior to the Ruby side action callback being called.
I didn’t know there were categories, or at least I didn’t know I had control over what category the post went into. Am I supposed to do something about it or is it too late to fix?
What is a thread and how do I prefix it?
The code example is not meant to be a plugin or extension. It is just something to try to show the lonely programmer how to get UI::HtmlDialog to do something vaguely useful. It is meant to be didactic in a friendly non expert manner. I looked for ages without success for something like it. I found ThomThom’s stuff on github too difficult and extensive to follow, when I didn’t even understand the basics.
Thank you for pointing out the redundant lines in the callback. I will edit them out of the posted code.
1.a. Yes there are categories, there is a big “Categories” link at the top of the landing page.
(The “Categories” page shows you the hierarchy of the categories.)
You also see a category column for the “Latest” page.
As you drill down into categories, there will be a breadcrumb bar in the top margin allowing you to navigate upward towards the root (which is represented by the red SketchUp icon.)
1.b. Yes you have control as a thread starter what the thread’s category will be.
When first starting a topic, on the “New Topic” form, just below the topic title editbox,
is a category dropdown control.
Expand it and then type characters to filter down the list (such as API.)
1.c. Mod already recategorized it, but to the toplevel Developers category.
2.THIS is a topic thread.
As the topic thread starter you can recategorize it and retitle it anytime.
I suggest doing both as a lesson.
Go to the top of the thread …
Click the pencil icon to the right of the Topic title.
Edit the title as suggested using a “[Example]” prefix.
Below the topic title editbox, is the category dropdown control.
Expand it, and then hit keys R and U (on the keyboard) to filter the list.
Choose the “Ruby API” subcategory to change it.
Then click the Apply ( ) button.
usually there are two types of examples: the really small ones that only show one single isolated thing, like the examples in the documentation, and those that show something in context, e.g. an example extension. I would have made a full extension out of this to better show how it would be implemented in practice (e.g. including what Dan said about dialog closing). This would also allow for the code to be divided into smaller, more manageable chunks, e.g. HTML in a separate file (with proper indentation) and box drawing in a separate method, isolated from callback logic.
There are also a number of cosmetic things I’d update for the code to be easier to read. pts can be defined as an Array with 4 values from the start, rather than as an empty Array and then having values assigned to indices. I would also style the code according to GitHub - rubocop/ruby-style-guide: A community-driven Ruby coding style guide to make it easier to read with less distractions, and use RuboCop to test that it follows these style guides, and other best practices. I’d also use meaningful variable names rather than inpObj.
My code snippet is yet another type of example. Frayed around the edges as it might be, it tries to do what it does as simply as possible. I wrote it to show the complete beginner (me) the very basics of using UI::HtmlDialog for getting input from a user and then doing something very simple with it, namely modelling a box. This was something I spent a long time trying to find out how to do. I managed to get the code working much more by luck and determination than with help from anything I found online. The SketchUp documentation was no help to me. Wrapping my code snippet in extension and method code would just make it less easy to understand, not simpler. I have posted the code to be tried, changed, broken and modified as the learner wishes. If you wish please do modify it as you suggest and post it the way you would like to see it.
The code for drawing the face I cut and pasted from the SketchUp documentation. If making an array and then populating it in this way is not good then shouldn’t the documentation show it in the preferred way? Please can you also tell me why this is bad.
I took a quick look at the Ruby style guide. Good advice, no doubt, but it goes on for pages. The wicked little thought ‘life is too short’ entered my depraved mind. Anyway, I like tabs, saves me having to count to 2 all the time. I might look into it in more detail in the future. Thanks for the tip.
Using meaningful variable names is a very good idea. Thank you, I will change inpObj to input_data or something even more meaningful, as soon as I made myself a cup of tea.
There are some good examples, like ThomThom’s HtmlDialog presentation, but the problem is they are hard to find (this example is also targeted at an audience with experience from WebDialogs). I have also attempted making an example extension, this one showing how the model can be traversed with a reference to the local coordinate system. I wish there was a list of up to date, good examples cover different aspects of the API and extension development e.g. on the front page of the SketchUp developer site, in a pedagogical order almost like a tutorial. This could be clearly linked from the API docs as the API docs show individual methods without any context. A lot could be done to lower the various tresholds people have to overcome to make extensions for SketchUp.
The “problem” with defining an empty array and then assigning values to specific indices is that it is cumbersome to read and contains redundant information (the order of the rows). If you wanted to change the order you couldn’t just move the liens around, but would also have to change the index. If you did one but not the other the code would be quite confusing as there are 2 different orders (indicies and line order) that doesn’t match. There are many examples in the API that are unconventional and just odd, which is quite sad as the community picks up a lot of habits from them.
Regarding tabs vs spaces you can set any proper text editor to use either of them when pressing the Tab key. Spaces play better with web browser (e.g. when showing code here in the forum), are consistent between platforms and is the de facto standard in most open source development.
Regarding meaningful variable names I would call the variables width, height etc throughout the code. Neither input_data or inputObj really says anything about the content (unless you create a very general input interface where you don’t know what the input is).
You deserve congratulations - what you have learned and accomplished is difficult. There are so many details you must understand to make this work and you can not know them all from the beginning. Others have tried and failed, you tried and succeeded.
Yes the documentation should show the preferred way. Unfortunately it often does not and adds another level of difficulty in learning (or unlearning poor) SketchUp/Ruby idioms.
What source code editor are you using? Automatic code indentation, formatting, and color syntax highlighting are essential in an editor. If you do not yet have a preference, use Visual Studio Code.
I use Notepad++. It recognises Ruby code and highlights keywords etc. I just went with the standard tab width without thinking about changing it. I should reduce it to 2 spaces. I will look at Visual Studio Code.
Thank you for the nice comments and advice.