# omniflo_weichen.py # Omniflo Weichen-Auswahl-Dialog (wx) und Weichen-Commands # Ersetzt die Weichen-Teile von OmniModulInsert.lsp + omniflo_weichen.dcl # ============================================ import wx import PyRx as Rx import PyDb as Db import PyEd as Ed from elemente.omniflo import ( load_weichen, filter_by, insert_from_entry, sivasnr_to_str, ) # ============================================================ # Weichen-Auswahl-Dialog (ersetzt omniflo_weichen.dcl) # ============================================================ class WeichenSelectDialog(wx.Dialog): """Weichen-Auswahl-Dialog mit Filtern. Layout: - Dropdown: ProfilTyp (gefiltert) - Filter-Gruppe Schaltungstyp: Alle / M / P (wx.RadioBox) - Filter-Gruppe Richtung: Alle / Links / Rechts (wx.RadioBox) - Detail-Felder (readonly): SivasNr, Winkel, Breite, Laenge - OK / Abbrechen """ def __init__(self, parent, basis_liste): super().__init__(parent, title="Omniflo Weiche auswaehlen", size=(500, 320), style=wx.DEFAULT_DIALOG_STYLE) self._basis = basis_liste self._gefiltert = list(basis_liste) self._selected_idx = 0 panel = wx.Panel(self) sizer = wx.BoxSizer(wx.VERTICAL) # Dropdown: ProfilTyp row_profil = wx.BoxSizer(wx.HORIZONTAL) row_profil.Add(wx.StaticText(panel, label="Profiltyp:"), 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5) self.cb_profil = wx.Choice(panel, choices=[]) self.cb_profil.Bind(wx.EVT_CHOICE, self._on_selection) row_profil.Add(self.cb_profil, 1) sizer.Add(row_profil, 0, wx.EXPAND | wx.ALL, 5) # Filter-Gruppe: Schaltungstyp + Richtung nebeneinander filter_sizer = wx.BoxSizer(wx.HORIZONTAL) self.rb_schaltung = wx.RadioBox(panel, label="Schaltungstyp", choices=["Alle", "M", "P"], majorDimension=1, style=wx.RA_SPECIFY_COLS) self.rb_schaltung.Bind(wx.EVT_RADIOBOX, self._apply_filter) filter_sizer.Add(self.rb_schaltung, 1, wx.EXPAND | wx.RIGHT, 5) self.rb_richtung = wx.RadioBox(panel, label="Richtung", choices=["Alle", "Links", "Rechts"], majorDimension=1, style=wx.RA_SPECIFY_COLS) self.rb_richtung.Bind(wx.EVT_RADIOBOX, self._apply_filter) filter_sizer.Add(self.rb_richtung, 1, wx.EXPAND) sizer.Add(filter_sizer, 0, wx.EXPAND | wx.ALL, 5) # Detail-Felder (2 Spalten) grid = wx.FlexGridSizer(cols=4, hgap=10, vgap=5) grid.AddGrowableCol(1) grid.AddGrowableCol(3) grid.Add(wx.StaticText(panel, label="SivasNr:"), 0, wx.ALIGN_CENTER_VERTICAL) self.txt_sivasnr = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(140, -1)) grid.Add(self.txt_sivasnr, 0) grid.Add(wx.StaticText(panel, label="Winkel:"), 0, wx.ALIGN_CENTER_VERTICAL) self.txt_winkel = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(100, -1)) grid.Add(self.txt_winkel, 0) grid.Add(wx.StaticText(panel, label="Breite:"), 0, wx.ALIGN_CENTER_VERTICAL) self.txt_breite = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(100, -1)) grid.Add(self.txt_breite, 0) grid.Add(wx.StaticText(panel, label="Laenge:"), 0, wx.ALIGN_CENTER_VERTICAL) self.txt_laenge = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(100, -1)) grid.Add(self.txt_laenge, 0) sizer.Add(grid, 0, wx.EXPAND | wx.ALL, 5) # OK / Cancel btn_sizer = self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL) sizer.Add(btn_sizer, 0, wx.EXPAND | wx.ALL, 10) panel.SetSizer(sizer) self.Fit() self.CenterOnScreen() # Initiale Befuellung self._refresh_dropdown() def _apply_filter(self, event=None): """Filter anwenden und Dropdown neu befuellen.""" self._refresh_dropdown() def _refresh_dropdown(self): """Dropdown mit gefilterter Liste neu fuellen.""" sch_idx = self.rb_schaltung.GetSelection() ri_idx = self.rb_richtung.GetSelection() # Schaltungstyp-Filter sch_filter = {0: None, 1: "M", 2: "P"}.get(sch_idx) # Richtungs-Filter (1=links, 2=rechts) ri_filter = {0: None, 1: 1, 2: 2}.get(ri_idx) self._gefiltert = [] for e in self._basis: if sch_filter and e.get("Schaltungstyp") != sch_filter: continue if ri_filter and e.get("KurvenRichtung") != ri_filter: continue self._gefiltert.append(e) # Dropdown neu befuellen self.cb_profil.Clear() for e in self._gefiltert: self.cb_profil.Append(e.get("ProfilTyp", "?")) if self._gefiltert: self.cb_profil.SetSelection(0) self._selected_idx = 0 self._update_details(0) else: self._selected_idx = -1 self.txt_sivasnr.SetValue("---") self.txt_winkel.SetValue("---") self.txt_breite.SetValue("---") self.txt_laenge.SetValue("---") def _on_selection(self, event): self._selected_idx = self.cb_profil.GetSelection() self._update_details(self._selected_idx) def _update_details(self, idx): if idx < 0 or idx >= len(self._gefiltert): return e = self._gefiltert[idx] self.txt_sivasnr.SetValue(sivasnr_to_str(e.get("Sivasnr"))) wkl = e.get("KurvenWinkel", 0) self.txt_winkel.SetValue(f"{wkl} Grad") self.txt_breite.SetValue(str(e.get("Breite", "?"))) self.txt_laenge.SetValue(str(e.get("Länge", "?"))) def get_selected(self): """Gewaehlten Weichen-Eintrag zurueckgeben.""" if 0 <= self._selected_idx < len(self._gefiltert): return self._gefiltert[self._selected_idx] return None # ============================================================ # Generische Weichen-Einfuege-Logik # ============================================================ def _weichen_command(winkel, weichentyp): """Weichen-Dialog oeffnen, Auswahl einfuegen.""" alle = load_weichen() # Nach Winkel filtern (None = alle Winkel) if winkel is not None: basis = filter_by(alle, "KurvenWinkel", winkel) else: basis = list(alle) # Nach WeichenTyp filtern if weichentyp: basis = [e for e in basis if e.get("WeichenTyp") == weichentyp] if not basis: wkl_str = "alle Winkel" if winkel is None else f"{winkel} Grad" typ_str = f" / {weichentyp}" if weichentyp else "" print(f"\nKeine Weichen fuer {wkl_str}{typ_str} gefunden.") return dlg = WeichenSelectDialog(None, basis) if dlg.ShowModal() == wx.ID_OK: eintrag = dlg.get_selected() dlg.Destroy() if eintrag: insert_from_entry(eintrag) else: print("\n[WEICHE] Kein Eintrag ausgewaehlt.") else: dlg.Destroy() print("\n[WEICHE] Abgebrochen.") # ============================================================ # Weichen-Commands (gleiche Namen wie LISP) # ============================================================ # --- 90 Grad --- @Rx.command("OMNI_W90_Einfach") def cmd_w90_einfach(): _weichen_command(90, "Einzelweiche") @Rx.command("OMNI_W90_Doppel") def cmd_w90_doppel(): _weichen_command(90, "Doppelweiche") @Rx.command("OMNI_W90_Dreiwege") def cmd_w90_dreiwege(): _weichen_command(90, "Dreiwegeweiche") # --- 45 Grad --- @Rx.command("OMNI_W45_Einfach") def cmd_w45_einfach(): _weichen_command(45, "Einzelweiche") @Rx.command("OMNI_W45_Doppel") def cmd_w45_doppel(): _weichen_command(45, "Doppelweiche") @Rx.command("OMNI_W45_Dreiwege") def cmd_w45_dreiwege(): _weichen_command(45, "Dreiwegeweiche") # --- Parallel (KurvenWinkel=0) --- @Rx.command("OMNI_WP_Einfach") def cmd_wp_einfach(): _weichen_command(0, "Einzelweiche") @Rx.command("OMNI_WP_Doppel") def cmd_wp_doppel(): _weichen_command(0, "Doppelweiche") @Rx.command("OMNI_WP_Dreiwege") def cmd_wp_dreiwege(): _weichen_command(0, "Dreiwegeweiche") # --- Weichenkoerper (KurvenWinkel=22.5) --- @Rx.command("OMNI_WK_Einfach") def cmd_wk_einfach(): _weichen_command(22.5, "Einzelweiche") @Rx.command("OMNI_WK_Doppel") def cmd_wk_doppel(): _weichen_command(22.5, "Doppelweiche") @Rx.command("OMNI_WK_Dreiwege") def cmd_wk_dreiwege(): _weichen_command(22.5, "Dreiwegeweiche") # --- Weichenkombinationen --- @Rx.command("OMNI_WKomb_Delta") def cmd_wkomb_delta(): _weichen_command(None, "Deltaweiche") @Rx.command("OMNI_WKomb_Star") def cmd_wkomb_star(): _weichen_command(None, "Sternweiche")