From 5d9e7e209a4ba24a2aedc67635e08920ed887f78 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 13 Apr 2025 14:33:24 +1000 Subject: [PATCH] map: added dropdown selection of frame to FlyTo and remember previous frame and value --- MAVProxy/modules/lib/mp_menu.py | 84 ++++++++++++++++++++++- MAVProxy/modules/mavproxy_map/__init__.py | 6 +- MAVProxy/modules/mavproxy_mode.py | 13 +++- 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/MAVProxy/modules/lib/mp_menu.py b/MAVProxy/modules/lib/mp_menu.py index 217b6f66d7..2ef3d40adb 100644 --- a/MAVProxy/modules/lib/mp_menu.py +++ b/MAVProxy/modules/lib/mp_menu.py @@ -361,9 +361,6 @@ def call(self): '''show a value dialog''' from MAVProxy.modules.lib.wx_loader import wx title = self.title - if title.find('FLYTOFRAMEUNITS') != -1 and self.settings is not None: - frameunits = "%s %s" % (self.settings.flytoframe, self.settings.height_unit) - title = title.replace('FLYTOFRAMEUNITS', frameunits) try: dlg = wx.TextEntryDialog(None, title, title, defaultValue=str(self.default)) except TypeError: @@ -372,6 +369,87 @@ def call(self): return None return dlg.GetValue() +# memory of last dropdowns +last_dropdown_selection = {} +last_value_selection = {} + +class MPMenuCallTextDropdownDialog(object): + '''used to create a value dialog with dropdown callback''' + def __init__(self, title='Enter Value', default='', + dropdown_options=None, + dropdown_label='Select option', + default_dropdown=None): + self.title = title + self.default = default + self.default_dropdown = default_dropdown + self.dropdown_options = dropdown_options or [] + self.dropdown_label = dropdown_label + + def call(self): + '''show a value dialog with dropdown''' + from MAVProxy.modules.lib.wx_loader import wx + + # Create a custom dialog + dlg = wx.Dialog(None, title=self.title, size=(400, 150)) + + # Create a vertical box sizer for the dialog + main_sizer = wx.BoxSizer(wx.VERTICAL) + + # Create a horizontal sizer for the text entry and dropdown + input_sizer = wx.BoxSizer(wx.HORIZONTAL) + + # Text entry label and control + text_label = wx.StaticText(dlg, label="Value:") + default = last_value_selection.get(self.title, self.default) + text_ctrl = wx.TextCtrl(dlg, value=str(default), size=(200, -1)) + + # Add text control components to input sizer + input_sizer.Add(text_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) + input_sizer.Add(text_ctrl, 1, wx.ALL | wx.EXPAND, 5) + + # Dropdown label and control + dropdown_label = wx.StaticText(dlg, label=self.dropdown_label) + dropdown_ctrl = wx.Choice(dlg, choices=self.dropdown_options) + + # Select first item by default if options exist + if self.dropdown_options: + default_idx = 0 + for i in range(len(self.dropdown_options)): + if self.dropdown_options[i] == self.default_dropdown: + default_idx = i + dropdown_ctrl.SetSelection(last_dropdown_selection.get(self.title,default_idx)) + + # Add dropdown components to input sizer + input_sizer.Add(dropdown_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) + input_sizer.Add(dropdown_ctrl, 0, wx.ALL | wx.EXPAND, 5) + + # Add the input sizer to the main sizer + main_sizer.Add(input_sizer, 0, wx.ALL | wx.EXPAND, 5) + + # Create button sizer with OK and Cancel buttons + button_sizer = dlg.CreateButtonSizer(wx.OK | wx.CANCEL) + main_sizer.Add(button_sizer, 0, wx.ALL | wx.ALIGN_CENTER, 10) + + # Set the sizer for the dialog + dlg.SetSizer(main_sizer) + + # Fit the dialog to its contents + dlg.Fit() + + # Show the dialog and get the result + if dlg.ShowModal() != wx.ID_OK: + return None + + text_value = text_ctrl.GetValue() + dropdown_index = dropdown_ctrl.GetSelection() + dropdown_value = self.dropdown_options[dropdown_index] if dropdown_index != -1 and self.dropdown_options else "" + + last_dropdown_selection[self.title] = dropdown_index + last_value_selection[self.title] = text_value + + # Return tuple with text value and selected dropdown value + return text_value + " " + dropdown_value + class MPMenuConfirmDialog(object): '''used to create a confirmation dialog''' def __init__(self, title='Confirmation', message='', callback=None, args=None): diff --git a/MAVProxy/modules/mavproxy_map/__init__.py b/MAVProxy/modules/mavproxy_map/__init__.py index ce7a5a4ea1..7df1447f3a 100644 --- a/MAVProxy/modules/mavproxy_map/__init__.py +++ b/MAVProxy/modules/mavproxy_map/__init__.py @@ -103,8 +103,10 @@ def __init__(self, mpstate): self.default_popup = MPMenuSubMenu('Popup', items=[]) self.add_menu(MPMenuItem('Fly To', 'Fly To', '# guided ', - handler=MPMenuCallTextDialog(title='Altitude (FLYTOFRAMEUNITS)', default=self.mpstate.settings.guidedalt, - settings=self.settings))) + handler=MPMenuCallTextDropdownDialog(title='Altitude', default=self.mpstate.settings.guidedalt, + dropdown_label='Frame', + dropdown_options=['AboveHome','AGL','AMSL'], + default_dropdown=self.settings.flytoframe))) self.add_menu(MPMenuItem('Terrain Check', 'Terrain Check', '# terrain check')) self.add_menu(MPMenuItem('Show Position', 'Show Position', 'showPosition')) self.add_menu(MPMenuItem('Google Maps Link', 'Google Maps Link', 'printGoogleMapsLink')) diff --git a/MAVProxy/modules/mavproxy_mode.py b/MAVProxy/modules/mavproxy_mode.py index f1a3a3efcf..8df21750c0 100644 --- a/MAVProxy/modules/mavproxy_mode.py +++ b/MAVProxy/modules/mavproxy_mode.py @@ -81,10 +81,19 @@ def cmd_guided(self, args): if args[0] == "forward": return self.cmd_guided_forward(args[1:]) - if len(args) != 1 and len(args) != 3: + if len(args) == 2: + frames = ['AboveHome', 'AGL', 'AMSL'] + if args[1] in frames: + self.settings.flytoframe = args[1] + else: + print("Usage: guided ALTITUDE %s" % '|'.join(frames)) + return + elif len(args) != 1 and len(args) != 3: print("Usage: guided ALTITUDE | guided LAT LON ALTITUDE | guided forward METRES") return + frame = self.flyto_frame() + if len(args) == 3: latitude = float(args[0]) longitude = float(args[1]) @@ -99,8 +108,6 @@ def cmd_guided(self, args): altitude = self.height_convert_from_units(altitude) - frame = self.flyto_frame() - print("Guided %s %s frame %u" % (str(latlon), str(altitude), frame)) if self.settings.guided_use_reposition: