I’m pretty new to Ruby and Sketchup, so hopefully this is just something I’m messing up.
If I make a HTTP::Request and then on success show a HTMLDialog, the content is blank when using show_modal, but show works fine. Any idea what I’m doing wrong?
show_modal pauses the execution of the code until it is closed. You can add a puts statement after show_modal and it wont be printed until the dialog is closed. I’m not sure though how this affects set_url.
First, run it with test_func. Notice that the UI.messagebox appears, but the HtmlDialog is not loaded/rendered yet. Once you close the UI.messagebox, the block and the method call complete, and the HtmlDialog shows google.
Then, run it with test_func modal: true. Since the HtmlDialog is shown modal, the UI.messagebox doesn’t appear. This also means that the block passed to Sketchup::Http::Request#start hasn’t completed, so the method hasn’t finished either.
So, what’s happening is that the HtmlDialog only processes things when the ruby code has finished. By placing a modal dialog inside a block used by a method, you’re stopping the code from finishing.
JFYI –
It’s not common for UI code (or any significant code) to be placed in an HTTP request. One gets the request.body and ‘moves on’…
I was introduced to Ruby via SketchUp about ten years ago, but I’ve been coding for decades. For new programmers, dialogs are messy, as they involve issues like the one here, but also using callbacks, etc.
I changed the style of some of your code, how you write it is your choice.
That is what I would like to do. The Http::Request is async, so I can’t figure out how to get the token without yielding the result to function that opens the dialog. Again, I’ve been only working in Ruby a few days, so excuse my inexperience with parts of the language.
What I’m doing is making a request for an access token, once I have the token then I want to pop up the dialog. I would like to do something like the following, but we return from the function before access_token has a value.
def self.get_token
...
access_token = nil
request.start do |request, response|
resultJson = {}
if response.status_code == 200 && !response.body.nil?
resultJson = JSON.parse(response.body)
File.write(tokenFile, resultJson['access_token'])
end
access_token = resultJson['access_token']
end
return access_token
end
That being understood, and having looked around quite a bit, I still cannot use ‘show_modal’ to my liking; the dialog is always blank.
Does the quote mean that a suite of methods cannot momentarily be interrupted with ‘_modal’, for an input request for instance ?
Any Ruby manipulation of the dialog object must come before the #show_modal method call.
Providing a snippet would help us know what you are trying to do.
That said, once the dialog is shown, the user can only work with that dialog whilst it is open. They cannot use any other application feature outside the dialog (at least on Windows.) [Note that they can switch to another application, but switching back to SketchUp will give the modal dialog the focus again. MacOS may be a bit different as to what Apple considers modality.]
Well, after playing a lot with modal HtmlDialog my conclusion is : it is way too complicated on Mac, as of now only a few people (at TT’s level) can use it, I think.
Since the purpose of ‘modal’ is to suspend the rb method till the dialog is closed,
I think a simple work around could be:
Split the method in 2 methods
At the end of the first, call the (non-modal) html dialog (no ruby after, so rb is stopped)
to carry on with rb,
put a call to the second method in an ‘action_callback’.
In method-1
...
...
dialog.add_action_callback('onclick') do |action_context, var|
@var = var
dialog.close
method-2
end #do
...
HtmlDialog and the Http API is driven by Chromium, which work in async separate processes. This is a challenge some times. I’ve found that starting new async within another async callbacks can be problematic.
You can often work around this by using UI.start_timer to defer the execution to be outside the context of the async callback. But that itself has issues if the timer pops up a modal dialog.
This pattern should allow you to pop up a modal in response to an HTTP request:
module Example
def self.test_func
request = Sketchup::Http::Request.new('http://sketchup.com', Sketchup::Http::GET)
request.start do |request, response|
puts response.status_code
self.delay(0.0) do
self.open_dialog
end
end
end
def self.open_dialog
options = {
:dialog_title => 'Test',
:width => 500,
:height => 400,
:style => UI::HtmlDialog::STYLE_DIALOG
}
dialog = UI::HtmlDialog.new(options)
dialog.set_url('http://google.com')
dialog.center
dialog.show_modal
end
def self.delay(seconds, &block)
# Needed to avoid the timer from repeating if the block opens a modal
# dialog or anything else that suspend execution.
done = false
UI.start_timer(seconds, false) do
next if done
done = true
block.call
end
end
end # module