📄 telephone.rb
字号:
#!/usr/bin/env ruby# -*- tab-width: 4; -*-## The contents of this file are subject to the Mozilla Public# License Version 1.1 (the "License"); you may not use this file# except in compliance with the License. You may obtain a copy of# the License at http://www.mozilla.org/MPL/## Software distributed under the License is distributed on an "AS# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or# implied. See the License for the specific language governing# rights and limitations under the License.## The Original Code is State Machine Compiler (SMC).## The Initial Developer of the Original Code is Charles W. Rapp.# Portions created by Charles W. Rapp are# Copyright (C) 2000 - 2003 Charles W. Rapp.# All Rights Reserved.## Contributor(s):# Port to Ruby by Francois Perrad, francois.perrad@gadz.org## Name# telephone.rb## Description# A simulation of an old fashioned touch-tone telephone.## RCS ID# $Id: telephone.rb,v 1.1 2005/06/16 17:52:04 fperrad Exp $## CHANGE LOG# $Log: telephone.rb,v $# Revision 1.1 2005/06/16 17:52:04 fperrad# Added Ruby examples 1 - 4 and 7.##require 'time'require 'tk'require 'Telephone_sm'class Telephone LONG_DISTANCE = 1 LOCAL = 2 EMERGENCY = 3 NYC_TEMP = 4 TIME = 5 DEPOSIT_MONEY = 6 LINE_BUSY = 7 INVALID_NUMBER = 8 SEC_PER_MINUTE = 60 def initialize(root) @_root = root @_areaCode = "" @_exchange = "" @_local = "" @_display = "" @_receiverButton = nil @_timerMap = { 'ClockTimer'=> nil, 'OffHookTimer'=> nil, 'LoopTimer'=> nil, 'RingTimer'=> nil, } @_timerAudioID = nil _loadUI # Create the state machine to drive this object. @_fsm = Telephone_sm::new(self) # DEBUG #@_fsm.setDebugFlag(true) end # Create the user interface but don't display it yet. def _loadUI() @_root.title("Telephone demo") frameDisplay = TkFrame.new(@_root) frameDisplay.pack( 'side' => 'top', 'fill' => 'both' ) # Create the read-only phone number display. @_numberDisplay = TkLabel.new(frameDisplay, 'width' => 30, 'bg' => 'white', 'relief' => 'sunken', 'padx' => 5, 'pady' => 5 ) @_numberDisplay.pack( 'side' => 'top', 'padx' => 5, 'pady' => 5 ) frameHook = TkFrame.new(@_root) frameHook.pack( 'side' => 'top', 'expand' => 1 ) # Create the off-hook/on-hook button. @_receiverButton = TkButton.new(frameHook, 'text' => "Pick up receiver", 'state' => 'normal', 'command' => proc { text = @_receiverButton.cget('text') if text == "Pick up receiver" then @_fsm.OffHook elsif text == "Put down receiver" then @_fsm.OnHook else $stderr.printf("Unknown receiver (%s).\n", text) end }, 'padx' => 10, 'pady' => 5, 'bd' => 3 ) @_receiverButton.pack( 'side' => 'top', 'padx' => 5, 'pady' => 5 ) frameDial = TkFrame.new(@_root) frameDial.pack( 'side' => 'top', 'fill' => 'both', 'padx' => 5, 'pady' => 5 ) # Create the dialing buttons. i = 0 "123456789*0#".split(//).each do |digit| b = TkButton.new(frameDial, 'text' => digit, 'height' => 2, 'width' => 3, 'command' => proc { @_fsm.Digit(digit) } ) b.grid( 'row' => i/3, 'column' => i%3, 'padx' => 1, 'pady' => 1 ) i += 1 end frameStatus = TkFrame.new(@_root) frameStatus.pack( 'side' => 'top', 'fill' => 'both' ) @_soundDisplay = TkLabel.new(frameStatus, 'relief' => 'groove' ) @_soundDisplay.pack( 'side' => 'top', 'fill' => 'x', 'expand' => 1, 'anchor' => 's' ) # Cntl-C stops the demo as well. @_root.bind('Control-c') { exit } end #----------------------------------------------------------- # State Machine Actions. # # Return the current area code. def getAreaCode() return @_areaCode end # Return the exchange. def getExchange() return @_exchange end # Return the local number. def getLocal() return @_local end def routeCall(callType, areaCode, exchange, local) if callType == EMERGENCY then route = EMERGENCY elsif (callType == LONG_DISTANCE and areaCode == "1212" and exchange == "555" and local == "1234") then route = NYC_TEMP elsif exchange == "555" then if local == "1212" then route = TIME else route = LINE_BUSY end elsif callType == LOCAL then route = DEPOSIT_MONEY else route = INVALID_NUMBER end # Call routing needs to be done asynchronouzly in order to # avoid issuing a transition within a transition. Tk.after(50, proc { _callRoute(route) } ) end def startTimer(name, delay) if name == "ClockTimer" then @_timerMap[name] = TkAfter.new(delay, 1, proc { @_fsm.ClockTimer } ) elsif name == "OffHookTimer" then @_timerMap[name] = TkAfter.new(delay, 1, proc { @_fsm.OffHookTimer } ) elsif name == "LoopTimer" then @_timerMap[name] = TkAfter.new(delay, 1, proc { @_fsm.LoopTimer } ) elsif name == "RingTimer" then @_timerMap[name] = TkAfter.new(delay, 1, proc { @_fsm.RingTimer } ) end @_timerMap[name].start end def resetTimer(name) unless @_timerMap[name].nil? then @_timerMap[name].restart end end def stopTimer(name) unless @_timerMap[name].nil? then @_timerMap[name].cancel @_timerMap[name] = nil end end def play(name, delay) unless @_timerAudioID.nil? then @_timerAudioID.cancel @_timerAudioID = nil end @_soundDisplay.configure('text' => name) @_timerAudioID = TkAfter.new(delay, 1, proc { @_soundDisplay.configure('text' => "") @_timerAudioID = nil } ) @_timerAudioID.start end def playTT(name) play(name, 400) end def loop(name) unless @_timerAudioID.nil? then @_timerAudioID.cancel @_timerAudioID = nil end @_soundDisplay.configure('text' => name + " ...") end def stopLoop(name) @_soundDisplay.configure('text' => "") end def stopPlayback() unless @_timerAudioID.nil? then @_timerAudioID.cancel @_timerAudioID = nil end @_soundDisplay.configure('text' => "") end def playEmergency() play("911", 5000) end def playNYCTemp() play("NYC_temp", 2000) end def playDepositMoney() play("50_cents_please", 2000) end def playTime() play("the_time_is ???", 2000) end def playInvalidNumber() play("you_dialed ### could_not_be_completed", 2000) end def getType() return @_callType end def setType(type) @_callType = type end def saveAreaCode(n) @_areaCode += n addDisplay(n) end def saveExchange(n) @_exchange += n addDisplay(n) end def saveLocal(n) @_local += n addDisplay(n) end def addDisplay(character) @_display += character @_numberDisplay.configure('text' => @_display) end def clearDisplay() #Clear the internal data store. @_display = "" @_areaCode = "" @_local = "" @_exchange = "" # Put up the current time and date on the display. @_numberDisplay.configure('text' => "") end def startClockTimer() currentTime = Time::now.to_i timeRemaining = SEC_PER_MINUTE - (currentTime % SEC_PER_MINUTE) # Figure out how long until the top of the minute # and set the timer for that amount. startTimer("ClockTimer", timeRemaining * 1000) end def updateClock() text = Time::now.localtime.strftime("%H:%M %b %d, %Y") @_numberDisplay.configure('text' => text) end def setReceiver(text) @_receiverButton.configure('text' => text) end def _callRoute(route) if route == EMERGENCY then @_fsm.Emergency elsif route == NYC_TEMP then @_fsm.NYCTemp elsif route == TIME then @_fsm.Time elsif route == DEPOSIT_MONEY then @_fsm.DepositMoney elsif route == LINE_BUSY then @_fsm.LineBusy elsif route == INVALID_NUMBER then @_fsm.InvalidNumber end endend# Display the "telephone" user interface and run until# the user quits the window.root = TkRoot.newtel = Telephone.new(root)Tk.mainloop
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -