source: src/mlx/gui/common.py@ 554:b585c74956cb

Last change on this file since 554:b585c74956cb was 554:b585c74956cb, checked in by István Váradi <ivaradi@…>, 10 years ago

The cruise level is initialized to 0 so that the Next button is disabled unless a valid value is entered (re #223)

File size: 11.3 KB
RevLine 
[28]1
[105]2import mlx.const as _const
[175]3from mlx.i18n import xstr
[105]4
[373]5from mlx.util import secondaryInstallation
6
[28]7import os
8
[300]9#-----------------------------------------------------------------------------
10
11## @package mlx.gui.common
12#
13# Common definitions and utilities for the GUI
14#
15# The main purpose of this module is to provide common definitions for things
16# that are named differently in Gtk+ 2 and 3. This way the other parts of the
[474]17# GUI have to check the version in use very rarely. The variable \c pygobject
[300]18# tells which version is being used. If it is \c True, Gtk+ 3 is used via the
19# PyGObject interface. Otherwise Gtk+ 2 is used, which is the default on
20# Windows or when the \c FORCE_PYGTK environment variable is set.
21#
[302]22# Besides this there are some common utility classes and functions.
[300]23
24#-----------------------------------------------------------------------------
25
[28]26appIndicator = False
27
28if os.name=="nt" or "FORCE_PYGTK" in os.environ:
29 print "Using PyGTK"
30 pygobject = False
31 import pygtk
[29]32 import gtk.gdk as gdk
[28]33 import gtk
34 import gobject
[44]35 import pango
[28]36 try:
37 import appindicator
38 appIndicator = True
39 except Exception, e:
40 pass
[42]41
42 MESSAGETYPE_ERROR = gtk.MESSAGE_ERROR
[76]43 MESSAGETYPE_QUESTION = gtk.MESSAGE_QUESTION
[97]44 MESSAGETYPE_INFO = gtk.MESSAGE_INFO
[175]45
[124]46 RESPONSETYPE_OK = gtk.RESPONSE_OK
[76]47 RESPONSETYPE_YES = gtk.RESPONSE_YES
[124]48 RESPONSETYPE_NO = gtk.RESPONSE_NO
[123]49 RESPONSETYPE_ACCEPT = gtk.RESPONSE_ACCEPT
50 RESPONSETYPE_REJECT = gtk.RESPONSE_REJECT
[149]51 RESPONSETYPE_CANCEL = gtk.RESPONSE_CANCEL
[175]52
[93]53 ACCEL_VISIBLE = gtk.ACCEL_VISIBLE
54 CONTROL_MASK = gdk.CONTROL_MASK
[123]55 DIALOG_MODAL = gtk.DIALOG_MODAL
[127]56 WRAP_WORD = gtk.WRAP_WORD
[132]57 JUSTIFY_CENTER = gtk.JUSTIFY_CENTER
[97]58
[144]59 CONTROL_MASK = gdk.CONTROL_MASK
60 SHIFT_MASK = gdk.SHIFT_MASK
61 BUTTON1_MASK = gdk.BUTTON1_MASK
62
63 SCROLL_UP = gdk.SCROLL_UP
64 SCROLL_DOWN = gdk.SCROLL_DOWN
65
66 SPIN_USER_DEFINED = gtk.SPIN_USER_DEFINED
67
[149]68 FILE_CHOOSER_ACTION_SELECT_FOLDER = gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER
[151]69 FILE_CHOOSER_ACTION_OPEN = gtk.FILE_CHOOSER_ACTION_OPEN
70 FILE_CHOOSER_ACTION_SAVE = gtk.FILE_CHOOSER_ACTION_SAVE
[149]71
[175]72 SELECTION_MULTIPLE = gtk.SELECTION_MULTIPLE
73
[220]74 SHADOW_IN = gtk.SHADOW_IN
[433]75 SHADOW_NONE = gtk.SHADOW_NONE
[220]76
77 POLICY_AUTOMATIC = gtk.POLICY_AUTOMATIC
78
[362]79 WEIGHT_NORMAL = pango.WEIGHT_NORMAL
[226]80 WEIGHT_BOLD = pango.WEIGHT_BOLD
81
[246]82 WINDOW_STATE_ICONIFIED = gdk.WINDOW_STATE_ICONIFIED
83 WINDOW_STATE_WITHDRAWN = gdk.WINDOW_STATE_WITHDRAWN
84
[264]85 SORT_ASCENDING = gtk.SORT_ASCENDING
86 SORT_DESCENDING = gtk.SORT_DESCENDING
87
[277]88 EVENT_BUTTON_PRESS = gdk.BUTTON_PRESS
89
[433]90 TREE_VIEW_COLUMN_FIXED = gtk.TREE_VIEW_COLUMN_FIXED
91
[438]92 FILL = gtk.FILL
93 EXPAND = gtk.EXPAND
94
[554]95 UPDATE_IF_VALID = gtk.UPDATE_IF_VALID
96
[227]97 pixbuf_new_from_file = gdk.pixbuf_new_from_file
98
[97]99 def text2unicode(text):
100 """Convert the given text, returned by a Gtk widget, to Unicode."""
101 return unicode(text)
[276]102
103 def text2str(text):
104 """Convert the given text, returned by xstr to a string."""
105 return str(text)
[401]106
[28]107else:
108 print "Using PyGObject"
109 pygobject = True
[29]110 from gi.repository import Gdk as gdk
[227]111 from gi.repository import GdkPixbuf as gdkPixbuf
[28]112 from gi.repository import Gtk as gtk
113 from gi.repository import GObject as gobject
114 from gi.repository import AppIndicator3 as appindicator
[44]115 from gi.repository import Pango as pango
[28]116 appIndicator = True
[401]117
[42]118 MESSAGETYPE_ERROR = gtk.MessageType.ERROR
[76]119 MESSAGETYPE_QUESTION = gtk.MessageType.QUESTION
[97]120 MESSAGETYPE_INFO = gtk.MessageType.INFO
[124]121 RESPONSETYPE_OK = gtk.ResponseType.OK
[76]122 RESPONSETYPE_YES = gtk.ResponseType.YES
[124]123 RESPONSETYPE_NO = gtk.ResponseType.NO
[123]124 RESPONSETYPE_ACCEPT = gtk.ResponseType.ACCEPT
125 RESPONSETYPE_REJECT = gtk.ResponseType.REJECT
[149]126 RESPONSETYPE_CANCEL = gtk.ResponseType.CANCEL
[93]127 ACCEL_VISIBLE = gtk.AccelFlags.VISIBLE
128 CONTROL_MASK = gdk.ModifierType.CONTROL_MASK
[123]129 DIALOG_MODAL = gtk.DialogFlags.MODAL
[127]130 WRAP_WORD = gtk.WrapMode.WORD
[132]131 JUSTIFY_CENTER = gtk.Justification.CENTER
[42]132
[144]133 CONTROL_MASK = gdk.ModifierType.CONTROL_MASK
134 SHIFT_MASK = gdk.ModifierType.SHIFT_MASK
135 BUTTON1_MASK = gdk.ModifierType.BUTTON1_MASK
136
137 SCROLL_UP = gdk.ScrollDirection.UP
138 SCROLL_DOWN = gdk.ScrollDirection.DOWN
139
140 SPIN_USER_DEFINED = gtk.SpinType.USER_DEFINED
141
[149]142 FILE_CHOOSER_ACTION_SELECT_FOLDER = gtk.FileChooserAction.SELECT_FOLDER
[151]143 FILE_CHOOSER_ACTION_OPEN = gtk.FileChooserAction.OPEN
144 FILE_CHOOSER_ACTION_SAVE = gtk.FileChooserAction.SAVE
[149]145
[175]146 SELECTION_MULTIPLE = gtk.SelectionMode.MULTIPLE
147
[220]148 SHADOW_IN = gtk.ShadowType.IN
[433]149 SHADOW_NONE = gtk.ShadowType.NONE
[220]150
151 POLICY_AUTOMATIC = gtk.PolicyType.AUTOMATIC
152
[362]153 WEIGHT_NORMAL = pango.Weight.NORMAL
[226]154 WEIGHT_BOLD = pango.Weight.BOLD
155
[246]156 WINDOW_STATE_ICONIFIED = gdk.WindowState.ICONIFIED
157 WINDOW_STATE_WITHDRAWN = gdk.WindowState.WITHDRAWN
158
[264]159 SORT_ASCENDING = gtk.SortType.ASCENDING
160 SORT_DESCENDING = gtk.SortType.DESCENDING
161
[277]162 EVENT_BUTTON_PRESS = gdk.EventType.BUTTON_PRESS
163
[433]164 TREE_VIEW_COLUMN_FIXED = gtk.TreeViewColumnSizing.FIXED
165
[438]166 FILL = gtk.AttachOptions.FILL
167 EXPAND = gtk.AttachOptions.EXPAND
168
[554]169 UPDATE_IF_VALID = gtk.SpinButtonUpdatePolicy.IF_VALID
170
[227]171 pixbuf_new_from_file = gdkPixbuf.Pixbuf.new_from_file
172
[97]173 import codecs
174 _utf8Decoder = codecs.getdecoder("utf-8")
[401]175
[97]176 def text2unicode(str):
177 """Convert the given text, returned by a Gtk widget, to Unicode."""
178 return _utf8Decoder(str)[0]
179
[276]180 def text2str(text):
181 """Convert the given text, returned by xstr to a string."""
182 return _utf8Decoder(text)[0]
183
[28]184import cairo
185
[32]186#------------------------------------------------------------------------------
187
188class FlightStatusHandler(object):
189 """Base class for objects that handle the flight status in some way."""
190 def __init__(self):
191 self._stage = None
192 self._rating = 100
193 self._noGoReason = None
194
195 def resetFlightStatus(self):
196 """Reset the flight status."""
197 self._stage = None
198 self._rating = 100
199 self._noGoReason = None
200 self._updateFlightStatus()
[401]201
[32]202 def setStage(self, stage):
203 """Set the stage of the flight."""
204 if stage!=self._stage:
205 self._stage = stage
206 self._updateFlightStatus()
207
208 def setRating(self, rating):
209 """Set the rating to the given value."""
210 if rating!=self._rating:
211 self._rating = rating
212 if self._noGoReason is None:
213 self._updateFlightStatus()
214
215 def setNoGo(self, reason):
216 """Set a No-Go condition with the given reason."""
217 if self._noGoReason is None:
218 self._noGoReason = reason
219 self._updateFlightStatus()
220
221#------------------------------------------------------------------------------
[84]222
223class IntegerEntry(gtk.Entry):
224 """An entry that allows only either an empty value, or an integer."""
225 def __init__(self, defaultValue = None):
226 """Construct the entry."""
227 gtk.Entry.__init__(self)
228
[86]229 self.set_alignment(1.0)
230
[84]231 self._defaultValue = defaultValue
232 self._currentInteger = defaultValue
233 self._selfSetting = False
234 self._set_text()
235
236 self.connect("changed", self._handle_changed)
237
238 def get_int(self):
239 """Get the integer."""
240 return self._currentInteger
241
[241]242 def reset(self):
243 """Reset the integer."""
244 self.set_int(None)
245
[84]246 def set_int(self, value):
247 """Set the integer."""
248 if value!=self._currentInteger:
249 self._currentInteger = value
250 self.emit("integer-changed", self._currentInteger)
251 self._set_text()
[401]252
[84]253 def _handle_changed(self, widget):
254 """Handle the changed signal."""
255 if self._selfSetting:
256 return
257 text = self.get_text()
258 if text=="":
259 self.set_int(self._defaultValue)
260 else:
261 try:
262 self.set_int(int(text))
263 except:
264 self._set_text()
265
266 def _set_text(self):
267 """Set the text value from the current integer."""
268 self._selfSetting = True
269 self.set_text("" if self._currentInteger is None
270 else str(self._currentInteger))
271 self._selfSetting = False
[401]272
[84]273#------------------------------------------------------------------------------
274
275gobject.signal_new("integer-changed", IntegerEntry, gobject.SIGNAL_RUN_FIRST,
276 None, (object,))
277
278#------------------------------------------------------------------------------
[105]279
[227]280PROGRAM_NAME = "MAVA Logger X"
281
[232]282WINDOW_TITLE_BASE = PROGRAM_NAME + " " + _const.VERSION
[373]283if secondaryInstallation:
284 WINDOW_TITLE_BASE += " (" + xstr("secondary") + ")"
[105]285
286#------------------------------------------------------------------------------
[175]287
288# A mapping of aircraft types to their screen names
[191]289aircraftNames = { _const.AIRCRAFT_B736 : xstr("aircraft_b736"),
290 _const.AIRCRAFT_B737 : xstr("aircraft_b737"),
291 _const.AIRCRAFT_B738 : xstr("aircraft_b738"),
292 _const.AIRCRAFT_B738C : xstr("aircraft_b738c"),
293 _const.AIRCRAFT_B733 : xstr("aircraft_b733"),
294 _const.AIRCRAFT_B734 : xstr("aircraft_b734"),
295 _const.AIRCRAFT_B735 : xstr("aircraft_b735"),
296 _const.AIRCRAFT_DH8D : xstr("aircraft_dh8d"),
297 _const.AIRCRAFT_B762 : xstr("aircraft_b762"),
298 _const.AIRCRAFT_B763 : xstr("aircraft_b763"),
299 _const.AIRCRAFT_CRJ2 : xstr("aircraft_crj2"),
300 _const.AIRCRAFT_F70 : xstr("aircraft_f70"),
301 _const.AIRCRAFT_DC3 : xstr("aircraft_dc3"),
302 _const.AIRCRAFT_T134 : xstr("aircraft_t134"),
303 _const.AIRCRAFT_T154 : xstr("aircraft_t154"),
[443]304 _const.AIRCRAFT_YK40 : xstr("aircraft_yk40"),
305 _const.AIRCRAFT_B462 : xstr("aircraft_b462") }
[175]306
307#------------------------------------------------------------------------------
[221]308
[226]309def formatFlightLogLine(timeStr, line):
[221]310 """Format the given flight log line."""
311 """Format the given line for flight logging."""
312 if timeStr is not None:
313 line = timeStr + ": " + line
314 return line + "\n"
315
316#------------------------------------------------------------------------------
[226]317
318def addFaultTag(buffer):
319 """Add a tag named 'fault' to the given buffer."""
[362]320 buffer.create_tag("fault", foreground="red", weight=WEIGHT_BOLD)
[226]321
322#------------------------------------------------------------------------------
323
324def appendTextBuffer(buffer, text, isFault = False):
325 """Append the given line at the end of the given text buffer.
326
327 If isFault is set, use the tag named 'fault'."""
[345]328 insertTextBuffer(buffer, buffer.get_end_iter(), text, isFault)
[226]329
330#------------------------------------------------------------------------------
[345]331
332def insertTextBuffer(buffer, iter, text, isFault = False):
333 """Insert the given line into the given text buffer at the given iterator.
334
[362]335 If isFault is set, use the tag named 'fault' else use the tag named
336 'normal'."""
337 line = iter.get_line()
338
339 buffer.insert(iter, text)
340
341 iter0 = buffer.get_iter_at_line(line)
342 iter1 = buffer.get_iter_at_line(line+1)
[345]343 if isFault:
[362]344 buffer.apply_tag_by_name("fault", iter0, iter1)
[345]345 else:
[362]346 buffer.remove_all_tags(iter0, iter1)
[345]347
348#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.