source: src/mlx/gui/prefs.py@ 1041:f66573decc5e

python3
Last change on this file since 1041:f66573decc5e was 999:e096a5638b87, checked in by István Váradi <ivaradi@…>, 5 years ago

Removed Gtk 2/3 constant definitions (re #347)

File size: 35.8 KB
Line 
1
2from .common import *
3
4from mlx.i18n import xstr
5import mlx.const as const
6import mlx.config as config
7
8import urllib.parse
9
10#------------------------------------------------------------------------------
11
12## @package mlx.gui.prefs
13#
14# The preferences dialog.
15#
16# This module implements the preferences dialog, allowing the editing of the
17# configuration of the program. The preferences are grouped into tabs, each
18# containing the necessary controls to set the various options.
19
20#------------------------------------------------------------------------------
21
22class Hotkey(Gtk.HBox):
23 """A widget to handle a hotkey."""
24
25 # Constant to denote that the status of the Ctrl modifier is changed
26 CHANGED_CTRL = 1
27
28 # Constant to denote that the status of the Shift modifier is changed
29 CHANGED_SHIFT = 2
30
31 # Constant to denote that the value of the key is changed
32 CHANGED_KEY = 3
33
34 def __init__(self, labelText, tooltips):
35 """Construct the hotkey widget.
36
37 labelText is the text for the label before the hotkey.
38
39 The tooltips parameter is an array of the tooltips for:
40 - the hotkey combo box,
41 - the control check box, and
42 - the shift check box."""
43 super(Hotkey, self).__init__()
44
45 label = Gtk.Label(labelText)
46 label.set_use_underline(True)
47 labelAlignment = Gtk.Alignment(xalign = 0.0, yalign = 0.5,
48 xscale = 0.0, yscale = 0.0)
49 labelAlignment.set_padding(padding_top = 0, padding_bottom = 0,
50 padding_left = 0, padding_right = 4)
51 labelAlignment.add(label)
52 self.pack_start(labelAlignment, False, False, 0)
53
54 self._ctrl = Gtk.CheckButton("Ctrl")
55 self._ctrl.set_tooltip_text(tooltips[1])
56 self._ctrl.connect("toggled", self._ctrlToggled)
57 self.pack_start(self._ctrl, False, False, 4)
58
59 self._shift = Gtk.CheckButton("Shift")
60 self._shift.set_tooltip_text(tooltips[2])
61 self._shift.connect("toggled", self._shiftToggled)
62 self.pack_start(self._shift, False, False, 4)
63
64 self._hotkeyModel = Gtk.ListStore(str)
65 for keyCode in list(range(ord("0"), ord("9")+1)) + list(range(ord("A"), ord("Z")+1)):
66 self._hotkeyModel.append([chr(keyCode)])
67
68 self._hotkey = Gtk.ComboBox(model = self._hotkeyModel)
69 cell = Gtk.CellRendererText()
70 self._hotkey.pack_start(cell, True)
71 self._hotkey.add_attribute(cell, 'text', 0)
72 self._hotkey.set_tooltip_text(tooltips[0])
73 self._hotkey.connect("changed", self._keyChanged)
74 self.pack_start(self._hotkey, False, False, 4)
75
76 label.set_mnemonic_widget(self._hotkey)
77
78 self._setting = False
79
80 @property
81 def ctrl(self):
82 """Get whether the Ctrl modifier is selected."""
83 return self._ctrl.get_active()
84
85 @ctrl.setter
86 def ctrl(self, ctrl):
87 """Get whether the Ctrl modifier is selected."""
88 self._setting = True
89 self._ctrl.set_active(ctrl)
90 self._setting = False
91
92 @property
93 def shift(self):
94 """Get whether the Shift modifier is selected."""
95 return self._shift.get_active()
96
97 @shift.setter
98 def shift(self, shift):
99 """Get whether the Shift modifier is selected."""
100 self._setting = True
101 self._shift.set_active(shift)
102 self._setting = False
103
104 @property
105 def key(self):
106 """Get the value of the key."""
107 return self._hotkeyModel.get_value(self._hotkey.get_active_iter(), 0)
108
109 @key.setter
110 def key(self, key):
111 """Set the value of the key."""
112 self._setting = True
113
114 hotkeyModel = self._hotkeyModel
115 iter = hotkeyModel.get_iter_first()
116 while iter is not None and \
117 hotkeyModel.get_value(iter, 0)!=key:
118 iter = hotkeyModel.iter_next(iter)
119
120 if iter is None:
121 iter = hotkeyModel.get_iter_first()
122
123 self._hotkey.set_active_iter(iter)
124
125 self._setting = False
126
127 def set(self, hotkey):
128 """Set the hotkey widget from the given hotkey."""
129 self.ctrl = hotkey.ctrl
130 self.shift = hotkey.shift
131 self.key = hotkey.key
132
133 def get(self):
134 """Get a hotkey corresponding to the settings in the widghet."""
135
136 key = self._hotkeyModel.get_value(self._hotkey.get_active_iter(), 0)
137
138 return config.Hotkey(ctrl = self.ctrl, shift = self.shift,
139 key = self.key)
140
141 def _ctrlToggled(self, checkButton):
142 """Called when the status of the Ctrl modifier has changed."""
143 if not self._setting:
144 self.emit("hotkey-changed", Hotkey.CHANGED_CTRL)
145
146 def _shiftToggled(self, checkButton):
147 """Called when the status of the Shift modifier has changed."""
148 if not self._setting:
149 self.emit("hotkey-changed", Hotkey.CHANGED_SHIFT)
150
151 def _keyChanged(self, comboBox):
152 """Called when the value of the key has changed."""
153 if not self._setting:
154 self.emit("hotkey-changed", Hotkey.CHANGED_KEY)
155
156 def __eq__(self, other):
157 """Determine if the two hotkeys are equal."""
158 return self.ctrl==other.ctrl and self.shift==other.shift and \
159 self.key==other.key
160
161#------------------------------------------------------------------------------
162
163GObject.signal_new("hotkey-changed", Hotkey, GObject.SIGNAL_RUN_FIRST,
164 None, (int,))
165
166#------------------------------------------------------------------------------
167
168class Preferences(Gtk.Dialog):
169 """The preferences dialog."""
170 def __init__(self, gui):
171 """Construct the dialog."""
172 super(Preferences, self).__init__(WINDOW_TITLE_BASE + " " +
173 xstr("prefs_title"),
174 gui.mainWindow,
175 Gtk.DialogFlags.MODAL)
176
177 self.add_button(xstr("button_cancel"), Gtk.ResponseType.REJECT)
178 self.add_button(xstr("button_ok"), Gtk.ResponseType.ACCEPT)
179 self.set_resizable(False)
180
181 self._gui = gui
182 self._settingFromConfig = False
183
184 contentArea = self.get_content_area()
185
186 notebook = Gtk.Notebook()
187 contentArea.pack_start(notebook, True, True, 4)
188
189 general = self._buildGeneral()
190 label = Gtk.Label(xstr("prefs_tab_general"))
191 label.set_use_underline(True)
192 label.set_tooltip_text(xstr("prefs_tab_general_tooltip"))
193 notebook.append_page(general, label)
194
195 messages = self._buildMessages()
196 label = Gtk.Label(xstr("prefs_tab_messages"))
197 label.set_use_underline(True)
198 label.set_tooltip_text(xstr("prefs_tab_message_tooltip"))
199 notebook.append_page(messages, label)
200
201 sounds = self._buildSounds()
202 label = Gtk.Label(xstr("prefs_tab_sounds"))
203 label.set_use_underline(True)
204 label.set_tooltip_text(xstr("prefs_tab_sounds_tooltip"))
205 notebook.append_page(sounds, label)
206
207 advanced = self._buildAdvanced()
208 label = Gtk.Label(xstr("prefs_tab_advanced"))
209 label.set_use_underline(True)
210 label.set_tooltip_text(xstr("prefs_tab_advanced_tooltip"))
211 notebook.append_page(advanced, label)
212
213 def run(self, config):
214 """Run the preferences dialog.
215
216 The dialog will be set up from data in the given configuration. If the
217 changes are accepted by the user, the configuration is updated and saved."""
218 self._fromConfig(config)
219
220 self.show_all()
221 response = super(Preferences, self).run()
222 self.hide()
223
224 if response==Gtk.ResponseType.ACCEPT:
225 self._toConfig(config)
226 config.save()
227
228 def _fromConfig(self, config):
229 """Setup the dialog from the given configuration."""
230 self._settingFromConfig = True
231
232 self._setLanguage(config.language)
233 self._hideMinimizedWindow.set_active(config.hideMinimizedWindow)
234 self._quitOnClose.set_active(config.quitOnClose)
235 self._onlineGateSystem.set_active(config.onlineGateSystem)
236 self._onlineACARS.set_active(config.onlineACARS)
237 self._flareTimeFromFS.set_active(config.flareTimeFromFS)
238 self._syncFSTime.set_active(config.syncFSTime)
239 self._usingFS2Crew.set_active(config.usingFS2Crew)
240
241 self._setSmoothing(self._iasSmoothingEnabled, self._iasSmoothingLength,
242 config.iasSmoothingLength)
243 self._setSmoothing(self._vsSmoothingEnabled, self._vsSmoothingLength,
244 config.vsSmoothingLength)
245
246 self._useSimBrief.set_active(config.useSimBrief)
247
248 pirepDirectory = config.pirepDirectory
249 self._pirepDirectory.set_text("" if pirepDirectory is None
250 else pirepDirectory)
251 self._pirepAutoSave.set_active(config.pirepAutoSave)
252 if not pirepDirectory:
253 self._pirepAutoSave.set_sensitive(False)
254
255 for messageType in const.messageTypes:
256 level = config.getMessageTypeLevel(messageType)
257 button = self._msgFSCheckButtons[messageType]
258 button.set_active(level == const.MESSAGELEVEL_FS or
259 level == const.MESSAGELEVEL_BOTH)
260 button = self._msgSoundCheckButtons[messageType]
261 button.set_active(level == const.MESSAGELEVEL_SOUND or
262 level == const.MESSAGELEVEL_BOTH)
263
264 self._enableSounds.set_active(config.enableSounds)
265 self._pilotControlsSounds.set_active(config.pilotControlsSounds)
266 self._pilotHotkey.set(config.pilotHotkey)
267 self._enableApproachCallouts.set_active(config.enableApproachCallouts)
268 self._speedbrakeAtTD.set_active(config.speedbrakeAtTD)
269
270 self._enableChecklists.set_active(config.enableChecklists)
271 self._checklistHotkey.set(config.checklistHotkey)
272
273 self._autoUpdate.set_active(config.autoUpdate)
274 if not config.autoUpdate:
275 self._warnedAutoUpdate = True
276
277 self._updateURL.set_text(config.updateURL)
278
279 self._useRPC.set_active(config.useRPC)
280
281 self._settingFromConfig = False
282
283 def _toConfig(self, config):
284 """Setup the given config from the settings in the dialog."""
285 config.language = self._getLanguage()
286 config.hideMinimizedWindow = self._hideMinimizedWindow.get_active()
287 config.quitOnClose = self._quitOnClose.get_active()
288 config.onlineGateSystem = self._onlineGateSystem.get_active()
289 config.onlineACARS = self._onlineACARS.get_active()
290 config.flareTimeFromFS = self._flareTimeFromFS.get_active()
291 config.syncFSTime = self._syncFSTime.get_active()
292 config.usingFS2Crew = self._usingFS2Crew.get_active()
293 config.iasSmoothingLength = self._getSmoothing(self._iasSmoothingEnabled,
294 self._iasSmoothingLength)
295 config.vsSmoothingLength = self._getSmoothing(self._vsSmoothingEnabled,
296 self._vsSmoothingLength)
297 config.useSimBrief = self._useSimBrief.get_active()
298 config.pirepDirectory = self._pirepDirectory.get_text()
299 config.pirepAutoSave = self._pirepAutoSave.get_active()
300
301 for messageType in const.messageTypes:
302 fsButtonActive = self._msgFSCheckButtons[messageType].get_active()
303 soundButtonActive = self._msgSoundCheckButtons[messageType].get_active()
304 if fsButtonActive:
305 level = const.MESSAGELEVEL_BOTH if soundButtonActive \
306 else const.MESSAGELEVEL_FS
307 elif soundButtonActive:
308 level = const.MESSAGELEVEL_SOUND
309 else:
310 level = const.MESSAGELEVEL_NONE
311 config.setMessageTypeLevel(messageType, level)
312
313 config.enableSounds = self._enableSounds.get_active()
314 config.pilotControlsSounds = self._pilotControlsSounds.get_active()
315 config.pilotHotkey = self._pilotHotkey.get()
316 config.enableApproachCallouts = self._enableApproachCallouts.get_active()
317 config.speedbrakeAtTD = self._speedbrakeAtTD.get_active()
318
319 config.enableChecklists = self._enableChecklists.get_active()
320 config.checklistHotkey = self._checklistHotkey.get()
321
322 config.autoUpdate = self._autoUpdate.get_active()
323 config.updateURL = self._updateURL.get_text()
324 config.useRPC = self._useRPC.get_active()
325
326 def _buildGeneral(self):
327 """Build the page for the general settings."""
328 mainAlignment = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
329 xscale = 1.0, yscale = 0.0)
330 mainAlignment.set_padding(padding_top = 0, padding_bottom = 8,
331 padding_left = 4, padding_right = 4)
332 mainBox = Gtk.VBox()
333 mainAlignment.add(mainBox)
334
335 guiBox = self._createFrame(mainBox, xstr("prefs_frame_gui"))
336
337 languageBox = Gtk.HBox()
338 guiBox.pack_start(languageBox, False, False, 4)
339
340 label = Gtk.Label(xstr("prefs_language"))
341 label.set_use_underline(True)
342
343 languageBox.pack_start(label, False, False, 4)
344
345 self._languageList = Gtk.ListStore(str, str)
346 for language in const.languages:
347 self._languageList.append([xstr("prefs_lang_" + language),
348 language])
349
350 self._languageComboBox = languageComboBox = \
351 Gtk.ComboBox(model = self._languageList)
352 cell = Gtk.CellRendererText()
353 languageComboBox.pack_start(cell, True)
354 languageComboBox.add_attribute(cell, 'text', 0)
355 languageComboBox.set_tooltip_text(xstr("prefs_language_tooltip"))
356 languageComboBox.connect("changed", self._languageChanged)
357 languageBox.pack_start(languageComboBox, False, False, 4)
358
359 label.set_mnemonic_widget(languageComboBox)
360
361 self._changingLanguage = False
362 self._warnedRestartNeeded = False
363
364 self._hideMinimizedWindow = Gtk.CheckButton(xstr("prefs_hideMinimizedWindow"))
365 self._hideMinimizedWindow.set_use_underline(True)
366 self._hideMinimizedWindow.set_tooltip_text(xstr("prefs_hideMinimizedWindow_tooltip"))
367 guiBox.pack_start(self._hideMinimizedWindow, False, False, 4)
368
369 self._quitOnClose = Gtk.CheckButton(xstr("prefs_quitOnClose"))
370 self._quitOnClose.set_use_underline(True)
371 self._quitOnClose.set_tooltip_text(xstr("prefs_quitOnClose_tooltip"))
372 guiBox.pack_start(self._quitOnClose, False, False, 4)
373
374 onlineBox = self._createFrame(mainBox, xstr("prefs_frame_online"))
375
376 self._onlineGateSystem = Gtk.CheckButton(xstr("prefs_onlineGateSystem"))
377 self._onlineGateSystem.set_use_underline(True)
378 self._onlineGateSystem.set_tooltip_text(xstr("prefs_onlineGateSystem_tooltip"))
379 onlineBox.pack_start(self._onlineGateSystem, False, False, 4)
380
381 self._onlineACARS = Gtk.CheckButton(xstr("prefs_onlineACARS"))
382 self._onlineACARS.set_use_underline(True)
383 self._onlineACARS.set_tooltip_text(xstr("prefs_onlineACARS_tooltip"))
384 onlineBox.pack_start(self._onlineACARS, False, False, 4)
385
386 simulatorBox = self._createFrame(mainBox, xstr("prefs_frame_simulator"))
387
388 self._flareTimeFromFS = Gtk.CheckButton(xstr("prefs_flaretimeFromFS"))
389 self._flareTimeFromFS.set_use_underline(True)
390 self._flareTimeFromFS.set_tooltip_text(xstr("prefs_flaretimeFromFS_tooltip"))
391 simulatorBox.pack_start(self._flareTimeFromFS, False, False, 4)
392
393 self._syncFSTime = Gtk.CheckButton(xstr("prefs_syncFSTime"))
394 self._syncFSTime.set_use_underline(True)
395 self._syncFSTime.set_tooltip_text(xstr("prefs_syncFSTime_tooltip"))
396 simulatorBox.pack_start(self._syncFSTime, False, False, 4)
397
398 self._usingFS2Crew = Gtk.CheckButton(xstr("prefs_usingFS2Crew"))
399 self._usingFS2Crew.set_use_underline(True)
400 self._usingFS2Crew.set_tooltip_text(xstr("prefs_usingFS2Crew_tooltip"))
401 simulatorBox.pack_start(self._usingFS2Crew, False, False, 4)
402
403 (iasSmoothingBox, self._iasSmoothingEnabled,
404 self._iasSmoothingLength) = \
405 self._createSmoothingBox(xstr("prefs_iasSmoothingEnabled"),
406 xstr("prefs_iasSmoothingEnabledTooltip"))
407 simulatorBox.pack_start(iasSmoothingBox, False, False, 4)
408
409 (vsSmoothingBox, self._vsSmoothingEnabled,
410 self._vsSmoothingLength) = \
411 self._createSmoothingBox(xstr("prefs_vsSmoothingEnabled"),
412 xstr("prefs_vsSmoothingEnabledTooltip"))
413 simulatorBox.pack_start(vsSmoothingBox, False, False, 4)
414
415 self._useSimBrief = Gtk.CheckButton(xstr("prefs_useSimBrief"))
416 self._useSimBrief.set_use_underline(True)
417 self._useSimBrief.set_tooltip_text(xstr("prefs_useSimBrief_tooltip"))
418 mainBox.pack_start(self._useSimBrief, False, False, 0)
419
420 pirepBox = Gtk.HBox()
421 mainBox.pack_start(pirepBox, False, False, 8)
422
423 label = Gtk.Label(xstr("prefs_pirepDirectory"))
424 label.set_use_underline(True)
425 pirepBox.pack_start(label, False, False, 4)
426
427 self._pirepDirectory = Gtk.Entry()
428 self._pirepDirectory.set_tooltip_text(xstr("prefs_pirepDirectory_tooltip"))
429 self._pirepDirectory.connect("changed", self._pirepDirectoryChanged)
430 label.set_mnemonic_widget(self._pirepDirectory)
431 pirepBox.pack_start(self._pirepDirectory, True, True, 4)
432
433 self._pirepDirectoryButton = Gtk.Button(xstr("button_browse"))
434 self._pirepDirectoryButton.connect("clicked",
435 self._pirepDirectoryButtonClicked)
436 pirepBox.pack_start(self._pirepDirectoryButton, False, False, 4)
437
438 self._pirepAutoSave = Gtk.CheckButton(xstr("prefs_pirepAutoSave"))
439 self._pirepAutoSave.set_use_underline(True)
440 self._pirepAutoSave.set_tooltip_text(xstr("prefs_pirepAutoSave_tooltip"))
441 mainBox.pack_start(self._pirepAutoSave, False, False, 0)
442
443 return mainAlignment
444
445 def _createFrame(self, mainBox, label):
446 """Create a frame with an inner alignment and VBox.
447
448 Return the vbox."""
449 frame = Gtk.Frame(label = label)
450 mainBox.pack_start(frame, False, False, 4)
451 alignment = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
452 xscale = 1.0, yscale = 0.0)
453 alignment.set_padding(padding_top = 4, padding_bottom = 0,
454 padding_left = 0, padding_right = 0)
455 frame.add(alignment)
456 vbox = Gtk.VBox()
457 alignment.add(vbox)
458
459 return vbox
460
461 def _createSmoothingBox(self, checkBoxLabel, checkBoxTooltip,
462 maxSeconds = 10):
463 """Create a HBox that contains entry fields for smoothing some value."""
464 smoothingBox = Gtk.HBox()
465
466 smoothingEnabled = Gtk.CheckButton(checkBoxLabel)
467 smoothingEnabled.set_use_underline(True)
468 smoothingEnabled.set_tooltip_text(checkBoxTooltip)
469
470 smoothingBox.pack_start(smoothingEnabled, False, False, 0)
471
472 smoothingLength = Gtk.SpinButton()
473 smoothingLength.set_numeric(True)
474 smoothingLength.set_range(2, maxSeconds)
475 smoothingLength.set_increments(1, 1)
476 smoothingLength.set_alignment(1.0)
477 smoothingLength.set_width_chars(2)
478
479 smoothingBox.pack_start(smoothingLength, False, False, 0)
480
481 smoothingBox.pack_start(Gtk.Label(xstr("prefs_smoothing_seconds")),
482 False, False, 4)
483
484 smoothingEnabled.connect("toggled", self._smoothingToggled,
485 smoothingLength)
486 smoothingLength.set_sensitive(False)
487
488 return (smoothingBox, smoothingEnabled, smoothingLength)
489
490 def _setLanguage(self, language):
491 """Set the language to the given one."""
492 iter = self._languageList.get_iter_first()
493 while iter is not None:
494 (lang,) = self._languageList.get(iter, 1)
495 if (not language and lang=="$system") or \
496 lang==language:
497 self._changingLanguage = True
498 self._languageComboBox.set_active_iter(iter)
499 self._changingLanguage = False
500 break
501 else:
502 iter = self._languageList.iter_next(iter)
503
504 def _getLanguage(self):
505 """Get the language selected by the user."""
506 iter = self._languageComboBox.get_active_iter()
507 (lang,) = self._languageList.get(iter, 1)
508 return "" if lang=="$system" else lang
509
510 def _languageChanged(self, comboBox):
511 """Called when the language has changed."""
512 if not self._changingLanguage and not self._warnedRestartNeeded:
513 dialog = Gtk.MessageDialog(parent = self,
514 type = Gtk.MessageType.INFO,
515 message_format = xstr("prefs_restart"))
516 dialog.add_button(xstr("button_ok"), Gtk.ResponseType.OK)
517 dialog.set_title(self.get_title())
518 dialog.format_secondary_markup(xstr("prefs_language_restart_sec"))
519 dialog.run()
520 dialog.hide()
521 self._warnedRestartNeeded = True
522
523 def _smoothingToggled(self, smoothingEnabled, smoothingLength):
524 """Called when a smoothing enabled check box is toggled."""
525 sensitive = smoothingEnabled.get_active()
526 smoothingLength.set_sensitive(sensitive)
527 if sensitive:
528 smoothingLength.grab_focus()
529
530 def _setSmoothing(self, smoothingEnabled, smoothingLength, smoothing):
531 """Set the smoothing controls from the given value.
532
533 If the value is less than 2, smoothing is disabled. The smoothing
534 length is the absolute value of the value."""
535 smoothingEnabled.set_active(smoothing>=2)
536 smoothingLength.set_value(abs(smoothing))
537
538 def _getSmoothing(self, smoothingEnabled, smoothingLength):
539 """Get the smoothing value from the given controls.
540
541 The returned value is the value of smoothingLength multiplied by -1, if
542 smoothing is disabled."""
543 value = smoothingLength.get_value_as_int()
544 if not smoothingEnabled.get_active():
545 value *= -1
546 return value
547
548 def _pirepDirectoryButtonClicked(self, button):
549 """Called when the PIREP directory button is clicked."""
550 dialog = Gtk.FileChooserDialog(title = WINDOW_TITLE_BASE + " - " +
551 xstr("prefs_pirepDirectory_browser_title"),
552 action = Gtk.FileChooserAction.SELECT_FOLDER,
553 buttons = (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
554 Gtk.STOCK_OK, Gtk.ResponseType.OK),
555 parent = self)
556 dialog.set_modal(True)
557 dialog.set_transient_for(self)
558
559 directory = self._pirepDirectory.get_text()
560 if directory:
561 dialog.select_filename(directory)
562
563 result = dialog.run()
564 dialog.hide()
565
566 if result==Gtk.ResponseType.OK:
567 self._pirepDirectory.set_text(dialog.get_filename())
568
569 def _pirepDirectoryChanged(self, entry):
570 """Called when the PIREP directory is changed."""
571 if self._pirepDirectory.get_text():
572 self._pirepAutoSave.set_sensitive(True)
573 else:
574 self._pirepAutoSave.set_active(False)
575 self._pirepAutoSave.set_sensitive(False)
576
577 def _buildMessages(self):
578 """Build the page for the message settings."""
579
580 mainAlignment = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
581 xscale = 0.0, yscale = 0.0)
582 mainAlignment.set_padding(padding_top = 16, padding_bottom = 8,
583 padding_left = 4, padding_right = 4)
584 mainBox = Gtk.VBox()
585 mainAlignment.add(mainBox)
586
587 table = Gtk.Table(len(const.messageTypes) + 1, 3)
588 table.set_row_spacings(8)
589 table.set_col_spacings(32)
590 table.set_homogeneous(False)
591 mainBox.pack_start(table, False, False, 4)
592
593 label = Gtk.Label(xstr("prefs_msgs_fs"))
594 label.set_justify(Gtk.Justification.CENTER)
595 label.set_alignment(0.5, 1.0)
596 table.attach(label, 1, 2, 0, 1)
597
598 label = Gtk.Label(xstr("prefs_msgs_sound"))
599 label.set_justify(Gtk.Justification.CENTER)
600 label.set_alignment(0.5, 1.0)
601 table.attach(label, 2, 3, 0, 1)
602
603 self._msgFSCheckButtons = {}
604 self._msgSoundCheckButtons = {}
605 row = 1
606 for messageType in const.messageTypes:
607 messageTypeStr = const.messageType2string(messageType)
608 label = Gtk.Label(xstr("prefs_msgs_type_" + messageTypeStr))
609 label.set_justify(Gtk.Justification.CENTER)
610 label.set_use_underline(True)
611 label.set_alignment(0.5, 0.5)
612 table.attach(label, 0, 1, row, row+1)
613
614 fsCheckButton = Gtk.CheckButton()
615 alignment = Gtk.Alignment(xscale = 0.0, yscale = 0.0,
616 xalign = 0.5, yalign = 0.5)
617 alignment.add(fsCheckButton)
618 table.attach(alignment, 1, 2, row, row+1)
619 self._msgFSCheckButtons[messageType] = fsCheckButton
620
621 soundCheckButton = Gtk.CheckButton()
622 alignment = Gtk.Alignment(xscale = 0.0, yscale = 0.0,
623 xalign = 0.5, yalign = 0.5)
624 alignment.add(soundCheckButton)
625 table.attach(alignment, 2, 3, row, row+1)
626 self._msgSoundCheckButtons[messageType] = soundCheckButton
627
628 mnemonicWidget = Gtk.Label("")
629 table.attach(mnemonicWidget, 3, 4, row, row+1)
630 label.set_mnemonic_widget(mnemonicWidget)
631 mnemonicWidget.connect("mnemonic-activate",
632 self._msgLabelActivated,
633 messageType)
634
635 row += 1
636
637 return mainAlignment
638
639 def _msgLabelActivated(self, button, cycle_group, messageType):
640 """Called when the mnemonic of a label is activated.
641
642 It cycles the corresponding options."""
643 fsCheckButton = self._msgFSCheckButtons[messageType]
644 soundCheckButton = self._msgSoundCheckButtons[messageType]
645
646 num = 1 if fsCheckButton.get_active() else 0
647 num += 2 if soundCheckButton.get_active() else 0
648 num += 1
649
650 fsCheckButton.set_active((num&0x01)==0x01)
651 soundCheckButton.set_active((num&0x02)==0x02)
652
653 return True
654
655 def _buildSounds(self):
656 """Build the page for the sounds."""
657 mainAlignment = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
658 xscale = 1.0, yscale = 1.0)
659 mainAlignment.set_padding(padding_top = 8, padding_bottom = 8,
660 padding_left = 4, padding_right = 4)
661
662 mainBox = Gtk.VBox()
663 mainAlignment.add(mainBox)
664
665 backgroundFrame = Gtk.Frame(label = xstr("prefs_sounds_frame_bg"))
666 mainBox.pack_start(backgroundFrame, False, False, 4)
667
668 backgroundAlignment = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
669 xscale = 1.0, yscale = 0.0)
670 backgroundAlignment.set_padding(padding_top = 4, padding_bottom = 4,
671 padding_left = 4, padding_right = 4)
672 backgroundFrame.add(backgroundAlignment)
673
674 backgroundBox = Gtk.VBox()
675 backgroundAlignment.add(backgroundBox)
676
677 self._enableSounds = Gtk.CheckButton(xstr("prefs_sounds_enable"))
678 self._enableSounds.set_use_underline(True)
679 self._enableSounds.set_tooltip_text(xstr("prefs_sounds_enable_tooltip"))
680 self._enableSounds.connect("toggled", self._enableSoundsToggled)
681 alignment = Gtk.Alignment(xalign = 0.0, yalign = 0.5,
682 xscale = 1.0, yscale = 0.0)
683 alignment.add(self._enableSounds)
684 backgroundBox.pack_start(alignment, False, False, 4)
685
686 self._pilotControlsSounds = Gtk.CheckButton(xstr("prefs_sounds_pilotControls"))
687 self._pilotControlsSounds.set_use_underline(True)
688 self._pilotControlsSounds.set_tooltip_text(xstr("prefs_sounds_pilotControls_tooltip"))
689 self._pilotControlsSounds.connect("toggled", self._pilotControlsSoundsToggled)
690 backgroundBox.pack_start(self._pilotControlsSounds, False, False, 4)
691
692 self._pilotHotkey = Hotkey(xstr("prefs_sounds_pilotHotkey"),
693 [xstr("prefs_sounds_pilotHotkey_tooltip"),
694 xstr("prefs_sounds_pilotHotkeyCtrl_tooltip"),
695 xstr("prefs_sounds_pilotHotkeyShift_tooltip")])
696
697 backgroundBox.pack_start(self._pilotHotkey, False, False, 4)
698
699 self._enableApproachCallouts = Gtk.CheckButton(xstr("prefs_sounds_approachCallouts"))
700 self._enableApproachCallouts.set_use_underline(True)
701 self._enableApproachCallouts.set_tooltip_text(xstr("prefs_sounds_approachCallouts_tooltip"))
702 backgroundBox.pack_start(self._enableApproachCallouts, False, False, 4)
703
704 self._speedbrakeAtTD = Gtk.CheckButton(xstr("prefs_sounds_speedbrakeAtTD"))
705 self._speedbrakeAtTD.set_use_underline(True)
706 self._speedbrakeAtTD.set_tooltip_text(xstr("prefs_sounds_speedbrakeAtTD_tooltip"))
707 backgroundBox.pack_start(self._speedbrakeAtTD, False, False, 4)
708
709 checklistFrame = Gtk.Frame(label = xstr("prefs_sounds_frame_checklists"))
710 mainBox.pack_start(checklistFrame, False, False, 4)
711
712 checklistAlignment = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
713 xscale = 1.0, yscale = 0.0)
714 checklistAlignment.set_padding(padding_top = 4, padding_bottom = 4,
715 padding_left = 4, padding_right = 4)
716 checklistFrame.add(checklistAlignment)
717
718 checklistBox = Gtk.VBox()
719 checklistAlignment.add(checklistBox)
720
721 self._enableChecklists = Gtk.CheckButton(xstr("prefs_sounds_enableChecklists"))
722 self._enableChecklists.set_use_underline(True)
723 self._enableChecklists.set_tooltip_text(xstr("prefs_sounds_enableChecklists_tooltip"))
724 self._enableChecklists.connect("toggled", self._enableChecklistsToggled)
725 checklistBox.pack_start(self._enableChecklists, False, False, 4)
726
727 self._checklistHotkey = Hotkey(xstr("prefs_sounds_checklistHotkey"),
728 [xstr("prefs_sounds_checklistHotkey_tooltip"),
729 xstr("prefs_sounds_checklistHotkeyCtrl_tooltip"),
730 xstr("prefs_sounds_checklistHotkeyShift_tooltip")])
731
732 checklistBox.pack_start(self._checklistHotkey, False, False, 4)
733
734 self._enableSoundsToggled(self._enableSounds)
735 self._enableChecklistsToggled(self._enableChecklists)
736
737 self._pilotHotkey.connect("hotkey-changed", self._reconcileHotkeys,
738 self._checklistHotkey)
739 self._checklistHotkey.connect("hotkey-changed", self._reconcileHotkeys,
740 self._pilotHotkey)
741
742 return mainAlignment
743
744 def _enableSoundsToggled(self, button):
745 """Called when the enable sounds button is toggled."""
746 active = button.get_active()
747 self._pilotControlsSounds.set_sensitive(active)
748 self._pilotControlsSoundsToggled(self._pilotControlsSounds)
749 self._enableApproachCallouts.set_sensitive(active)
750 self._speedbrakeAtTD.set_sensitive(active)
751
752 def _pilotControlsSoundsToggled(self, button):
753 """Called when the enable sounds button is toggled."""
754 active = button.get_active() and self._enableSounds.get_active()
755 self._pilotHotkey.set_sensitive(active)
756 if active and self._checklistHotkey.get_sensitive():
757 self._reconcileHotkeys(self._checklistHotkey, Hotkey.CHANGED_SHIFT,
758 self._pilotHotkey)
759
760 def _enableChecklistsToggled(self, button):
761 """Called when the enable checklists button is toggled."""
762 active = button.get_active()
763 self._checklistHotkey.set_sensitive(active)
764 if active and self._pilotHotkey.get_sensitive():
765 self._reconcileHotkeys(self._pilotHotkey, Hotkey.CHANGED_SHIFT,
766 self._checklistHotkey)
767
768 def _reconcileHotkeys(self, changedHotkey, what, otherHotkey):
769 """Reconcile the given hotkeys so that they are different.
770
771 changedHotkey is the hotkey that has changed. what is one of the
772 Hotkey.CHANGED_XXX constants denoting what has changed. otherHotkey is
773 the other hotkey that must be reconciled.
774
775 If the other hotkey is not sensitive or is not equal to the changed
776 one, nothing happens.
777
778 Otherwise, if the status of the Ctrl modifier has changed, the status
779 of the Ctrl modifier on the other hotkey will be negated. Similarly, if
780 the Shift modifier has changed. If the key has changed, the Shift
781 modifier is negated in the other hotkey."""
782 if otherHotkey.get_sensitive() and changedHotkey==otherHotkey:
783 if what==Hotkey.CHANGED_CTRL:
784 otherHotkey.ctrl = not changedHotkey.ctrl
785 elif what==Hotkey.CHANGED_SHIFT or what==Hotkey.CHANGED_KEY:
786 otherHotkey.shift = not changedHotkey.shift
787
788 def _buildAdvanced(self):
789 """Build the page for the advanced settings."""
790
791 mainAlignment = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
792 xscale = 1.0, yscale = 0.0)
793 mainAlignment.set_padding(padding_top = 16, padding_bottom = 8,
794 padding_left = 4, padding_right = 4)
795 mainBox = Gtk.VBox()
796 mainAlignment.add(mainBox)
797
798 self._autoUpdate = Gtk.CheckButton(xstr("prefs_update_auto"))
799 mainBox.pack_start(self._autoUpdate, False, False, 4)
800
801 self._autoUpdate.set_use_underline(True)
802 self._autoUpdate.connect("toggled", self._autoUpdateToggled)
803 self._autoUpdate.set_tooltip_text(xstr("prefs_update_auto_tooltip"))
804 self._warnedAutoUpdate = False
805
806 updateURLBox = Gtk.HBox()
807 mainBox.pack_start(updateURLBox, False, False, 4)
808 label = Gtk.Label(xstr("prefs_update_url"))
809 label.set_use_underline(True)
810 updateURLBox.pack_start(label, False, False, 4)
811
812 self._updateURL = Gtk.Entry()
813 label.set_mnemonic_widget(self._updateURL)
814 self._updateURL.set_width_chars(40)
815 self._updateURL.set_tooltip_text(xstr("prefs_update_url_tooltip"))
816 self._updateURL.connect("changed", self._updateURLChanged)
817 updateURLBox.pack_start(self._updateURL, True, True, 4)
818
819 self._useRPC = Gtk.CheckButton(xstr("prefs_use_rpc"))
820 mainBox.pack_start(self._useRPC, False, False, 16)
821
822 self._useRPC.set_use_underline(True)
823 self._useRPC.set_tooltip_text(xstr("prefs_use_rpc_tooltip"))
824
825 return mainAlignment
826
827 def _setOKButtonSensitivity(self):
828 """Set the sensitive state of the OK button."""
829 sensitive = False
830 try:
831 result = urllib.parse.urlparse(self._updateURL.get_text())
832 sensitive = result.scheme!="" and (result.netloc + result.path)!=""
833 except:
834 pass
835
836 okButton = self.get_widget_for_response(Gtk.ResponseType.ACCEPT)
837 okButton.set_sensitive(sensitive)
838
839 def _autoUpdateToggled(self, button):
840 """Called when the auto update check button is toggled."""
841 if not self._settingFromConfig and not self._warnedAutoUpdate and \
842 not self._autoUpdate.get_active():
843 dialog = Gtk.MessageDialog(parent = self,
844 type = Gtk.MessageType.INFO,
845 message_format = xstr("prefs_update_auto_warning"))
846 dialog.add_button(xstr("button_ok"), Gtk.ResponseType.OK)
847 dialog.set_title(self.get_title())
848 dialog.run()
849 dialog.hide()
850 self._warnedAutoUpdate = True
851
852 def _updateURLChanged(self, entry):
853 """Called when the update URL is changed."""
854 self._setOKButtonSensitivity()
855
Note: See TracBrowser for help on using the repository browser.