Embedded toolbar or HTML dialog in viewport


#1

I’ve been recently using the FredoTools extension, which I find very useful to perform different matters. But the thing that pleased me more is the way it embeds some tools into the viewport, like for example the Angle Inspector.

I found it interesting and I’m trying to do the same in one plugin, but I can’t find the way to do it using the standard classes of the API I’ve used in the past: ToolBar, WebDialog/HtmlDialog or Tool.

Do you know how to embed a toolbar or a html dialog in the SkecthUp viewport?


#2

@Aerilius had a GUI toolkit on github for awhile, not sure if it’s still there…

it’s basically draw(view) from Class: Sketchup::Tool

not trivial…

john


#3

I would generally advise against this type of head up display if a window can be used instead. Windows can be moved away from where the user is modeling and are less noisy due to how they are framed into one single element. It is also much easier to style the content of a window too feel like a part of SketchUp, than a custom HUD that you create from scratch.


#4

Also, Fredo had to put quite a lot of effort into getting his custom toolbars to scale properly on high-dpi monitors. For a long time I couldn’t use them on my MacBook Pro Retina because the text was too tiny to see. Unless he is still sharing his library as John observed, this would be a very difficult thing to get right and to keep right.


#5

Certainly if the way to implement that is to play with Sketchup::Tool::draw(view) and OpenGL primitives I am going to think it twice before getting to it. Besides, the functionality I aim is not simple at all, so I’m not quite sure that I can achieve it with this approach.


#6

No big effort actually. It’s just that the capability to control the font size in view.draw_text appeared in SU2017.


#7

If you want the SketchUp HTML Dialog to be placed in the right corner of the View position and also eliminate the Window Dialog borders & title then the example below is for you. This will kinda make it look like its drawn in the vieport instead of being an extra window. Also, the code need some extra work but something is something.

And this only works on Windows…

require 'Win32API'

module RafaelRivera
module TestScript

	class Test

		def initialize
			@dlg = UI::HtmlDialog.new(
			{
				:dialog_title => "WEB",
				:preferences_key => "com.sample.plugin",
				:scrollable => true,
				:resizable => true,
				:width => 600,
				:height => 400,
				:left => 100,
				:top => 100,
				:min_width => 50,
				:min_height => 50,
				:max_width =>1000,
				:max_height => 1000,
				:style => UI::HtmlDialog::STYLE_DIALOG
			})
			@dlg.set_url("https://forums.sketchup.com/")

			@dlg.show()


			## Import some Windows API functions
			@getWindowRect         = Win32API.new('User32', 'GetWindowRect', 'LP', 'I')
			@findWindow            = Win32API.new('user32', 'FindWindow', ["P", "P"], "L")
			@getWindowPos          = Win32API.new("user32","GetWindowRect",["L","P"],"V")
			@setWindowPos          = Win32API.new("user32","SetWindowPos",["L","L","L","L","L","L","L"],"V")
			@getActiveWindow       = Win32API.new('User32', 'GetActiveWindow', '', 'L')
			@getWindow             = Win32API.new('User32', 'GetWindow', 'LL', 'L')
			@getClientRect         = Win32API.new('User32', 'GetClientRect', 'LP', 'I')
			@findWindowEx          = Win32API.new('User32', 'FindWindowEx', 'LLPP', 'L')
			@getWindowLong         = Win32API.new('User32', 'GetWindowLong', 'LI', 'L')
			@adjustWindowRectEx    = Win32API.new('User32', 'AdjustWindowRectEx', 'PLIL', 'I')
			@setWindowLong         = Win32API.new('user32', 'SetWindowLong', 'LLL','L')

			## This simple technique works in most cases if not all.
			active = @getActiveWindow.call()
			owner  = @getWindow.call(active, 4)
			@main_hwnd = owner == 0 ? active : owner


			@pw = @findWindow.call(0,"WEB") # Specify the title of the SketchUp HtmlDialog. I used "WEB"

			## Check Window styles in link below...
			## https://docs.microsoft.com/en-us/windows/desktop/winmsg/window-styles
			ws_visible = 0x10000000 # The window is initially visible.
			ws_border  = 0x00800000 # The window has a thin-line border.
			ws_caption = 0x00C00000 # The window has a title bar (includes the WS_BORDER style).
			ws_sizebox = 0x00040000 # The window has a sizing border. Same as the WS_THICKFRAME style.
			ws_sysmenu = 0x00080000 # The window has a window menu on its title bar. The WS_CAPTION style must also be specified.

			# # Add above varables below to change window style # # #
			# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
			# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
			
			# This eliminates windows borders and titles so you need to add
			# your own way to close HTML dialog.
			@setWindowLong.call(@pw, -16, ws_visible)
			
			# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
			# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
			

			dock_viewport_right("WEB") # Specify the title of the SketchUp HtmlDialog. I used "WEB"

			Sketchup.send_action('selectSelectionTool:')
		end

		def window_pos(window_ref)
			r = "0"*16
			if window_ref.is_a? Fixnum
				h = window_ref
			else
				h = @findWindow.call(nil,window_ref)
			end
			@getWindowPos.call(h,r)
			return r.unpack("LLLL")
		end # def

		def set_window_pos(window_ref,x,y,width=0,height=0)
			r = "0"*20
			temp = [x,y,height,width,16]
			if window_ref.is_a? Fixnum
				h = window_ref
			else
				h = @findWindow.call(nil,window_ref)
			end
			wp = window_pos(window_ref)
			if height == 0 then height = wp[3] - wp[1] end
			if width == 0 then width = wp[2] - wp[0] end
			@setWindowPos.call(h,0,x,y,width,height,16)
		end # def

		def dock_viewport_right(hwnd)
			vp_pos = window_pos(get_viewport_handle)
			docked_pos = window_pos(hwnd)
			needs_move = false
			left = vp_pos[2] - (docked_pos[2]-docked_pos[0])-3
			unless left == docked_pos[0] and vp_pos[1] == docked_pos[1]
				set_window_pos(hwnd,left,(vp_pos[1])+33,0,vp_pos[3]-vp_pos[1])     
			end
		end # def

		def get_viewport_handle
			cname = case Sketchup.version.to_i
			when 6
				'AfxFrameOrView70u'
			when 7,8
				'AfxFrameOrView80u'
			when 13,14,15,16
				'AfxFrameOrView100u'
			else
				'AfxFrameOrView140u'     
			end
			return @findWindowEx.call(@main_hwnd, 0, cname, nil)
		end # def

	end #class
end # module
end # module

Sketchup.active_model.select_tool RafaelRivera::TestScript::Test.new

#8

@RafaelRivera that’s definitely an intermediate and cool solution that allows the user to keep working with the standard web development tools and gives the appearance of an embedded menu. I’ll dig a little deeper in the Windows API and let’s see what I can do. Thanks.


#9

Hi,

Just in case you want to add more window styles on the same windows then do as follows…

Just add ‘|’ inbetween them on the call below…

## https://docs.microsoft.com/en-us/windows/desktop/winmsg/window-styles
ws_visible = 0x10000000 # The window is initially visible.
ws_border  = 0x00800000 # The window has a thin-line border.
ws_caption = 0x00C00000 # The window has a title bar (includes the WS_BORDER style).
ws_sizebox = 0x00040000 # The window has a sizing border. Same as the WS_THICKFRAME style.
ws_sysmenu = 0x00080000 # The window has a window menu on its title bar. The WS_CAPTION style must also be specified.

## Just add '|' inbetween them...
@setWindowLong.call(@pw, -16, ws_visible|ws_border|ws_sizebox) # < - - Here

Eventually we can rework the code to make it better and post it here as a template to use.


#10

Do you think if similar code can be done for osx platform (MAC)?


#11

Yes, but saddly my old macbook died an can’t test for that OS.

I am sure other developer’s here can make it happen. I DO want to learn how to do it as well.


#12

You would have to find your personal answer to the question whether you want to turn an extension that was using a cross-platform API to become cross-platform incompatible by depending on Win32API. And if there is a way to imitate this on OS X, you would have to ask yourself whether the gain is worth to maintain the code for such a workaround (and how many users with some different environment or version of Windows/OS X would contact you that it does not work for them).

The beauty of a cross-platform API is that extension developers can choose to have no dependency on the system environment or OS, and only the API provider decides which platforms it supports. If they one day added the API to another platform, your extension would work in the same instant without adaptations.

(For me personally, this is not an ideal I aspire to do.)


#13

In addition to being cross platform, only using the SketchUp API also means future (and past) OS versions are much, much more likely to be supported. You don’t want to rewrite your code in 5 years because an OS updates breaks it.