def data(self, index, role): row = index.row() col = index.column() if role == Qt.DisplayRole: if row < len(self.navpoints): # row is a navpoint navpoint = self.navpoints[row] if col == 0: return Navpoint.tstr(navpoint.type) elif col == 1: return navpoint.code elif col == 2: return navpoint.long_name else: # row is a parking position pk = self.pk_pos[row - len(self.navpoints)] #EarthCoords, Heading, str (gate|hangar|misc|tie-down), str list (heavy|jets|turboprops|props|helos) if col == 0: return 'PKG' elif col == 1: return pk elif col == 2: pk_info = env.airport_data.ground_net.parkingPosInfo(pk) txt = pk_info[2].capitalize() if pk_info[3] != []: txt += ' for ' + ', '.join(pk_info[3]) return txt elif role == Qt.ToolTipRole: coords = self.coordsForRow(row) if env.radarPos() == None: return str(coords) else: distance = env.radarPos().distanceTo(coords) return '%s°, %s' % (env.radarPos().headingTo(coords).readTrue(), dist_str(distance))
def toolTipText(self): txt = '' if self.social_name != None: txt += self.social_name + '\n' txt += 'Position: ' if self.position == None: txt += 'unknown' else: distance = env.radarPos().distanceTo(self.position) if distance < nearby_dist_threshold: txt += 'nearby' else: txt += '%s°, %s' % (env.radarPos().headingTo( self.position).readTrue(), dist_str(distance)) return txt
def __init__(self, parent, external, port): ''' external is a host (possibly localhost) for external FGCom instance, or None for internal (child process) ''' QWidget.__init__(self, parent) self.setupUi(self) client_address = some(external, 'localhost'), port self.settings = FgcomSettings(socket(AF_INET, SOCK_DGRAM), client_address) self.controller = Ticker(self.settings.send, parent=self) self.frequency_combo.addFrequencies([(frq, descr) for frq, descr, t in env.frequencies]) self.frequency_combo.addFrequencies(frequencies_always_proposed) if external == None: # child process self.onOff_button.setToolTip('Internal FGCom instance using local port %d' % port) ad = world_navpoint_db.findClosest(env.radarPos(), types=[Navpoint.AD]).code if env.airport_data == None else settings.location_code self.instance = InternalFgcomInstance(port, ['--airport=%s' % ad], self) self.instance.started.connect(self.processHasStarted) self.instance.finished.connect(self.processHasStopped) self.onOff_button.toggled.connect(self.switchFGCom) else: # creating box for external instance self.instance = None self.onOff_button.setToolTip('External FGCom instance on %s:%d' % client_address) self.onOff_button.setChecked(True) # keep checked (tested for RDF) self.onOff_button.setEnabled(False) self.PTT_button.setEnabled(True) self.controller.start(fgcom_controller_ticker_interval) self.PTT_button.pressed.connect(lambda: self.PTT(True)) self.PTT_button.released.connect(lambda: self.PTT(False)) self.softVolume_tickBox.clicked.connect(self.setVolume) self.frequency_combo.frequencyChanged.connect(self.setFrequency) self.updateRDF() self.RDF_tickBox.toggled.connect(self.updateRDF) self.onOff_button.toggled.connect(self.updateRDF) signals.localSettingsChanged.connect(self.updateRDF)
def start(self, traffic_count): # overrides (but calls) parent's p = lambda d: env.radarPos().moved(Heading(d, True), 1.5 * settings. map_range) env.ATCs.updateATC('N', p(360), 'North', None) env.ATCs.updateATC('S', p(180), 'South', None) env.ATCs.updateATC('E', p(90), 'East', None) env.ATCs.updateATC('W', p(270), 'West', None) SoloSessionManager.start(self, traffic_count)
def indicatePoint(self, coords): if env.pointOnMap(coords): if not self.lockPanZoom_button.isChecked( ) and self.autoCentre_action.isChecked(): self.scopeView.moveToShow(coords) self.scene.point_indicator.indicate(coords) else: # point is off map hdg = env.radarPos().headingTo(coords) signals.statusBarMsg.emit('Point is off map to the %s' % hdg.approxCardinal(True))
def spawnNewUncontrolledAircraft(self): rndpos = env.radarPos().moved(Heading(randint(1, 360), True), uniform(10, .8 * settings.radar_range)) rndalt = StdPressureAlt(randint(1, 10) * 1000) if self.airbornePositionFullySeparated(rndpos, rndalt): acft_type = choice(self.uncontrolled_aircraft_types) params = SoloParams(Status(Status.AIRBORNE), rndpos, rndalt, Heading(randint(1, 360), True), cruise_speed(acft_type)) params.XPDR_code = settings.uncontrolled_VFR_XPDR_code new_acft = self.mkAiAcft(acft_type, params, goal=None) if new_acft != None: self.uncontrolled_traffic.append(new_acft)
def new_arrival_APP(self, entry_point): type_choice = self.parkable_aircraft_types if self.parkable_aircraft_types != [] else self.playable_aircraft_types # must be landable too rwy_choice = [ rwy for rwy in env.airport_data.allRunways() if rwy.use_for_arrivals ] if rwy_choice == []: rwy_choice = env.airport_data.allRunways() pop_all( type_choice, lambda t: all(not rwy.acceptsAcftType(t) for rwy in rwy_choice)) if type_choice == []: return None acft_type = choice(type_choice) ils = any(rwy.hasILS() for rwy in rwy_choice) and random() >= settings.solo_ILSvsVisual_balance if entry_point == None: hdg = Heading(randint(1, 360), True) pos = env.radarPos().moved( hdg.opposite(), uniform(.33 * settings.radar_range, .75 * settings.radar_range)) else: pos = entry_point.coordinates hdg = pos.headingTo(env.radarPos()) alt = StdPressureAlt.fromFL( 10 * randint(settings.solo_APP_ceiling_FL_min // 10, settings.solo_APP_ceiling_FL_max // 10)) if not self.airbornePositionFullySeparated(pos, alt): return None ias = restrict_speed_under_ceiling( cruise_speed(acft_type), alt, StdPressureAlt.fromFL(150)) # 5000-ft anticipation params = SoloParams(Status(Status.AIRBORNE), pos, alt, hdg, ias) params.XPDR_code = env.nextSquawkCodeAssignment(XPDR_range_IFR_ARR) return self.mkAiAcft(acft_type, params, ils)
def __init__(self, socket, address): self.socket = socket self.address = address try: self.frq = env.frequencies[0][0] except IndexError: self.frq = frequencies_always_proposed[0][0] self.ptt = False # "push to talk" self.vol = 1 # output volume pos = env.radarPos() # packet format has 3 slots to fill: PTT, frq, vol self.packet_format = 'PTT=%d' self.packet_format += ',LAT=%f,LON=%f,ALT=%f' % (pos.lat, pos.lon, env.elevation(pos)) self.packet_format += ',COM1_FRQ=%s,COM2_FRQ=121.850' self.packet_format += ',OUTPUT_VOL=%f,SILENCE_THD=-60' self.packet_format += ',CALLSIGN=%s' % FGCom_callsign()
def handoverGuard(self, acft, atc): if acft.coords().distanceTo( env.radarPos()) <= settings.solo_CTR_range_dist: return 'Aircraft is still in your airspace.' # Check if expected receiver dist_key_expected = lambda atc: env.ATCs.getATC( atc).position.distanceTo(acft.goal.coordinates) expected_receiver = min(env.ATCs.knownATCs(), key=dist_key_expected) if atc != expected_receiver: return 'Destination is %s; hand over to %s.' % (acft.goal, expected_receiver) # Check if closest ATC dist_key_closest = lambda atc: env.ATCs.getATC( atc).position.distanceTo(acft.params.position) if atc != min(env.ATCs.knownATCs(), key=dist_key_closest): return 'ACFT not near enough this neighbour\'s airspace.'
def __init__(self, parent=None): QDialog.__init__(self, parent) self.setupUi(self) self.installEventFilter(RadioKeyEventFilter(self)) self.magneticDeclination_infoLabel.setText( some(env.readDeclination(), 'N/A')) self.radarPosition_infoLabel.setText(str(env.radarPos())) if env.airport_data == None: self.airport_tab.setEnabled(False) else: self.airportName_infoLabel.setText(env.locationName()) self.airportElevation_infoLabel.setText( '%.1f ft' % env.airport_data.field_elevation) table_model = RwyInfoTableModel(self) self.runway_tableView.setModel(table_model) for i in range(table_model.columnCount()): self.runway_tableView.resizeColumnToContents(i)
def new_arrival_TWR(self): acft_type = choice( self.parkable_aircraft_types if self.parkable_aircraft_types != [] else self.playable_aircraft_types) ils = random() >= settings.solo_ILSvsVisual_balance rwy_ok = lambda rwy: rwy.acceptsAcftType(acft_type) and (not ils or rwy .hasILS()) rwy = rnd_rwy([ rwy for rwy in env.airport_data.allRunways() if rwy.use_for_arrivals ], rwy_ok) if rwy == None: return None dthr = rwy.threshold(dthr=True) try: furthest = max([ dthr.distanceTo(acft.params.position) for acft in self.controlled_traffic if acft.isInboundGoal() ]) dist = max( furthest + uniform(1, 2) * distance_flown(TTF_separation, cruise_speed(acft_type)), settings.solo_TWR_range_dist) except ValueError: dist = settings.solo_TWR_range_dist / 2 if dist > min(settings.solo_TWR_range_dist * 1.5, settings.radar_range - 10): return None # to protect from creating aircraft out of radar range status = Status(Status.LANDING, arg=rwy.name) if ils else Status( Status.AIRBORNE) hdg = rwy.appCourse() alt = GS_alt(env.elevation(dthr), rwy.param_FPA, max(2, dist if ils else dist - 2)) params = SoloParams(status, env.radarPos().moved(hdg.opposite(), dist), alt, hdg, touch_down_speed(acft_type)) params.XPDR_code = env.nextSquawkCodeAssignment(XPDR_range_IFR_ARR) acft = self.mkAiAcft(acft_type, params, ils) acft.instructions.append( Instruction(Instruction.EXPECT_RWY, arg=rwy.name)) if ils: acft.instructions.append(Instruction(Instruction.CLEARED_APP)) return acft
def start(self, traffic_count): # overrides (but calls) parent's self.parkable_aircraft_types = \ [t for t in self.playable_aircraft_types if env.airport_data.ground_net.parkingPositions(acftType=t) != []] # Start errors (cancels start) if settings.solo_role_GND and self.parkable_aircraft_types == []: QMessageBox.critical( self.gui, 'Insufficient ground data', 'You cannot play solo GND with no parkable ACFT type.') return # Start warnings if (settings.solo_role_GND or settings.solo_role_TWR ) and settings.radar_signal_floor_level > max( 0, env.airport_data.field_elevation): QMessageBox.warning( self.gui, 'Radar visibility warning', 'You are playing solo TWR/GND with radar signal floor above surface.' ) if settings.solo_role_DEP and settings.solo_ARRvsDEP_balance == 0: QMessageBox.warning(self.gui, 'No departures warning', 'You are playing DEP with no departures set.') if settings.solo_role_APP and settings.solo_ARRvsDEP_balance == 1: QMessageBox.warning(self.gui, 'No arrivals warning', 'You are playing APP with no arrivals set.') # Set up ATC neighbours env.ATCs.updateATC('CTR', env.radarPos(), 'En-route control centre', None) if settings.solo_role_GND: env.ATCs.updateATC('Ramp', None, 'Apron/gate services', None) else: env.ATCs.updateATC('GND', None, 'Airport ground', None) if not settings.solo_role_TWR: env.ATCs.updateATC('TWR', None, 'Tower', None) if not settings.solo_role_APP: env.ATCs.updateATC('APP', None, 'Approach', None) if not settings.solo_role_DEP: env.ATCs.updateATC('DEP', None, 'Departure', None) SoloSessionManager.start(self, traffic_count)
def inTWRrange(params): return params.position.distanceTo(env.radarPos()) <= settings.solo_TWR_range_dist \ and params.altitude.diff(StdPressureAlt.fromFL(settings.solo_TWR_ceiling_FL)) < 0
def run(self): ## PREPARING QUERY pos = env.radarPos() qdict = { 'username': settings.MP_social_name, 'lon': pos.lon, 'lat': pos.lat, 'range': some(settings.ORSX_handover_range, settings.radar_range), 'xmlVersion': '1.0', 'contacts': ','.join( acft.identifier for acft in env.radar.contacts()) # should this be all FGMS connections? } if settings.publicised_frequency != None: qdict['frequency'] = str(settings.publicised_frequency) server_response = server_query('getFlightplans', qdict) ## USING RESPONSE if server_response != None: try: ww_root = ElementTree.fromstring(server_response) except ElementTree.ParseError as parse_error: print('Parse error in SX server data: %s' % parse_error) return new_ATCs = [] # ATCs first for ww_atc in ww_root.find('atcsInRange').iter( 'atc'): # NOTE the server sends the full list each time atc = ATC(ww_atc.find('callsign').text) atc.social_name = ww_atc.find('username').text atc.position = EarthCoords(float(ww_atc.find('lat').text), float(ww_atc.find('lon').text)) ww_frq = ww_atc.find('frequency').text try: atc.frequency = CommFrequency(ww_frq) except ValueError: atc.frequency = None new_ATCs.append(atc) self.ATCs_on_last_run = new_ATCs # Then strip data (contact claims and handover) for ww_flightplan in ww_root.iter( 'flightplan' ): # NOTE the server only sends those when something changes ww_header = ww_flightplan.find('header') ww_callsign = ww_header.find('callsign').text ww_owner = ww_header.find('owner').text if ww_owner == None: if ww_callsign in self.current_contact_claims: del self.current_contact_claims[ww_callsign] else: self.current_contact_claims[ww_callsign] = ww_owner if ww_header.find( 'handover' ).text == settings.session_manager.myCallsign( ): # RECEIVE A STRIP! strip = Strip() strip.writeDetail(received_from_detail, ww_owner) strip.writeDetail( assigned_SQ_detail, ck_int(ww_header.find('squawk').text, base=8)) strip.writeDetail(assigned_altitude_detail, ww_header.find('assignedAlt').text) # Ignored from WW header above: <flags>, <assignedRunway>, <assignedRoute>, <status>, <flight> # Ignored from WW data below: <fuelTime>; used with ulterior motive: <pilot> ww_data = ww_flightplan.find('data') # ATC-pie hides a token in <pilot>, wake turb. on its left and callsign to its right # e.g. <pilot>M__ATC-pie__X-FOO</pilot> for M turb. and X-FOO strip callsign # If the token is absent, we know the strip is from OpenRadar hidden_tokens = some(ww_data.find('pilot').text, '').split(ATCpie_hidden_string, maxsplit=1) if len( hidden_tokens ) == 1: # hidden marker NOT present; previous strip editor was OpenRadar strip.writeDetail(FPL.CALLSIGN, ww_callsign) else: # recognise strip edited with ATC-pie strip.writeDetail(FPL.WTC, hidden_tokens[0]) strip.writeDetail(FPL.CALLSIGN, hidden_tokens[1]) strip.writeDetail(FPL.FLIGHT_RULES, ww_data.find('type').text) strip.writeDetail(FPL.ACFT_TYPE, ww_data.find('aircraft').text) strip.writeDetail(FPL.ICAO_DEP, ww_data.find('departure').text) strip.writeDetail(FPL.ICAO_ARR, ww_data.find('destination').text) strip.writeDetail(FPL.ROUTE, ww_data.find('route').text) strip.writeDetail(FPL.CRUISE_ALT, ww_data.find('cruisingAlt').text) spd = ck_int(ww_data.find('trueAirspeed').text) if spd != None: strip.writeDetail(FPL.TAS, Speed(spd)) strip.writeDetail(FPL.COMMENTS, ww_data.find('remarks').text) # Possibly ignored details (OpenRadar confuses FPLs and strips): DEP time, EET, alt. AD, souls [*] signals.receiveStrip.emit(strip) send_update(ww_callsign, strip) # Acknowledge strip
def map_loc_str(pos): if env.pointOnMap(pos): return ' near %s' % env.navpoints.findClosest(pos) else: return ' far %s' % env.radarPos().headingTo(pos).approxCardinal(True)
def generateAircraftAndStrip(self): start_angle = uniform(0, 360) start_pos = env.radarPos().moved(Heading(start_angle, True), settings.solo_CTR_range_dist) end_pos = env.radarPos().moved( Heading(start_angle + 90 + uniform(1, 179), True), settings.solo_CTR_range_dist) transit_hdg = start_pos.headingTo(end_pos) dep_ad = world_navpoint_db.findClosest(env.radarPos().moved(transit_hdg.opposite(), \ uniform(1.2 * settings.map_range, 5000)), types=[Navpoint.AD]) dest_ad = world_navpoint_db.findClosest(env.radarPos().moved(transit_hdg, \ uniform(1.2 * settings.map_range, 5000)), types=[Navpoint.AD]) if env.pointOnMap(dep_ad.coordinates) or env.pointOnMap( dest_ad.coordinates): return None, None candidate_midpoints = [p for code in settings.solo_CTR_routing_points \ for p in env.navpoints.findAll(code, types=[Navpoint.NDB, Navpoint.VOR, Navpoint.FIX]) \ if start_pos.distanceTo(p.coordinates) < start_pos.distanceTo(end_pos)] midpoint = None if candidate_midpoints == [] else choice( candidate_midpoints) FLd10 = randint(settings.solo_CTR_floor_FL // 10, settings.solo_CTR_ceiling_FL // 10) if settings.solo_CTR_semi_circular_rule == SemiCircRule.E_W and (FLd10 % 2 == 0) != (transit_hdg.magneticAngle() >= 180) \ or settings.solo_CTR_semi_circular_rule == SemiCircRule.N_S and (FLd10 % 2 == 1) != (90 <= transit_hdg.magneticAngle() < 270): FLd10 += 1 if 10 * FLd10 > settings.solo_CTR_ceiling_FL: return None, None p_alt = StdPressureAlt.fromFL(10 * FLd10) if not self.airbornePositionFullySeparated(start_pos, p_alt): return None, None acft_type = choice(self.playable_aircraft_types) hdg = start_pos.headingTo(some(midpoint, dest_ad).coordinates) params = SoloParams(Status(Status.AIRBORNE), start_pos, p_alt, hdg, cruise_speed(acft_type)) params.XPDR_code = env.nextSquawkCodeAssignment(XPDR_range_IFR_transit) new_acft = self.mkAiAcft(acft_type, params, dest_ad) dist_key = lambda atc: env.ATCs.getATC(atc).position.distanceTo( start_pos) received_from = min(env.ATCs.knownATCs(), key=dist_key) strip = Strip() strip.writeDetail(FPL.CALLSIGN, new_acft.identifier) strip.writeDetail(FPL.ACFT_TYPE, new_acft.aircraft_type) strip.writeDetail(FPL.WTC, wake_turb_cat(new_acft.aircraft_type)) strip.writeDetail(FPL.FLIGHT_RULES, 'IFR') strip.writeDetail(FPL.ICAO_DEP, dep_ad.code) strip.writeDetail(FPL.ICAO_ARR, dest_ad.code) strip.writeDetail(FPL.CRUISE_ALT, env.readStdAlt(new_acft.params.altitude)) strip.writeDetail(assigned_altitude_detail, strip.lookup(FPL.CRUISE_ALT)) strip.writeDetail(assigned_SQ_detail, new_acft.params.XPDR_code) strip.writeDetail(received_from_detail, received_from) if midpoint != None: strip.insertRouteWaypoint(midpoint) new_acft.instructions.append( Instruction(Instruction.FOLLOW_ROUTE, arg=strip.lookup(parsed_route_detail).dup())) return new_acft, strip
def __init__(self, parent=None): QWidget.__init__(self, parent) self.setupUi(self) self.lockPanZoom_button.setIcon(QIcon(IconFile.button_lockRadar)) self.mouse_info.clear() self.scene = RadarScene(self) self.scopeView.setScene(self.scene) self.courseLineFlyTime_edit.setValue(self.scene.speedMarkCount()) self.last_airfield_clicked = None self.LDG_disp_actions = {} # BG IMAGES menu self.rebuildImgToggleMenu() # Nav menu nav_menu = QMenu() self._addMenuToggleAction(nav_menu, 'Navaids', True, self.scene.layers[Layer.NAV_AIDS].setVisible) self._addMenuToggleAction( nav_menu, 'Fixes', False, self.scene.layers[Layer.NAV_FIXES].setVisible) self._addMenuToggleAction( nav_menu, 'RNAV points', False, self.scene.layers[Layer.RNAV_POINTS].setVisible) nav_menu.addSeparator() self._addMenuToggleAction( nav_menu, 'Airfields', False, self.scene.layers[Layer.NAV_AIRFIELDS].setVisible) self.nav_menuButton.setMenu(nav_menu) # AD menu AD_menu = QMenu() self._addMenuToggleAction(AD_menu, 'Ground routes', False, self.scene.showGroundNetworks) self._addMenuToggleAction(AD_menu, 'Taxiway names', False, self.scene.showTaxiwayNames) self._addMenuToggleAction(AD_menu, 'Highlight TWYs under mouse', True, self.scene.highlightEdgesOnMouseover) self._addMenuToggleAction(AD_menu, 'RWY names always visible', False, self.scene.setRunwayNamesAlwaysVisible) AD_menu.addSeparator() self._addMenuToggleAction( AD_menu, 'Parking positions', True, self.scene.layers[Layer.PARKING_POSITIONS].setVisible) self._addMenuToggleAction( AD_menu, 'Holding lines', False, self.scene.layers[Layer.HOLDING_LINES].setVisible) self._addMenuToggleAction( AD_menu, 'Taxiway centre lines', False, self.scene.layers[Layer.TAXIWAY_LINES].setVisible) self._addMenuToggleAction( AD_menu, 'Other objects', True, self.scene.layers[Layer.AIRPORT_OBJECTS].setVisible) self.AD_menuButton.setMenu(AD_menu) # LDG menu if env.airport_data == None: self.LDG_menuButton.setEnabled(False) else: LDG_menu = QMenu() self.syncLDG_action = self._addMenuToggleAction( LDG_menu, 'Sync with arrival runway selection', True, self.setSyncLDG) for rwy in env.airport_data.allRunways( sortByName=True ): # all menu options set to False below; normally OK at start txt = 'RWY %s' % rwy.name if rwy.ILS_cat != None: txt += ' (%s)' % rwy.ILS_cat action = self._addMenuToggleAction( LDG_menu, txt, False, lambda b, r=rwy.name: self.scene.showLandingHelper(r, b)) action.triggered.connect( lambda b: self.syncLDG_action.setChecked(False) ) # cancel sync when one is set manually (triggered) self.LDG_disp_actions[rwy.name] = action LDG_menu.addSeparator() self._addMenuToggleAction(LDG_menu, 'Slope altitudes', True, self.scene.showSlopeAltitudes) self._addMenuToggleAction(LDG_menu, 'LOC interception cones', False, self.scene.showInterceptionCones) self.LDG_menuButton.setMenu(LDG_menu) # ACFT menu ACFT_menu = QMenu() self._addMenuToggleAction(ACFT_menu, 'Filter out unlinked GND modes', False, lambda b: self.scene.showGndModes(not b)) ACFT_menu.addSeparator() self._addMenuToggleAction(ACFT_menu, 'Selected ACFT course/assignments', True, self.scene.showSelectionAssignments) self._addMenuToggleAction(ACFT_menu, 'All courses/vectors', False, self.scene.showVectors) self._addMenuToggleAction(ACFT_menu, 'All routes', False, self.scene.showRoutes) ACFT_menu.addSeparator() self._addMenuToggleAction(ACFT_menu, 'Unlinked radar tags', True, self.scene.showUnlinkedTags) self._addMenuToggleAction(ACFT_menu, 'Separation rings', False, self.scene.showSeparationRings) self.ACFT_menuButton.setMenu(ACFT_menu) # OPTIONS menu options_menu = QMenu() self.autoCentre_action = self._addMenuToggleAction( options_menu, 'Centre on indications', False, None) self._addMenuToggleAction( options_menu, 'Show custom labels', True, self.scene.layers[Layer.CUSTOM_LABELS].setVisible) self.showRdfLine_action = self._addMenuToggleAction( options_menu, 'Show RDF line', False, self.scene.showRdfLine) options_menu.addSeparator() drawAirport_action = QAction('Draw additional airport...', self) drawAirport_action.triggered.connect(self.drawAdditionalAirport) resetAirports_action = QAction('Reset drawn airports', self) resetAirports_action.triggered.connect(self.scene.resetAirportItems) options_menu.addAction(drawAirport_action) options_menu.addAction(resetAirports_action) self.options_menuButton.setMenu(options_menu) # Other actions and signals self.lockPanZoom_button.toggled.connect(self.lockRadar) self.courseLineFlyTime_edit.valueChanged.connect( self.scene.setSpeedMarkCount) self.scene.mouseInfo.connect(self.mouse_info.setText) self.scene.addRemoveRouteNavpoint.connect( self.addRemoveRouteNavpointToSelection) self.scene.imagesRedrawn.connect(self.rebuildImgToggleMenu) self.zoomLevel_slider.valueChanged.connect(self.changeZoomLevel) self.scopeView.zoom_signal.connect(self.zoom) # External signal connections below. CAUTION: these must all be disconnected on widget deletion signals.selectionChanged.connect(self.mouse_info.clear) signals.runwayUseChanged.connect(self.updateLdgMenuAndDisplay) signals.localSettingsChanged.connect(self.updateRdfMenuAction) signals.navpointClick.connect(self.setLastAirfieldClicked) signals.indicatePoint.connect(self.indicatePoint) signals.mainWindowClosing.connect(self.close) # Finish up self.sync_LDG_display = True self.updateLdgMenuAndDisplay() self.updateRdfMenuAction() self.scopeView.moveToShow(env.radarPos()) self.f_scale = lambda x: max_zoom_factor / exp(x * log( settings.map_range / max_zoom_range)) # x in [0, 1] self.changeZoomLevel(self.zoomLevel_slider.value())
def updateDisplay(self): if self.radar_contact == None: self.info_area.setEnabled(False) return else: self.info_area.setEnabled(True) # AIRCRAFT BOX # Heading hdg = self.radar_contact.heading() self.aircraftHeading_info.setText('?' if hdg == None else hdg.read() + '°') # Alt./FL alt = self.radar_contact.xpdrAlt() if alt == None: self.aircraftAltitude_info.setText( 'N/A' if settings.SSR_mode_capability in '0A' else '?') else: alt_str = env.readStdAlt(alt, step=None, unit=True) if not alt_str.startswith('FL') and env.QNH( noneSafe=False) == None: alt_str += ' !!QNH' self.aircraftAltitude_info.setText(alt_str) # Ground speed groundSpeed = self.radar_contact.groundSpeed() if groundSpeed == None: self.aircraftGroundSpeed_info.setText('?') else: self.aircraftGroundSpeed_info.setText(str(groundSpeed)) # Indicated airspeed speed ias = self.radar_contact.IAS() if ias == None: self.indicatedAirSpeed_info.setText( '?' if settings.SSR_mode_capability == 'S' else 'N/A') else: s = str(ias) if self.radar_contact.xpdrIAS() == None: s += ' !!estimate' self.indicatedAirSpeed_info.setText(s) # Vertical speed vs = self.radar_contact.verticalSpeed() if vs == None: self.aircraftVerticalSpeed_info.setText( 'N/A' if settings.SSR_mode_capability in '0A' else '?') else: self.aircraftVerticalSpeed_info.setText('%+d ft/min' % vs) # ROUTE BOX coords = self.radar_contact.coords() strip = env.linkedStrip(self.radar_contact) route = None if strip == None else strip.lookup(parsed_route_detail) self._last_known_route = route if route == None: self.route_box.setEnabled(False) else: self.route_box.setEnabled(True) i_leg = route.currentLegIndex(coords) wpdist = coords.distanceTo(route.waypoint(i_leg).coordinates) self.legCount_info.setText('%d of %d' % (i_leg + 1, route.legCount())) self.legSpec_info.setText(route.legStr(i_leg)) self.waypointAt_info.setText(dist_str(wpdist)) try: # TTF if groundSpeed == None: raise ValueError('No ground speed info') self.waypointTTF_info.setText(TTF_str(wpdist, groundSpeed)) except ValueError: self.waypointTTF_info.setText('?') # AIRPORT BOX if env.airport_data != None: airport_dist = coords.distanceTo(env.radarPos()) self.airportBearing_info.setText( coords.headingTo(env.radarPos()).read()) self.airportDistance_info.setText(dist_str(airport_dist)) try: # TTF if groundSpeed == None: raise ValueError('No ground speed info') self.airportTTF_info.setText(TTF_str(airport_dist, groundSpeed)) except ValueError: self.airportTTF_info.setText('?')
def extractSectorFile(self): txt, ignore = QFileDialog.getOpenFileName(self, caption='Select sector file to extract from') if txt != '': extract_sector(txt, env.radarPos(), settings.map_range) QMessageBox.information(self, 'Done extracting', \ 'Background drawings extracted.\nSee console for summary and files created in the output directory.')
def __init__(self, launcher, parent=None): QMainWindow.__init__(self, parent) self.setupUi(self) self.central_workspace = WorkspaceWidget(self) self.setCentralWidget(self.central_workspace) self.installEventFilter(RadioKeyEventFilter(self)) self.setAttribute(Qt.WA_DeleteOnClose) self.launcher = launcher settings.controlled_tower_viewer = FlightGearTowerViewer(self) settings.session_manager = SessionManager(self) self.setWindowTitle('%s - %s (%s)' % (self.windowTitle(), env.locationName(), settings.location_code)) self.session_start_sound_lock_timer = QTimer(self) self.session_start_sound_lock_timer.setSingleShot(True) self.session_start_sound_lock_timer.timeout.connect(self.unlockSounds) ## Restore saved dock layout try: with open(dock_layout_file, 'rb') as f: # Restore saved dock arrangement self.restoreState(f.read()) except FileNotFoundError: # Fallback on default dock arrangement # left docks, top zone self.tabifyDockWidget(self.selection_info_dock, self.weather_dock) self.tabifyDockWidget(self.selection_info_dock, self.towerView_dock) self.tabifyDockWidget(self.selection_info_dock, self.navigator_dock) self.selection_info_dock.hide() # left docks, bottom zone self.tabifyDockWidget(self.instructions_dock, self.notepads_dock) self.tabifyDockWidget(self.instructions_dock, self.radio_dock) self.tabifyDockWidget(self.instructions_dock, self.FPLlist_dock) self.tabifyDockWidget(self.instructions_dock, self.CPDLC_dock) self.instructions_dock.hide() self.notepads_dock.hide() self.radio_dock.hide() self.CPDLC_dock.hide() # right docks self.rwyBoxes_dock.hide() # hiding this because bad position (user will drag 1st thing after raise) # bottom docks self.atcTextChat_dock.hide() ## Permanent tool/status bar widgets self.selectionInfo_toolbar.addWidget(SelectionInfoToolbarWidget(self)) self.METAR_statusBarLabel = QLabel() self.PTT_statusBarLabel = QLabel() self.RDF_statusBarLabel = QLabel() self.RDF_statusBarLabel.setToolTip('Current signal / last QDM') self.wind_statusBarLabel = QLabel() self.QNH_statusBarLabel = QLabel() self.QNH_statusBarLabel.setToolTip('hPa / inHg') self.clock_statusBarLabel = QLabel() self.alarmClock_statusBarButtons = [AlarmClockButton('1', self), AlarmClockButton('2', self)] self.statusbar.addWidget(self.METAR_statusBarLabel) self.statusbar.addPermanentWidget(self.PTT_statusBarLabel) self.statusbar.addPermanentWidget(self.RDF_statusBarLabel) self.statusbar.addPermanentWidget(self.wind_statusBarLabel) self.statusbar.addPermanentWidget(self.QNH_statusBarLabel) for b in self.alarmClock_statusBarButtons: self.statusbar.addPermanentWidget(b) b.alarm.connect(self.notification_pane.notifyAlarmClockTimedOut) self.statusbar.addPermanentWidget(self.clock_statusBarLabel) # Populate menus (toolbar visibility and airport viewpoints) toolbar_menu = QMenu() self.general_viewToolbar_action = self.general_toolbar.toggleViewAction() self.stripActions_viewToolbar_action = self.stripActions_toolbar.toggleViewAction() self.docks_viewToolbar_action = self.docks_toolbar.toggleViewAction() self.selectionInfo_viewToolbar_action = self.selectionInfo_toolbar.toggleViewAction() self.radarAssistance_viewToolbar_action = self.radarAssistance_toolbar.toggleViewAction() self.workspace_viewToolbar_action = self.workspace_toolbar.toggleViewAction() toolbar_menu.addAction(self.general_viewToolbar_action) toolbar_menu.addAction(self.stripActions_viewToolbar_action) toolbar_menu.addAction(self.docks_viewToolbar_action) toolbar_menu.addAction(self.selectionInfo_viewToolbar_action) toolbar_menu.addAction(self.radarAssistance_viewToolbar_action) toolbar_menu.addAction(self.workspace_viewToolbar_action) self.toolbars_view_menuAction.setMenu(toolbar_menu) if env.airport_data == None or len(env.airport_data.viewpoints) == 0: self.viewpointSelection_view_menuAction.setEnabled(False) else: viewPointSelection_menu = QMenu() viewPointSelection_actionGroup = QActionGroup(self) for vp_i, (vp_pos, vp_h, vp_name) in enumerate(env.airport_data.viewpoints): action = QAction('%s - %d ft ASFC' % (vp_name, vp_h + .5), self) action.setCheckable(True) action.triggered.connect(lambda ignore_checked, i=vp_i: self.selectIndicateViewpoint(i)) viewPointSelection_actionGroup.addAction(action) actions = viewPointSelection_actionGroup.actions() viewPointSelection_menu.addActions(actions) self.viewpointSelection_view_menuAction.setMenu(viewPointSelection_menu) try: actions[settings.selected_viewpoint].setChecked(True) except IndexError: actions[0].setChecked(True) ## Memory-persistent windows and dialogs self.solo_connect_dialog_AD = StartSoloDialog_AD(self) self.MP_connect_dialog = StartFlightGearMPdialog(self) self.start_student_session_dialog = StartStudentSessionDialog(self) self.recall_cheat_dialog = DiscardedStripsDialog(self, ShelfFilterModel(self, env.discarded_strips, False), 'Sent and deleted strips') self.shelf_dialog = DiscardedStripsDialog(self, ShelfFilterModel(self, env.discarded_strips, True), 'Strip shelf') self.environment_info_dialog = EnvironmentInfoDialog(self) self.about_dialog = AboutDialog(self) self.teaching_console = TeachingConsole(parent=self) self.unit_converter = UnitConversionWindow(parent=self) self.world_airport_navigator = WorldAirportNavigator(parent=self) self.quick_reference = QuickReference(parent=self) for w in self.teaching_console, self.unit_converter, self.world_airport_navigator, self.quick_reference: w.setWindowFlags(Qt.Window) w.installEventFilter(RadioKeyEventFilter(w)) # Make a few actions always visible self.addAction(self.newStrip_action) self.addAction(self.newLinkedStrip_action) self.addAction(self.newFPL_action) self.addAction(self.newLinkedFPL_action) self.addAction(self.startTimer1_action) self.addAction(self.forceStartTimer1_action) self.addAction(self.startTimer2_action) self.addAction(self.forceStartTimer2_action) self.addAction(self.notificationSounds_options_action) self.addAction(self.quickReference_help_action) self.addAction(self.saveDockLayout_view_action) self.addAction(self.recallWindowState_view_action) # Populate icons self.newStrip_action.setIcon(QIcon(IconFile.action_newStrip)) self.newLinkedStrip_action.setIcon(QIcon(IconFile.action_newLinkedStrip)) self.newFPL_action.setIcon(QIcon(IconFile.action_newFPL)) self.newLinkedFPL_action.setIcon(QIcon(IconFile.action_newLinkedFPL)) self.teachingConsole_view_action.setIcon(QIcon(IconFile.panel_teaching)) self.unitConversionTool_view_action.setIcon(QIcon(IconFile.panel_unitConv)) self.worldAirportNavigator_view_action.setIcon(QIcon(IconFile.panel_airportList)) self.environmentInfo_view_action.setIcon(QIcon(IconFile.panel_envInfo)) self.generalSettings_options_action.setIcon(QIcon(IconFile.action_generalSettings)) self.soloSessionSettings_system_action.setIcon(QIcon(IconFile.action_sessionSettings)) self.runwaysInUse_options_action.setIcon(QIcon(IconFile.action_runwayUse)) self.newLooseStripBay_view_action.setIcon(QIcon(IconFile.action_newLooseStripBay)) self.newRadarScreen_view_action.setIcon(QIcon(IconFile.action_newRadarScreen)) self.newStripRackPanel_view_action.setIcon(QIcon(IconFile.action_newRackPanel)) self.popOutCurrentWindow_view_action.setIcon(QIcon(IconFile.action_popOutWindow)) self.reclaimPoppedOutWindows_view_action.setIcon(QIcon(IconFile.action_reclaimWindows)) self.primaryRadar_options_action.setIcon(QIcon(IconFile.option_primaryRadar)) self.approachSpacingHints_options_action.setIcon(QIcon(IconFile.option_approachSpacingHints)) self.runwayOccupationWarnings_options_action.setIcon(QIcon(IconFile.option_runwayOccupationMonitor)) self.routeConflictWarnings_options_action.setIcon(QIcon(IconFile.option_routeConflictWarnings)) self.trafficIdentification_options_action.setIcon(QIcon(IconFile.option_identificationAssistant)) setDockAndActionIcon(IconFile.panel_ATCs, self.handovers_dockView_action, self.handover_dock) setDockAndActionIcon(IconFile.panel_atcChat, self.atcTextChat_dockView_action, self.atcTextChat_dock) setDockAndActionIcon(IconFile.panel_CPDLC, self.cpdlc_dockView_action, self.CPDLC_dock) setDockAndActionIcon(IconFile.panel_FPLs, self.FPLs_dockView_action, self.FPLlist_dock) setDockAndActionIcon(IconFile.panel_instructions, self.instructions_dockView_action, self.instructions_dock) setDockAndActionIcon(IconFile.panel_navigator, self.navpoints_dockView_action, self.navigator_dock) setDockAndActionIcon(IconFile.panel_notepads, self.notepads_dockView_action, self.notepads_dock) setDockAndActionIcon(IconFile.panel_notifications, self.notificationArea_dockView_action, self.notification_dock) setDockAndActionIcon(IconFile.panel_radios, self.fgcom_dockView_action, self.radio_dock) setDockAndActionIcon(IconFile.panel_runwayBox, self.runwayBoxes_dockView_action, self.rwyBoxes_dock) setDockAndActionIcon(IconFile.panel_selInfo, self.radarContactDetails_dockView_action, self.selection_info_dock) setDockAndActionIcon(IconFile.panel_racks, self.strips_dockView_action, self.strip_dock) setDockAndActionIcon(IconFile.panel_txtChat, self.radioTextChat_dockView_action, self.radioTextChat_dock) setDockAndActionIcon(IconFile.panel_twrView, self.towerView_dockView_action, self.towerView_dock) setDockAndActionIcon(IconFile.panel_weather, self.weather_dockView_action, self.weather_dock) # action TICKED STATES (set here before connections) self.windowedWorkspace_view_action.setChecked(settings.saved_workspace_windowed_view) self.verticalRwyBoxLayout_view_action.setChecked(settings.vertical_runway_box_layout) self.notificationSounds_options_action.setChecked(settings.notification_sounds_enabled) self.primaryRadar_options_action.setChecked(settings.primary_radar_active) self.routeConflictWarnings_options_action.setChecked(settings.route_conflict_warnings) self.trafficIdentification_options_action.setChecked(settings.traffic_identification_assistant) self.runwayOccupationWarnings_options_action.setChecked(settings.monitor_runway_occupation) self.approachSpacingHints_options_action.setChecked(settings.APP_spacing_hints) # action CONNECTIONS # non-menu actions self.newStrip_action.triggered.connect(lambda: new_strip_dialog(self, default_rack_name, linkToSelection=False)) self.newLinkedStrip_action.triggered.connect(lambda: new_strip_dialog(self, default_rack_name, linkToSelection=True)) self.newFPL_action.triggered.connect(lambda: self.FPLlist_pane.createLocalFPL(link=None)) self.newLinkedFPL_action.triggered.connect(lambda: self.FPLlist_pane.createLocalFPL(link=selection.strip)) self.startTimer1_action.triggered.connect(lambda: self.startTimer(0, False)) self.forceStartTimer1_action.triggered.connect(lambda: self.startTimer(0, True)) self.startTimer2_action.triggered.connect(lambda: self.startTimer(1, False)) self.forceStartTimer2_action.triggered.connect(lambda: self.startTimer(1, True)) # system menu self.soloSession_system_action.triggered.connect(lambda: self.startStopSession(self.start_solo)) self.connectFlightGearMP_system_action.triggered.connect(lambda: self.startStopSession(self.start_FlightGearMP)) self.teacherSession_system_action.triggered.connect(lambda: self.startStopSession(self.start_teaching)) self.studentSession_system_action.triggered.connect(lambda: self.startStopSession(self.start_learning)) self.reloadAdditionalViewers_system_action.triggered.connect(self.reloadAdditionalViewers) self.reloadBgImages_system_action.triggered.connect(self.reloadBackgroundImages) self.reloadColourConfig_system_action.triggered.connect(self.reloadColourConfig) self.reloadRoutePresets_system_action.triggered.connect(self.reloadRoutePresets) self.reloadEntryExitPoints_system_action.triggered.connect(self.reloadEntryExitPoints) self.announceFgSession_system_action.triggered.connect(self.announceFgSession) self.fgcomEchoTest_system_action.triggered.connect(self.radio_pane.performEchoTest) self.extractSectorFile_system_action.triggered.connect(self.extractSectorFile) self.repositionBgImages_system_action.triggered.connect(self.repositionRadarBgImages) self.measuringLogsCoordinates_system_action.toggled.connect(self.switchMeasuringCoordsLog) self.airportGateway_system_action.triggered.connect(lambda: self.goToURL(airport_gateway_URL)) self.openStreetMap_system_action.triggered.connect(lambda: self.goToURL(mk_OSM_URL(env.radarPos()))) self.soloSessionSettings_system_action.triggered.connect(self.openSoloSessionSettings) self.locationSettings_system_action.triggered.connect(self.openLocalSettings) self.systemSettings_system_action.triggered.connect(self.openSystemSettings) self.changeLocation_system_action.triggered.connect(self.changeLocation) self.quit_system_action.triggered.connect(self.close) # view menu self.saveDockLayout_view_action.triggered.connect(self.saveDockLayout) self.recallWindowState_view_action.triggered.connect(self.recallWindowState) self.handovers_dockView_action.triggered.connect(lambda: self.raiseDock(self.handover_dock)) self.atcTextChat_dockView_action.triggered.connect(lambda: self.raiseDock(self.atcTextChat_dock)) self.cpdlc_dockView_action.triggered.connect(lambda: self.raiseDock(self.CPDLC_dock)) self.FPLs_dockView_action.triggered.connect(lambda: self.raiseDock(self.FPLlist_dock)) self.instructions_dockView_action.triggered.connect(lambda: self.raiseDock(self.instructions_dock)) self.navpoints_dockView_action.triggered.connect(lambda: self.raiseDock(self.navigator_dock)) self.notepads_dockView_action.triggered.connect(lambda: self.raiseDock(self.notepads_dock)) self.notificationArea_dockView_action.triggered.connect(lambda: self.raiseDock(self.notification_dock)) self.fgcom_dockView_action.triggered.connect(lambda: self.raiseDock(self.radio_dock)) self.runwayBoxes_dockView_action.triggered.connect(lambda: self.raiseDock(self.rwyBoxes_dock)) self.radarContactDetails_dockView_action.triggered.connect(lambda: self.raiseDock(self.selection_info_dock)) self.strips_dockView_action.triggered.connect(lambda: self.raiseDock(self.strip_dock)) self.radioTextChat_dockView_action.triggered.connect(lambda: self.raiseDock(self.radioTextChat_dock)) self.towerView_dockView_action.triggered.connect(lambda: self.raiseDock(self.towerView_dock)) self.weather_dockView_action.triggered.connect(lambda: self.raiseDock(self.weather_dock)) self.windowedWorkspace_view_action.toggled.connect(self.central_workspace.switchWindowedView) self.popOutCurrentWindow_view_action.triggered.connect(self.central_workspace.popOutCurrentWindow) self.reclaimPoppedOutWindows_view_action.triggered.connect(self.central_workspace.reclaimPoppedOutWidgets) self.newLooseStripBay_view_action.triggered.connect(lambda: self.central_workspace.addWorkspaceWidget(WorkspaceWidget.LOOSE_BAY)) self.newRadarScreen_view_action.triggered.connect(lambda: self.central_workspace.addWorkspaceWidget(WorkspaceWidget.RADAR_SCREEN)) self.newStripRackPanel_view_action.triggered.connect(lambda: self.central_workspace.addWorkspaceWidget(WorkspaceWidget.STRIP_PANEL)) self.verticalRwyBoxLayout_view_action.toggled.connect(self.switchVerticalRwyBoxLayout) self.towerView_view_action.triggered.connect(self.toggleTowerWindow) self.addViewer_view_action.triggered.connect(self.addView) self.listViewers_view_action.triggered.connect(self.listAdditionalViews) self.activateAdditionalViewers_view_action.toggled.connect(self.activateAdditionalViews) self.removeViewer_view_action.triggered.connect(self.removeView) self.teachingConsole_view_action.triggered.connect(self.teaching_console.show) self.unitConversionTool_view_action.triggered.connect(self.unit_converter.show) self.worldAirportNavigator_view_action.triggered.connect(self.world_airport_navigator.show) self.environmentInfo_view_action.triggered.connect(self.environment_info_dialog.exec) # options menu self.runwaysInUse_options_action.triggered.connect(self.configureRunwayUse) self.notificationSounds_options_action.toggled.connect(self.switchNotificationSounds) self.primaryRadar_options_action.toggled.connect(self.switchPrimaryRadar) self.routeConflictWarnings_options_action.toggled.connect(self.switchConflictWarnings) self.trafficIdentification_options_action.toggled.connect(self.switchTrafficIdentification) self.runwayOccupationWarnings_options_action.toggled.connect(self.switchRwyOccupationIndications) self.approachSpacingHints_options_action.toggled.connect(self.switchApproachSpacingHints) self.generalSettings_options_action.triggered.connect(self.openGeneralSettings) # cheat menu self.pauseSimulation_cheat_action.toggled.connect(self.pauseSession) self.spawnAircraft_cheat_action.triggered.connect(self.spawnAircraft) self.killSelectedAircraft_cheat_action.triggered.connect(self.killSelectedAircraft) self.popUpMsgOnRejectedInstr_cheat_action.toggled.connect(self.setRejectedInstrPopUp) self.showRecognisedVoiceStrings_cheat_action.toggled.connect(self.setShowRecognisedVoiceStrings) self.ensureClearWeather_cheat_action.toggled.connect(self.ensureClearWeather) self.ensureDayLight_cheat_action.triggered.connect(self.towerView_pane.ensureDayLight) self.changeTowerHeight_cheat_action.triggered.connect(self.changeTowerHeight) self.recallDiscardedStrip_cheat_action.triggered.connect(self.recall_cheat_dialog.exec) self.radarCheatMode_cheat_action.toggled.connect(self.setRadarCheatMode) # help menu self.quickReference_help_action.triggered.connect(self.quick_reference.show) self.videoTutorial_help_action.triggered.connect(lambda: self.goToURL(video_tutorial_URL)) self.FAQ_help_action.triggered.connect(lambda: self.goToURL(FAQ_URL)) self.about_help_action.triggered.connect(self.about_dialog.exec) ## More signal connections signals.openShelfRequest.connect(self.shelf_dialog.exec) signals.privateAtcChatRequest.connect(lambda: self.raiseDock(self.atcTextChat_dock)) signals.stripRecall.connect(recover_strip) env.radar.blip.connect(env.strips.refreshViews) env.radar.lostContact.connect(self.aircraftHasDisappeared) signals.aircraftKilled.connect(self.aircraftHasDisappeared) env.strips.rwyBoxFreed.connect(lambda box, strip: env.airport_data.physicalRunway_restartWtcTimer(box, strip.lookup(FPL.WTC))) env.rdf.signalChanged.connect(self.updateRDF) signals.statusBarMsg.connect(lambda msg: self.statusbar.showMessage(msg, status_bar_message_timeout)) signals.newWeather.connect(self.updateWeatherIfPrimary) signals.kbdPTT.connect(self.updatePTT) signals.sessionStarted.connect(self.sessionHasStarted) signals.sessionEnded.connect(self.sessionHasEnded) signals.towerViewProcessToggled.connect(self.towerView_view_action.setChecked) signals.towerViewProcessToggled.connect(self.towerView_cheat_menu.setEnabled) signals.stripInfoChanged.connect(env.strips.refreshViews) signals.fastClockTick.connect(self.updateClock) signals.fastClockTick.connect(env.cpdlc.updateAckStatuses) signals.slowClockTick.connect(strip_auto_print_check) signals.stripEditRequest.connect(lambda strip: edit_strip(self, strip)) signals.selectionChanged.connect(self.updateStripFplActions) signals.receiveStrip.connect(receive_strip) signals.handoverFailure.connect(self.recoverFailedHandover) signals.sessionPaused.connect(env.radar.stopSweeping) signals.sessionResumed.connect(env.radar.startSweeping) signals.aircraftKilled.connect(env.radar.silentlyForgetContact) signals.rackVisibilityLost.connect(self.collectClosedRacks) signals.localSettingsChanged.connect(env.rdf.clearAllSignals) signals.localSettingsChanged.connect(self.updateRDF) ## MISC GUI setup self.strip_pane.setViewRacks([default_rack_name]) # will be moved out if a rack panel's saved "visible_racks" claims it [*1] self.strip_pane.restoreState(settings.saved_strip_dock_state) # [*1] self.central_workspace.restoreWorkspaceWindows(settings.saved_workspace_windows) self.central_workspace.switchWindowedView(settings.saved_workspace_windowed_view) # keep this after restoring windows! self.subsecond_ticker = Ticker(signals.fastClockTick.emit, parent=self) self.subminute_ticker = Ticker(signals.slowClockTick.emit, parent=self) self.subsecond_ticker.start_stopOnZero(subsecond_tick_interval) self.subminute_ticker.start_stopOnZero(subminute_tick_interval) self.towerView_cheat_menu.setEnabled(False) self.solo_cheat_menu.setEnabled(False) self.updateClock() self.updateWeatherIfPrimary(settings.primary_METAR_station, None) self.updateStripFplActions() self.last_RDF_qdm = None self.updateRDF() self.updatePTT(0, False) # Disable some base airport stuff if doing CTR if env.airport_data == None: self.towerView_view_action.setEnabled(False) self.runwaysInUse_options_action.setEnabled(False) self.runwayOccupationWarnings_options_action.setEnabled(False) # Finish self.atcTextChat_pane.switchAtcChatFilter(None) # Show GUI on general chat room at start if speech_recognition_available: prepare_SR_language_files()