(phixonline)-->
--
-- demo\rosetta\Morse_code.exw
-- ===========================
--
with javascript_semantics
include pGUI.e
include builtins\beep.e
Ihandle input, canvas, output, vbox, dlg
cdCanvas cddbuffer, cdcanvas
constant title = "Morse code",
help_text = """
Enter a message to convert to morse code.
Press Return to listen to the result.
Characters A-Z are shown with Baden-Powell menemonics.
(Note said are a memory aid, not perfectly readable.)
Obviously deliberately looking away and listening
would be the best way to use this as a learning aid.
"""
function show_help()
IupMessage(title,help_text,bWrap:=false)
IupSetFocus(input)
return IUP_IGNORE -- (don't open the browser help!)
end function
constant morse_data = """
!-.-.--#".-..-.#$...-..-#&.-...#'.----.#(-.--.#)-.--.-#+.-.-.#,--..--#--....-#..-.-.-#/-..-.#=-...-#
0-----#1.----#2..---#3...--#4....-#5.....#6-....#7--...#8---..#9----.#:---...#;-.-.-.#?..--..#@.--.-.#
A.-51517525#B-...7177414144444747#C-.-.7121121277271616#D-..717741414747#E.7474#F..-.7171111174247777#
G--.712177271818#H....2121717127277777#I..51515757#J.---2121222558269668#K-.-742184854428#(-.--.#
L.-..7171727677771717#M--45118155#N-.71362727#O---712182861216#P.--.8181612164247777#)-.--.-#
Q--.-8286121677775818#R.-.717144261717#S...515154545757#T-7121#U..-818111117727#V...-8181111156567727#
W.--818187534317#X-..-8154333365654518#Y-.--8163545433115558#Z--..7121762277771717#_..--.-# #"""
sequence morse = repeat(``,255), -- the eg "..."'s
bdnpwl = repeat({},255) -- Baden-Powell mnemonics
procedure setMorse()
-- I trust the characters and morse codes are all pretty evident in morse_data.
-- Baden-Powell mnemonics are encoded as 4 points on a 9wx7h grid per dot/dash,
-- counting (it just turned out that way) right to left and top to bottom, such
-- that "9711" (=1197) is(/looks like) a forwardslash and "9117" a backslash.
-- Each quite fiddly to set up - rather relieved there were only 26 of them!
sequence data = split(substitute(morse_data,"\n",""),'#')
for di in data do
integer key = di[1]
string bpm = trim_head(di[2..$],".- "),
code = di[2..-length(bpm)-1]
assert(length(bpm)=0 or length(bpm)=4*length(code))
morse[key] = code -- eg morse['S'] = "..."
bdnpwl[key] = sq_sub('5',bpm)
end for
morse['['] = morse['(']
morse[']'] = morse[')']
end procedure
setMorse()
function redraw_cb(Ihandle /*ih*/)
string text = upper(IupGetAttribute(input,"VALUE")),
outstr = ""
integer {dw,dh} = IupGetIntInt(canvas, "DRAWSIZE"),
{tw,th} = cdCanvasGetTextSize(cddbuffer,text)
while tw>dw do
if length(outstr) then outstr &= " " end if
outstr &= morse[text[1]]
text = text[2..$]
{tw,th} = cdCanvasGetTextSize(cddbuffer,text)
end while
atom cw = tw/max(length(text),1),
cx = dw/2,
cy = dh/2
cdCanvasActivate(cddbuffer)
cdCanvasSetBackground(cddbuffer, CD_LIGHT_PARCHMENT)
cdCanvasClear(cddbuffer)
cdCanvasSetForeground(cddbuffer, #BBADA0)
cdCanvasText(cddbuffer, cx, cy, text)
cx -= cw*(length(text)/2-0.5)
cdCanvasSetForeground(cddbuffer, CD_BLUE)
cdCanvasSetLineWidth(cddbuffer,3)
{} = cdCanvasMarkSize(cddbuffer,3)
atom gw = cw*0.75, gh = th*0.285
for ch in text do
sequence bpm = bdnpwl[ch]
if length(bpm) then
for k=1 to length(bpm) by 4 do
atom x1 = cx+gw*bpm[k+0]/8-1,
y1 = cy+gh*bpm[k+1]/4-3,
x2 = cx+gw*bpm[k+2]/8-1,
y2 = cy+gh*bpm[k+3]/4-3
if x1=x2 and y1=y2 then
cdCanvasMark(cddbuffer, x1, y1)
else
cdCanvasLine(cddbuffer, x1, y1, x2, y2)
end if
end for
end if
cx += cw
if length(outstr) then outstr &= " " end if
outstr &= morse[ch]
end for
cdCanvasFlush(cddbuffer)
IupSetStrAttribute(output,"TITLE",outstr)
return IUP_DEFAULT
end function
function map_cb(Ihandle ih)
cdcanvas = cdCreateCanvas(CD_IUP, ih)
cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
-- cdCanvasFont(cddbuffer,"Courier",CD_PLAIN,24)
cdCanvasFont(cddbuffer,"Courier",CD_PLAIN,48)
cdCanvasSetTextAlignment(cddbuffer, CD_CENTER)
return IUP_DEFAULT
end function
constant frequency = 1280, -- in Hz, 37..32767
wpm = 15, -- words per minute
dit = 1200/wpm, -- in milliseconds
dah = 3*dit,
lettergap = 3*dit,
wordgap = 7*dit
function key_cb(Ihandle /*dlg*/, atom c)
if c=K_ESC then return IUP_CLOSE end if -- (standard practice for me)
if c=K_F5 then return IUP_DEFAULT end if -- (let browser reload work)
if c=K_F1 then return show_help() end if
if c=K_CR then
string text = trim(upper(IupGetAttribute(input,"VALUE")))
sequence durations = {}
for ch in text do
if ch=' ' then
durations &= wordgap
else
if length(durations) then
durations &= lettergap
end if
string m = morse[ch]
for i=1 to length(m) do
if i>1 then durations &= dit end if
durations &= iff(m[i]='.'?dit:dah)
end for
end if
end for
beep(frequency,durations,0.5)
IupSetAttribute(input,"SELECTION","ALL")
elsif find(c,"#") then
beep()
return IUP_IGNORE
else
IupUpdate(canvas)
end if
return IUP_CONTINUE
end function
IupOpen()
input = IupText("EXPAND=HORIZONTAL")
canvas = IupCanvas("RASTERSIZE=520x40")
output = IupLabel("","EXPAND=HORIZONTAL")
vbox = IupVbox({input,canvas,output}, "MARGIN=10x5, GAP=5")
dlg = IupDialog(vbox,`TITLE="%s",MINSIZE=440x140`,{title})
IupSetCallback(dlg,"KEY_CB",Icallback("key_cb"))
IupSetCallbacks(canvas, {"MAP_CB", Icallback("map_cb"),
"ACTION", Icallback("redraw_cb")})
IupShow(dlg)
IupSetAttribute(canvas, "RASTERSIZE", NULL)
IupSetAttributeHandle(NULL,"PARENTDIALOG",dlg)
if platform()!=JS then
IupMainLoop()
IupClose()
end if