1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
19 class CalculatorContext
20 var result
: nullable Float = null
22 var last_op
: nullable Char = null
24 var current
: nullable Float = null
25 var after_point
: nullable Int = null
27 fun push_op
( op
: Char )
34 last_op
= op
# store for next push_op
37 # prepare next current
42 fun push_digit
( digit
: Int )
45 if current
== null then current
= 0.0
47 var after_point
= after_point
48 if after_point
== null then
49 current
= current
* 10.0 + digit
.to_f
51 current
= current
+ digit
.to_f
* 10.0.pow
(after_point
.to_f
)
55 self.current
= current
58 fun switch_to_decimals
60 if self.current
== null then current
= 0.0
61 if after_point
!= null then return
66 fun apply_last_op_if_any
71 if result
== null then result
= 0.0
74 if current
== null then current
= 0.0
78 else if op
== '+' then
79 result
= result
+ current
80 else if op
== '-' then
81 result
= result
- current
82 else if op
== '/' then
83 result
= result
/ current
84 else if op
== '*' then
85 result
= result
* current
96 var container
: GtkGrid
98 var lbl_disp
: GtkLabel
99 var but_eq
: GtkButton
100 var but_dot
: GtkButton
102 var context
= new CalculatorContext
104 redef fun signal
( sender
, user_data
)
106 var after_point
= context
.after_point
107 if after_point
== null then
110 after_point
= (after_point
.abs
)
113 if user_data
isa Char then # is an operation
116 but_dot
.sensitive
= false
117 context
.switch_to_decimals
118 lbl_disp
.text
= "{context.current.to_i}."
120 but_dot
.sensitive
= true
123 var s
= context
.result
.to_precision_native
(6)
124 var index
: nullable Int = null
125 for i
in s
.length
.times
do
127 if chiffre
== '0' and index
== null then
129 else if chiffre
!= '0' then
133 if index
!= null then
134 s
= s
.substring
(0, index
)
135 if s
[s
.length-1
] == ',' then s
= s
.substring
(0, s
.length-1
)
139 else if user_data
isa Int then # is a number
141 context
.push_digit
( n
)
142 lbl_disp
.text
= context
.current
.to_precision_native
(after_point
)
150 win
= new GtkWindow( 0 )
152 container
= new GtkGrid(5,5,true)
155 lbl_disp
= new GtkLabel( "_" )
156 container
.attach
( lbl_disp
, 0, 0, 5, 1 )
160 var but
= new GtkButton.with_label
( n
.to_s
)
161 but
.request_size
( 64, 64 )
162 but
.signal_connect
( "clicked", self, n
)
164 container
.attach
( but
, 0, 4, 1, 1 )
165 else container
.attach
( but
, (n-1
)%3, 3-(n-1
)/3, 1, 1 )
170 for op
in ['+', '-', '*', '/' ] do
171 var but
= new GtkButton.with_label
( op
.to_s
)
172 but
.request_size
( 64, 64 )
173 but
.signal_connect
( "clicked", self, op
)
174 container
.attach
( but
, 3, r
, 1, 1 )
179 but_eq
= new GtkButton.with_label
( "=" )
180 but_eq
.request_size
( 64, 64 )
181 but_eq
.signal_connect
( "clicked", self, '=' )
182 container
.attach
( but_eq
, 4, 3, 1, 2 )
185 but_dot
= new GtkButton.with_label
( "." )
186 but_dot
.request_size
( 64, 64 )
187 but_dot
.signal_connect
( "clicked", self, '.' )
188 container
.attach
( but_dot
, 1, 4, 1, 1 )
191 var but_c
= new GtkButton.with_label
( "C" )
192 but_c
.request_size
( 64, 64 )
193 but_c
.signal_connect
("clicked", self, 'C')
194 container
.attach
( but_c
, 2, 4, 1, 1 )
201 var context
= new CalculatorContext
202 context
.push_digit
( 1 )
203 context
.push_digit
( 2 )
204 context
.push_op
( '+' )
205 context
.push_digit
( 3 )
206 context
.push_op
( '*' )
207 context
.push_digit
( 2 )
208 context
.push_op
( '=' )
209 var r
= context
.result
.to_precision
( 2 )
210 assert r
== "30.00" else print r
212 context
= new CalculatorContext
213 context
.push_digit
( 1 )
214 context
.push_digit
( 4 )
215 context
.switch_to_decimals
216 context
.push_digit
( 1 )
217 context
.push_op
( '*' )
218 context
.push_digit
( 3 )
219 context
.push_op
( '=' )
220 r
= context
.result
.to_precision
( 2 )
221 assert r
== "42.30" else print r
223 context
.push_op
( '+' )
224 context
.push_digit
( 1 )
225 context
.push_digit
( 1 )
226 context
.push_op
( '=' )
227 r
= context
.result
.to_precision
( 2 )
228 assert r
== "53.30" else print r
230 context
= new CalculatorContext
231 context
.push_digit
( 4 )
232 context
.push_digit
( 2 )
233 context
.switch_to_decimals
234 context
.push_digit
( 3 )
235 context
.push_op
( '/' )
236 context
.push_digit
( 3 )
237 context
.push_op
( '=' )
238 r
= context
.result
.to_precision
( 2 )
239 assert r
== "14.10" else print r
241 #test multiple decimals
242 context
= new CalculatorContext
243 context
.push_digit
( 5 )
244 context
.push_digit
( 0 )
245 context
.switch_to_decimals
246 context
.push_digit
( 1 )
247 context
.push_digit
( 2 )
248 context
.push_digit
( 3 )
249 context
.push_op
( '+' )
250 context
.push_digit
( 1 )
251 context
.push_op
( '=' )
252 r
= context
.result
.to_precision
( 3 )
253 assert r
== "51.123" else print r
256 context
= new CalculatorContext
257 context
.push_digit
( 1 )
258 context
.push_digit
( 0 )
259 context
.push_op
( '+' )
260 context
.push_digit
( 1 )
261 context
.push_digit
( 0 )
262 context
.push_op
( '=' )
263 context
.push_op
( 'C' )
264 r
= context
.result
.to_precision
( 1 )
265 assert r
== "0.0" else print r
267 # graphical application
269 if "NIT_TESTING".environ
!= "true" then
270 var app
= new CalculatorGui