global $
global g_wx
global g_hMenuMain
global g_isDark
global g_showStatusBar
global g_coords
----------------------------------------
--
----------------------------------------
on startMovie
-- g_isDark = appsUseDarkTheme()
g_isDark = TRUE
g_showStatusBar = TRUE
the floatPrecision = 8
_movie.puppetTempo(30)
----------------------------------------
-- Events/callbacks triggered by a scripting xtra (like in this case WebView xtra) fail silently
-- in case of scripting errors, so without error dialogs and debug support. This can be fixed
-- by "detaching" the events from the xtra callback using provided detacher lib.
----------------------------------------
-- $.import("detacher")
----------------------------------------
-- This demo uses Lingo's value() function to parse the JSON 'args' strings received from JS,
-- since here args only contains arrays of numbers.
-- In other cases the included JSON decoder/encoder should be used instead.
----------------------------------------
-- $.import("json")
-- Some WinAPI constants we use
$["MOD_ALT"] = 1
$["MOD_CONTROL"] = 2
$["MOD_SHIFT"] = 4
$["VK_F1"] = 112
$["VK_F11"] = 122
$["MB_ICONINFORMATION"] = 64
-- Our menu command IDs - arbitrary integers, they only have to be unique
$["IDM_OPEN"] = 1001
$["IDM_EXIT"] = 1002
$["IDM_SEARCH"] = 2001
$["IDM_SHOW_STATUSBAR"] = 3001
$["IDM_DARK_MODE"] = 3002
$["IDM_FULLSCREEN"] = 3003
$["IDM_SHOW_MEESAGE_WIN"] = 3004
$["IDM_ABOUT"] = 4001
if g_isDark then
bg_color = rgb("#000000")
else
bg_color = rgb("#FFFFFF")
end if
-- window settings
_movie.stage.title = "WebView Map Demo"
_movie.stage.titlebarOptions.visible = TRUE
_movie.stage.rect = rect(0, 0, 1280, 960)
_movie.stage.bgcolor = bg_color
_movie.stage.resizable = 1
_movie.centerStage = 1
g_wx = xtra("WebView").new()
if g_isDark then
g_wx.useDarkMode(g_isDark)
end if
createMenu()
g_wx.statusBarCreate(200)
_movie.updateStage()
-- IMPORTANT: window *must* be visible when calling webviewCreate()!
_movie.stage.visible = 1
g_wx.webviewCreate(TRUE, 1, bg_color)
g_wx.webviewSetAutoSize()
g_wx.webviewJSBind("OnKeyDown")
g_wx.webviewJSBind("OnMapChanged")
g_wx.webviewNavigate("https://59de44955ebd.github.io/map/?nofullscreen")
----------------------------------------
-- Unfortunately WebView2 doesn't forward key events to the host application,
-- so we have to handle key events manually in JS to make our menu shortcuts
-- work also when the WebView has keyboard focus.
----------------------------------------
g_wx.webviewJSEval("window.addEventListener('keydown', (e) => {if(e.ctrlKey)e.preventDefault();window.OnKeyDown(e.keyCode, +e.altKey, +e.ctrlKey, +e.shiftKey)});")
end
----------------------------------------
-- This is required when running the movie in Director, i.e. in the authoring IDE
----------------------------------------
--on stopMovie
-- if not voidP(g_wx) then
-- g_wx.forget()
-- g_wx = VOID
-- end if
--end
----------------------------------------
--
----------------------------------------
on createMenu
g_hMenuMain = g_wx.createMenu()
hSubmenu = g_wx.insertSubMenu(g_hMenuMain, -1, "&File")
g_wx.insertMenuItem(hSubmenu, -1, "&Load GPX File..." & TAB & "Ctrl+O", $.IDM_OPEN, chartonum("O"), $.MOD_CONTROL)
g_wx.insertSeparator(hSubmenu, -1)
g_wx.insertMenuItem(hSubmenu, -1, "&Exit" & TAB & "Ctrl+Q", $.IDM_EXIT, chartonum("Q"), $.MOD_CONTROL)
hSubmenu = g_wx.insertSubMenu(g_hMenuMain, -1, "&Edit")
g_wx.insertMenuItem(hSubmenu, -1, "&Search..." & TAB & "Ctrl+F", $.IDM_SEARCH, chartonum("F"), $.MOD_CONTROL)
hSubmenu = g_wx.insertSubMenu(g_hMenuMain, -1, "&View")
g_wx.insertMenuItem(hSubmenu, -1, "&StatusBar" & TAB & "Alt+S", $.IDM_SHOW_STATUSBAR, chartonum("S"), $.MOD_ALT)
if g_showStatusBar then g_wx.checkMenuItem(g_hMenuMain, $.IDM_SHOW_STATUSBAR, TRUE)
g_wx.insertMenuItem(hSubmenu, -1, "&Dark Mode" & TAB & "Alt+D", $.IDM_DARK_MODE, chartonum("D"), $.MOD_ALT)
if g_isDark then g_wx.checkMenuItem(g_hMenuMain, $.IDM_DARK_MODE, TRUE)
g_wx.insertMenuItem(hSubmenu, -1, "&Fullscreen" & TAB & "F11", $.IDM_FULLSCREEN, $.VK_F11)
g_wx.insertSeparator(hSubmenu, -1)
g_wx.insertMenuItem(hSubmenu, -1, "Show &Message Window" & TAB & "Ctrl+M", $.IDM_SHOW_MEESAGE_WIN, chartonum("M"), $.MOD_CONTROL)
hSubmenu = g_wx.insertSubMenu(g_hMenuMain, -1, "&Help")
g_wx.insertMenuItem(hSubmenu, -1, "&About" & TAB & "F1", $.IDM_ABOUT, $.VK_F1)
g_wx.setMainMenu(g_hMenuMain)
end
----------------------------------------
--
----------------------------------------
on loadGPX
g_wx.webviewJSEval("document.querySelector('.leaflet-control-filelayer a').click();")
end
----------------------------------------
--
----------------------------------------
on toggleStatusBar
g_showStatusBar = not g_showStatusBar
g_wx.checkMenuItem(g_hMenuMain, 3001, g_showStatusBar)
g_wx.statusBarShow(g_showStatusBar)
end
----------------------------------------
--
----------------------------------------
on toggleDarkMode
g_isDark = not g_isDark
g_wx.checkMenuItem(g_hMenuMain, 3002, g_isDark)
g_wx.useDarkMode(g_isDark)
end
----------------------------------------
--
----------------------------------------
on toggleSearch
g_wx.webviewJSEval("document.querySelector('.search-button').click();")
end
----------------------------------------
--
----------------------------------------
on about
g_wx.ShowMessageBox("WebView Map Demo v1.0 "&RETURN&"(c) 2025 59de44955ebd", "About", $.MB_ICONINFORMATION)
-- After showing messagebox return mouse/keyboard focus to webview
g_wx.webviewSetFocus()
end
----------------------------------------
-- @callback
-- Called from browser JS in webview
----------------------------------------
on OnKeyDown (args)
-- args: "[keyCode, altKey, ctrlKey, shiftKey]", all integers, so we can use value() to convert to Lingo list
args = value(args)
-- To avoid repeating code we just forward to OnCommand()
case TRUE of
(args[1] = chartonum("O") and args[3]): OnCommand($.IDM_OPEN)
(args[1] = chartonum("Q") and args[3]): OnCommand($.IDM_EXIT)
(args[1] = chartonum("F") and args[3]): OnCommand($.IDM_SEARCH)
(args[1] = chartonum("S") and args[2]): OnCommand($.IDM_SHOW_STATUSBAR)
(args[1] = chartonum("D") and args[2]): OnCommand($.IDM_DARK_MODE)
(args[1] = $.VK_F11): OnCommand($.IDM_FULLSCREEN)
(args[1] = chartonum("M") and args[3]): OnCommand($.IDM_SHOW_MEESAGE_WIN)
(args[1] = $.VK_F1): OnCommand($.IDM_ABOUT)
end case
end
----------------------------------------
-- @callback
-- Called from browser JS in webview
----------------------------------------
on OnMapChanged (args)
-- args: "[zoom, lat, lon]", all integers or floats, so we can use value() to convert to Lingo list
g_coords = value(args)
g_wx.statusBarMsg(g_coords[1] & " / " & g_coords[2] & " / " & g_coords[3] , 1)
end
----------------------------------------
-- @callback
-- Called from WebView xtra
----------------------------------------
on OnStatusBarClicked (isRightClick, sectionNum)
if sectionNum <> 1 or voidP(g_coords) then return
if isRightClick then
hMenu = g_wx.createPopupMenu()
g_wx.insertMenuItem(hMenu, -1, "Copy to Clipboard", 1)
g_wx.insertSeparator(hMenu, -1)
g_wx.insertMenuItem(hMenu, -1, "Open in Mapswitcher", 2)
cmdID = g_wx.showPopupMenu(hMenu)
g_wx.destroyMenu(hMenu)
if cmdID = 1 then
m = new(#field)
m.text = g_coords[1] & "/" & g_coords[2] & "/" & g_coords[3]
m.copyToClipboard()
m.erase()
end if
if cmdID <> 2 then return
end if
-- Open mapswitcher with current map coords in the user's default browser
u = "https://59de44955ebd.github.io/mapswitcher/#https://www.google.com/maps/@" & g_coords[2] & "," & g_coords[3] & "," & g_coords[1] & "z"
open QUOTE & u & QUOTE, "C:\windows\explorer.exe"
end
----------------------------------------
-- @callback
-- Called from WebView xtra
----------------------------------------
on OnCommand (cmdID)
case cmdID of
($.IDM_OPEN): loadGPX()
($.IDM_EXIT): _player.quit()
($.IDM_SEARCH): toggleSearch()
($.IDM_SHOW_STATUSBAR): toggleStatusBar()
($.IDM_DARK_MODE): toggleDarkMode()
($.IDM_FULLSCREEN): g_wx.webviewToggleFullScreen()
($.IDM_SHOW_MEESAGE_WIN):
_player.debugPlaybackEnabled = 1
printMsg xtra("WebView").interface() & "\n"
($.IDM_ABOUT): about()
end case
end
----------------------------------------
-- @callback
-- Called from WebView xtra
-- Alternative using detacher to make callback showing errors and allow debugging
----------------------------------------
--on OnCommand (cmdID)
-- $.detacher.detach(#OnCommandDetached, _movie, cmdID)
--end
----------------------------------------
--
----------------------------------------
--on OnCommandDetached (cmdID)
-- ...
--end