141a24ca84e782ccb2fd2141e39859d6e3baf73a
[munter.git] / munter / gui.py
1 # -*- coding: utf-8 -*-
2
3
4 """
5 GUI implementation
6 """
7
8 import wx
9 from . import munter
10
11 class MainFrame(wx.Frame):
12 """
13 The main wx.Frame
14 """
15
16 def __init__(self, *args, **kw):
17 super(MainFrame, self).__init__(*args, **kw)
18
19 self.SetTitle('Munter.py')
20 self.SetSize(600, 400)
21
22 self.props = dict()
23 self.props['distance'] = 0
24 self.props['elevation'] = 0
25 self.props['fitness'] = 'average'
26 self.props['units'] = 'imperial'
27 self.props['travel_mode'] = 'uphill'
28
29 self.pnl = wx.Panel(self)
30
31 st = wx.StaticText(self.pnl, label="Munter.py")
32 font = st.GetFont()
33 font.PointSize += 10
34 font = font.Bold()
35
36 st.SetFont(font)
37
38 #sizer = wx.BoxSizer(wx.VERTICAL)
39 sizer = wx.BoxSizer(wx.HORIZONTAL)
40 sizer.Add(st, wx.SizerFlags().Border(wx.TOP|wx.LEFT, 0))
41 #self.pnl.SetSizer(sizer)
42
43 # text entry fields
44 self.st_distance = wx.StaticText(self.pnl, label="Distance: ")
45 self.te_distance = wx.TextCtrl(self.pnl, value="0", size=(140, -1))
46
47 self.st_elevation = wx.StaticText(self.pnl, label="Elevation: ")
48 self.te_elevation = wx.TextCtrl(self.pnl, value="0", size=(140, -1))
49
50 self.st_fitness = wx.StaticText(self.pnl, label="Fitness: ")
51 cb_fitness_choices = ['slow', 'average', 'fast']
52 cb_fitness_default = 'average'
53 self.cb_fitness = wx.ComboBox(self.pnl, choices=cb_fitness_choices,
54 value=cb_fitness_default, style=wx.CB_READONLY)
55
56 self.st_travel_mode = wx.StaticText(self.pnl, label="Travel Mode: ")
57 cb_travel_mode_choices = ['uphill', 'flat', 'downhill', 'bushwhacking']
58 cb_travel_mode_default = 'uphill'
59 self.cb_travel_mode = wx.ComboBox(self.pnl, choices=cb_travel_mode_choices,
60 value=cb_travel_mode_default, style=wx.CB_READONLY)
61
62 self.st_units = wx.StaticText(self.pnl, label="Units: ")
63 cb_units_choices = ['imperial', 'metric']
64 cb_units_default = 'imperial'
65
66 self.cb_units = []
67 for choice in range(len(cb_units_choices)):
68 label = cb_units_choices[choice]
69 style = wx.RB_GROUP if not choice else 0
70 self.cb_units.append(wx.RadioButton(self.pnl, label=label, style=style))
71
72 # static text
73 self.st_mtc = wx.StaticText(self.pnl, label="0h",
74 style=wx.ALIGN_CENTRE_HORIZONTAL)
75
76 st_mtc_font = st.GetFont()
77 st_mtc_font.PointSize += 10
78 self.st_mtc.SetFont(st_mtc_font)
79
80 # bindings
81 self.pnl.Bind(wx.EVT_TEXT, self.update_distance, self.te_distance)
82 self.pnl.Bind(wx.EVT_TEXT, self.update_elevation, self.te_elevation)
83 self.cb_fitness.Bind(wx.EVT_COMBOBOX, self.update_fitness)
84 self.cb_travel_mode.Bind(wx.EVT_COMBOBOX, self.update_travel_mode)
85
86 for cb in self.cb_units:
87 cb.Bind(wx.EVT_RADIOBUTTON, self.update_units)
88
89 # buttons
90 b_clear = wx.Button(self.pnl, wx.NewId(), '&Clear', (-1, -1),
91 wx.DefaultSize)
92
93 # layout
94 b = 5
95 w = 100
96
97 static_line = wx.StaticLine(self.pnl, wx.NewId(), style=wx.LI_HORIZONTAL)
98
99 hsizer_distance = wx.BoxSizer(wx.HORIZONTAL)
100 hsizer_distance.Add(self.st_distance, 0, wx.RIGHT, b)
101 hsizer_distance.Add(self.te_distance, 1, wx.GROW, b)
102 hsizer_distance.SetItemMinSize(self.st_distance, (w, -1))
103
104 hsizer_elevation = wx.BoxSizer(wx.HORIZONTAL)
105 hsizer_elevation.Add(self.st_elevation, 0, wx.RIGHT, b)
106 hsizer_elevation.Add(self.te_elevation, 1, wx.GROW, b)
107 hsizer_elevation.SetItemMinSize(self.st_elevation, (w, -1))
108
109 hsizer_fitness = wx.BoxSizer(wx.HORIZONTAL)
110 hsizer_fitness.Add(self.st_fitness, 0, wx.RIGHT, b)
111 hsizer_fitness.Add(self.cb_fitness, 1, wx.GROW, b)
112 hsizer_fitness.SetItemMinSize(self.st_fitness, (w, -1))
113
114 hsizer_travel_mode = wx.BoxSizer(wx.HORIZONTAL)
115 hsizer_travel_mode.Add(self.st_travel_mode, 0, wx.RIGHT, b)
116 hsizer_travel_mode.Add(self.cb_travel_mode, 1, wx.GROW, b)
117 hsizer_travel_mode.SetItemMinSize(self.st_travel_mode, (w, -1))
118
119 hsizer_units = wx.BoxSizer(wx.HORIZONTAL)
120 hsizer_units.Add(self.st_units, 0, wx.RIGHT, b)
121 for cb in range(len(self.cb_units)):
122 hsizer_units.Add(self.cb_units[cb], cb + 1, wx.GROW, b)
123 hsizer_units.SetItemMinSize(self.st_units, (w, -1))
124
125 hsizer_mtc = wx.BoxSizer(wx.HORIZONTAL)
126 hsizer_mtc.Add(self.st_mtc, 1, wx.GROW, b)
127 hsizer_mtc.SetItemMinSize(self.st_mtc, (w, -1))
128
129 hsizer5 = wx.BoxSizer(wx.HORIZONTAL)
130 hsizer5.Add(b_clear, 0)
131
132 b = 5
133 vsizer1 = wx.BoxSizer(wx.VERTICAL)
134 vsizer1.Add(sizer, 0, wx.EXPAND | wx.ALL, b*b)
135 vsizer1.Add(hsizer_distance, 0, wx.EXPAND | wx.ALL, b)
136 vsizer1.Add(hsizer_elevation, 0, wx.EXPAND | wx.ALL, b)
137 vsizer1.Add(hsizer_fitness, 0, wx.EXPAND | wx.ALL, b)
138 vsizer1.Add(hsizer_travel_mode, 0, wx.EXPAND | wx.ALL, b)
139 vsizer1.Add(hsizer_units, 0, wx.EXPAND | wx.ALL, b)
140 vsizer1.Add(hsizer_mtc, 0, wx.EXPAND | wx.ALL, b)
141 vsizer1.Add(static_line, 0, wx.GROW | wx.ALL, b)
142 vsizer1.Add(hsizer5, 0, wx.ALIGN_RIGHT | wx.ALL, b)
143
144 self.pnl.SetSizerAndFit(vsizer1)
145 self.pnl.SetClientSize(vsizer1.GetSize())
146
147 def update_distance(self, event):
148 value = self.te_distance.GetValue()
149 if value:
150 self.props['distance'] = float(value)
151 self.update_mtc()
152
153 def update_elevation(self, event):
154 value = self.te_elevation.GetValue()
155 if value:
156 self.props['elevation'] = int(value)
157 self.update_mtc()
158
159 def update_fitness(self, event):
160 value = self.cb_fitness.GetValue()
161 if value:
162 self.props['fitness'] = value
163 self.update_mtc()
164
165 def update_travel_mode(self, event):
166 value = self.cb_travel_mode.GetValue()
167 if value:
168 self.props['travel_mode'] = value
169 self.update_mtc()
170
171 def update_units(self, event):
172 rb = event.GetEventObject()
173 value = rb.GetLabel()
174 if value:
175 self.props['units'] = value
176 self.update_mtc()
177
178 def update_mtc(self):
179 if (self.props['distance'] is None) or (self.props['elevation'] is None):
180 return
181
182 est = munter.time_calc(self.props['distance'],
183 self.props['elevation'],
184 self.props['fitness'],
185 self.props['travel_mode'],
186 self.props['units'])
187
188 hours = int(est['time'])
189 minutes = int((est['time'] - hours) * 60)
190 self.st_mtc.SetLabel("{human_time}".format(
191 human_time="{hours} hours {minutes} minutes".format(
192 hours=hours,
193 minutes=minutes)))
194
195 self.pnl.Layout()
196
197 def startup():
198 app = wx.App()
199 frm = MainFrame(None)
200 frm.Show()
201
202 app.MainLoop()