:can pascal make a menu that is the same of that of mobile phone
:the user can move the option and press enter without typing anything
Here's a simple menu demo in graphic mode with mouse support, I put together from some programs I wrote long time ago. Could have some glitches though, because I did lots of copy/paste without going through every line of code. It doesn't support nested menus, it shouldn't be too hard to implement anyhow, I let you figure it out

{ Compiler TP/BP 7 }
{$A+,B-,D-,E-,F-,G+,I-,L-,N+,O-,P-,Q-,R-,S-,T-,V-,X+}
{$M 16384,0,655360}
uses crt,graph;
var maxx,maxy:word;
gr_mode:boolean;
caption:string;
const id_text='Menu demo';
{### Mouse functions ########################################################}
const arrow_cursor:array[1..32] of word=($3fff,$1fff,$0fff,$07ff,
$03ff,$01ff,$00ff,$007f,
$003f,$001f,$000f,$00ff,
$10ff,$387f,$f87f,$fcff,{mask}
$0000,$4000,$6000,$7000,
$7800,$7c00,$7e00,$7f00,
$7f80,$7fc0,$7c00,$6600,
$4600,$0300,$0300,$0000);{cursor}
function mousereset_:word;assembler; { returns: 0021h - Ok, ffffh - Failed }
asm
mov ax,0021h { Software reset }
int 33h
end;
function mouse_reset:boolean;assembler;
asm
xor ax,ax
int 33h { hardware reset }
test ax,ax
jz @nomouse
mov ax,0021h
int 33h { software reset }
mov ax,0003h
int 33h { request status }
mov ax,0001h
int 33h { show cursor }
@nomouse:
end;
procedure mousereset;assembler;
asm
xor ax,ax
int 33h
end;
procedure mouseon;assembler;
asm
mov ax,0001h
int 33h
end;
procedure mouseoff;assembler;
asm
mov ax,0002h
int 33h
end;
function leftbutton:boolean;assembler;
asm
mov ax,0003h
int 33h
mov al,bl
and al,01h
end;
function rightbutton:boolean;assembler;
asm
mov ax,0003h
int 33h
shr bx,1
and bx,0001h
mov ax,bx
end;
procedure setcursor(b:byte);assembler;
asm
mov bx,0
mov cx,0 { default $ffff}
mov dh,2eh { 2x - background | xe - foreground | default: dx=7700h}
mov dl,b
mov ax,000ah
int 33h
end;
function mousex:word;assembler;
asm
mov ax,0003h
int 33h
{ shr cx,1 {for 320x200 and Text modes only}
mov ax,cx
end;
function mousey:word;assembler;
asm
mov ax,0003h
int 33h
mov ax,dx
end;
{ Returns true if the mouse cursor is in the given rectangular area }
function micedom(x1,y1,x2,y2:word):boolean;assembler;
asm
mov ax,0003h
int 33h
{ shr cx,1 { 320x200 mode only}
cmp cx,[x1]
jl @nodom
cmp cx,[x2]
jg @nodom
cmp dx,[y1]
jl @nodom
cmp dx,[y2]
jg @nodom
mov ax,0001h
jmp @end_
@nodom:
xor ax,ax
@end_:
end;
{ Restricts mouse cursor movement to the given rectangular area }
procedure setmousearea(x1,y1,x2,y2:word);assembler;
asm
mov ax,0007h
mov cx,[x1]
{ shl cx,1 {for 320x200 modes only}
mov dx,[x2]
{ shl dx,1 {for 320x200 modes only}
int 33h
mov ax,0008h
mov cx,[y1]
mov dx,[y2]
int 33h
end;
procedure movemousecursor(x,y:word);assembler;
{ Moves the cursor to the given coord. }
asm
mov ax,0004h
mov cx,[x]
{ shl cx,1 {<----}
mov dx,[y]
int 33h
end;
function mousemove:boolean;assembler;
{ Returns true if the cursor was moved since the last int 33h call }
asm
mov ax,000bh
int 33h
test cx,cx
jz @nomove
test dx,dx
jz @nomove
mov ax,0001h
jmp @exit_
@nomove:
xor ax,ax
@exit_:
end;
procedure setmousecursor(var cur;hot_x,hot_y:word);assembler;
asm
mov ax,9
mov bx,hot_x
mov cx,hot_y
les dx,cur
int 33h
end;
procedure set_arrow_cursor;
begin
mouseoff;
setmousecursor(arrow_cursor,0,0);
mouseon;
end;
procedure waitkey;assembler;
asm
mov ah,07h
int 21h
end;
procedure beep;assembler; { System beep }
asm
mov ah,02h
mov dl,07h
int 21h
end;
{### VGA GUI functions ######################################################}
type _button=object
id:string[40];
x1,y1,x2,y2:word;
typ:byte;
xdep,ydep:shortint;
caption:string[14];
icon:pointer;
status:boolean;
constructor init(x1_,y1_,x2_,y2_:word;typ_:byte;cap_,id_:string;icon_:pointer);
destructor done;
procedure display;
procedure push;
procedure relase;
function isdom:boolean;
function _isdom(x_,y_:word):boolean;
{to be continued here ***}
end;
_inputbar=object
id:string[40];
x,y:word;
typ,maxlen:byte;
caption:string[40];
constructor init(x1_,y1_:word;typ_,maxlength_:byte;cap_,id_:string);
destructor done;
procedure display;
function input(ch:char):string;
function isdom:boolean;
function _isdom(x_,y_:word):boolean;
end;
_rbutton=object { typ: 0 = radio button 1 = check box / size is 16x16 pixel}
id:string[40];
x,y:word;
typ:byte;
state:boolean;
constructor init(x_,y_:word;typ_:byte;stat:boolean;id_:string);
destructor done;
procedure flip;
procedure change(b:boolean);
function isdom:boolean;
function _isdom(x_,y_:word):boolean;
procedure display;
end;
const show_hint:boolean=false;
{########### Some useful functions}
procedure _swap(var a,b:word);
var c:word;
begin c:=a;a:=b;b:=c; end;
function tostr(l:longint):string; { Converts longint to string }
var s:string;
begin
str(l,s);
tostr:=s;
end;
{Return true is (x,y) is inside (x1,y1,x2,y2) rectangular area}
function inrec(x,y,x1,y1,x2,y2:word):boolean;
begin
inrec:=((x>=x1) and (x<=x2)) and ((y>=y1) and (y<=y2));
end;
{Performs a XOR operation between col and pixel in an rectangular area}
procedure xorbar(x1,y1,x2,y2:word;col:byte);
var i,j:word;
begin
if x2<x1 then _swap(x1,x2); if y2<y1 then _swap(y1,y2);
for i:=x1 to x2 do
for j:=y1 to y2 do
putpixel(i,j,getpixel(i,j) xor col);
end;
{adds a '0' to front if length=1, useful to format display of date/time}
function zeroadj(s:string):string;
begin if length(s)=1 then zeroadj:='0'+s else zeroadj:=s;end;
{########### Radio button object}
constructor _rbutton.init;
begin
x:=x_;y:=y_;state:=stat;id:=id_;typ:=typ_;
display;
end;
destructor _rbutton.done; begin end; {yet another dummy proc.}
procedure ffill(x,y,col,target:integer);
var t:integer;
begin
t:=getpixel(x,y);
if t<>target then exit;
if t=col then exit;
putpixel(x,y,col);
ffill(x-1,y,col,target);
ffill(x+1,y,col,target);
ffill(x,y-1,col,target);
ffill(x,y+1,col,target);
end;
procedure _rbutton.display;
var t:word;
begin
t:=getpixel(x+1,y+1);
setfillstyle(1,t);
bar(x,y,x+15,y+15);
if typ=0 then begin
setcolor(black);
circle(x+8,y+8,7);
setfillstyle(1,white);
floodfill(x+8,y+8,black);
if state then begin
setcolor(0);
circle(x+8,y+8,3);
ffill(x+7,y+7,0,white);
end;{state}
end else begin
setfillstyle(1,white);
bar(x,y,x+15,y+15);
setcolor(black);
rectangle(x,y,x+15,y+15);
if state then begin
setcolor(lightred);
line(x+4,y+7,x+8,y+12);
line(x+8,y+12,x+12,y+2);
end;
end;
end;
procedure _rbutton.flip; {toggle state}
begin
state:=not(state);
mouseoff;
display;
setmousearea(x,y,x+15,y+15);
mouseon;
while leftbutton do;
mouseoff;
setmousearea(0,0,639,479);
mouseon;
end;
procedure _rbutton.change;
begin
state:=b;
mouseoff;
display;
setmousearea(x,y,x+15,y+15);
mouseon;
while leftbutton do;
mouseoff;
setmousearea(0,0,maxx,maxy);
mouseon;
end;
function _rbutton.isdom;
begin isdom:=micedom(x+3,y+3,x+12,y+12);end;
function _rbutton._isdom;
begin
_isdom:=(((x+3)<=x_) and ((x+12)>=x_)) and (((y+3)<=y_) and ((y+12)>=y_));
end;
{########### Input bar object}
constructor _inputbar.init;
begin
x:=x1_;y:=y1_;
typ:=typ_;caption:=cap_;maxlen:=maxlength_;
id:=id_;
display;
end;
destructor _inputbar.done;
begin end; {dummy}
procedure _inputbar.display;
begin
setcolor(0);
rectangle(x,y,x+succ(maxlen)*8+5,y+11);
setfillstyle(1,15);
bar(x+1,y+1,x+succ(maxlen)*8+4,y+10);
setcolor(0);
outtextxy(x+3,y+2,caption);
end;
function _inputbar.isdom;
begin isdom:=micedom(x,y,x+succ(maxlen)*8+5,y+11);end;
function _inputbar._isdom;
begin
_isdom:=((x<=x_) and ((x+succ(maxlen)*8+5)>=x_)) and
((y<=y_) and ((y+11)>=y_));
end;
function _inputbar.input;
var c:char;
temp:string[41];
km,app:boolean;
procedure md;
begin
mouseoff;
setfillstyle(1,white);
bar(x+1,y+1,x+succ(maxlen)*8+4,y+10);
setcolor(red);
outtextxy(x+3,y+2,temp+'_');
mouseon;
end;
begin
temp:=caption;
km:=false;app:=false;
if (ord(ch)<32) then ch:=#0;
if ((ch<>#0) and (length(temp)<=maxlen)) then temp:=temp+ch;
md;
repeat
if keypressed then begin
c:=readkey;
if typ=0 {numbers only} then begin
case c of
#0:readkey;
#3,#27:km:=true;
'0'..'9','.','^','e':if length(temp)<maxlen then begin
temp:=temp+c;md;
end else write(#7{DOS beep});
#8{bkspc}:if length(temp)>0 then begin
if length(temp)=1 then temp:='' else
temp:=copy(temp,1,length(temp)-1);md;
end else write(#7);
#10,#13:begin km:=true;app:=true;end;
else write(#7);
end;{case} end else begin
case c of
#0:readkey;
#3,#27:km:=true;
'0'..'9','a'..'z','A'..'Z',#32,
'`','~','!','@','#','$','%','^','&',
'*','(',')','-','_','=','+','[','{','}','}','\',
'|',';',':','"','''','<','>',',','.','/','?':if length(temp)<maxlen then begin
temp:=temp+c;md;
end else write(#7{DOS beep});
#8{bkspc}:if length(temp)>0 then begin
if length(temp)=1 then temp:='' else
temp:=copy(temp,1,length(temp)-1);md;
end else write(#7);
#10,#13:begin km:=true;app:=true;end;
else write(#7);
end;{case}end;{if}
end;{keypr}
until km;
if app then begin caption:=temp;input:=caption;end else input:='';
mouseoff;
display;
mouseon;
end;
{########### Button object}
constructor _button.init;
begin
x1:=x1_;y1:=y1_;x2:=x2_;y2:=y2_;
typ:=typ_;caption:=cap_;id:=id_;
icon:=icon_;
status:=false; { true = pushed }
xdep:=2;ydep:=2;
display;
end;
destructor _button.done;
begin
end;
procedure _button.push;
begin
status:=true;
mouseoff;
display;
setmousearea(x1,y1,x2,y2);
mouseon;
while leftbutton do;
mouseoff;
status:=false;
display;
setmousearea(0,0,maxx,maxy);
mouseon;
end;
procedure _button.relase; begin status:=false;display;end;
function _button.isdom;begin isdom:=micedom(x1,y1,x2,y2);end;
function _button._isdom;
begin
_isdom:=((x1<=x_) and (x2>=x_)) and ((y1<=y_) and (y2>=y_));
end;
procedure _button.display;
begin
setfillstyle(1,7);
bar(x1,y1,x2,y2);
setcolor(0);
rectangle(x1,y1,x2,y2);
if not(status) then begin
setcolor(8);
line(x1+1,y2-1,x2-1,y2-1);
line(x2-1,y1+1,x2-1,y2-1);
setcolor(15);
line(x1+1,y1+1,x2-1,y1+1);
line(x1+1,y1+1,x1+1,y2-1);
end else begin
setcolor(15);
line(x1+1,y2-1,x2-1,y2-1);
line(x2-1,y1+1,x2-1,y2-1);
setcolor(8);
line(x1+1,y1+1,x2-1,y1+1);
line(x1+1,y1+1,x1+1,y2-1);
end;
if length(caption)=0 then caption:='N/C';
if typ=0 then begin
setcolor(0);
outtextxy(x1+((x2-x1)-length(caption)*8) div 2+2,y1+((y2-y1)-8) div 2+1,caption);end
else if icon<>nil then
putimage(x1+xdep,y1+ydep,icon^,0);
end;
{############################################################################}
procedure i_bar(s:string);
begin
mouseoff;
if (length(s)>79) then s:=copy(s,1,79);
setfillstyle(1,white);
bar(1,maxy-11,maxx-1,maxy-1);
setcolor(0);
rectangle(1,maxy-11,maxx-1,maxy-1);
setcolor(0);
outtextxy(3,maxy-9,s);
mouseon;
end;
procedure window_(x1,y1,x2,y2:word;s:string);
begin
setfillstyle(1,7);
bar(x1,y1,x2,y2);
setcolor(0);
rectangle(x1,y1,x2,y2);
setcolor(8);
line(x1+1,y2-1,x2-1,y2-1);
line(x2-1,y1+1,x2-1,y2-1);
setcolor(15);
line(x1+1,y1+1,x2-1,y1+1);
line(x1+1,y1+1,x1+1,y2-1);
setfillstyle(1,blue);
bar(x1+2,y1+2,x2-2,y1+12);
setcolor(yellow);
outtextxy(x1+6,y1+4,s);
end;
function lwindow(s1,s2,s3:string):boolean;
var pkep:pointer;
pngs,x1,x2,y1,y2,n,d:word;
b1,b2:_button;
km,am:boolean;
cf:char;
mox,moy:word;
begin
km:=false;am:=false;
if length(s1)<16 then s1:=s1+' ';
pngs:=imagesize(1,1,succ(length(s1))*8+4,52);
if maxavail>pngs then begin
getmem(pkep,pngs);
mouseoff;
x1:=(succ(maxx)-(succ(length(s1))*8+4)) div 2;
y1:=164;
x2:=x1+succ(length(s1))*8+4;
y2:=226;
getimage(x1,y1,x2,y2,pkep^);
window_(x1,y1,x2,y2,s1);
d:=x2-x1;n:=(d-40) div 2;
b1.init(x1+10,y1+30,x1+10+n,y1+44,0,s2,'This will trigger logic 1',nil);
b2.init(x1+30+n,y1+30,x1+30+2*n,y1+44,0,s3,'This will trigger logic 0',nil);
mouseon;
repeat
if leftbutton then begin
if b1.isdom then begin b1.push;km:=true;am:=true;end;
if b2.isdom then begin b2.push;km:=true;end;
end;
if show_hint and mousemove then begin
mox:=mousex;moy:=mousey;
if b1._isdom(mox,moy) then i_bar(b1.id);
if b2._isdom(mox,moy) then i_bar(b2.id);
end;
if keypressed then begin
cf:=readkey;
if cf=#13 then begin km:=true;am:=true;end else
if cf=#27 then km:=true else write(#7);
end;
until km;
mouseoff;
b2.done;b1.done;
putimage(x1,y1,pkep^,0);
freemem(pkep,pngs);
mouseon;
i_bar(id_text);
lwindow:=am;
end else i_bar('Darn, not enough memory');
end;
{Menu function x - x position
n - number of items including blank ones
name - file window caption
caption - items concatenated separaded by "/"
hotkeys - hotkeys concatenated, separated by "/"
will be appended to caption items
Can contain empty items, not as first or last, these will be jumped over
Returns: the current item clicked or pressed enter
Pretty lame code, not fool proof so experiment with it :)
Ex. menu(10,5,'File','New /Save/Open//Exit','Alt-N/ F3/ F2//Alt-X');}
function menu(x:word;n:byte;name,caption,hotkeys:string):byte;
var lns:array[1..16] of string[75];
i,j,pos_,totl,cur_s:byte;
pkep:pointer;
pngs:word;
chg:char;
kk,apla:boolean;
procedure disp;
var t,y:byte;
oldpat:fillpatterntype;
const gr:fillpatterntype=($ee,$bb,$ee,$bb,$ee,$bb,$ee,$bb);
begin
mouseoff;
getfillpattern(oldpat);
setfillpattern(gr,8);
bar(x+5,25,x+145,45+12*n);
setfillpattern(oldpat,15);
window_(x,20,x+140,40+12*n,name);
setfillstyle(1,7);
setcolor(0);
for t:=1 to n do begin
outtextxy(x+5,26+t*12,lns[t]);
if cur_s=t then begin
setwritemode(xorput);
setcolor(yellow);
for y:=1 to 10 do
line(x+4,25+t*12+pred(y),x+136,25+t*12+pred(y));
setwritemode(0);
setcolor(0);
end;
end;
mouseon;
end;
procedure displa(dir:shortint);
var y:byte;
begin
if ((lns[cur_s+dir][1]=' ') and ((cur_s+2*dir) in [1..n])) then dir:=2*dir;
mouseoff;
setwritemode(xorput);
setcolor(yellow);
for y:=1 to 10 do
line(x+4,25+cur_s*12+pred(y),x+136,25+cur_s*12+pred(y));
inc(cur_s,dir);
for y:=1 to 10 do
line(x+4,25+cur_s*12+pred(y),x+136,25+cur_s*12+pred(y));
setwritemode(0);
mouseon;
end;
procedure ddd(kt:byte);
var y:byte;
begin
mouseoff;
setwritemode(xorput);
setcolor(yellow);
for y:=1 to 10 do
line(x+4,25+cur_s*12+pred(y),x+136,25+cur_s*12+pred(y));
cur_s:=kt;
for y:=1 to 10 do
line(x+4,25+cur_s*12+pred(y),x+136,25+cur_s*12+pred(y));
setwritemode(0);
mouseon;
end;
begin
j:=1;cur_s:=1;
kk:=false;apla:=false;
if x>490 then x:=490; {limit position to avoid clipping}
for i:=1 to n do begin {this does the splitting}
pos_:=pos('/',caption);
lns[i]:=copy(caption,j,pred(pos_));
caption:=copy(caption,succ(pos_),length(caption)-pos_);
end;{i}
j:=1;
for i:=1 to n do begin
pos_:=pos('/',hotkeys);
lns[i]:=lns[i]+' '+copy(hotkeys,j,pred(pos_));
hotkeys:=copy(hotkeys,succ(pos_),length(hotkeys)-pos_);
end;{i}
pngs:=imagesize(0,0,145,25+12*n);
if maxavail>=pngs then begin
mouseoff;
getmem(pkep,pngs);
getimage(x,20,x+145,45+12*n,pkep^);
mouseon;
disp;
repeat
if keypressed then begin
chg:=readkey;
case chg of
#13:begin kk:=true;apla:=true;end;
#27:kk:=true;
#0:begin
chg:=readkey;
case chg of
#72:{up}if cur_s>1 then displa(-1);
#80:{dn}if cur_s<n then displa(+1);
end;{case chg, the 2nd}
end;{#0}
end;{case chg}
end;{keypressed}
if leftbutton then begin
for j:=1 to n do
if micedom(x+4,25+j*12,x+136,25+j*12+10) then begin
if j=cur_s then begin kk:=true;apla:=true;end else
if (lns[j][1]<>' ') then ddd(j);
end;
while leftbutton do;
end;{leftbutton}
until kk;
mouseoff;
putimage(x,20,pkep^,0);
freemem(pkep,pngs);
mouseon;
if apla then menu:=cur_s else menu:=0;
end else lwindow('Darn, not enough memory !','Accept','Acknowledge');
end;
{############################################################################}
procedure quit(n:byte);
const err_code:array[0..6] of string[45]=
('Unknown error',
'386+ CPU required',
'VGA+ required',
'Mouse required',
'Not enough conventional memory',
'Internal link error',
'');
begin
if gr_mode then closegraph;
if not(n in[0..6]) then n:=0;
writeln(#13#10,'An error occured > ',err_code[n],#7);
delay(1500);
halt(n);
end;
procedure init;
var gd,gm:integer;
begin
if test8086<2 then quit(1);
{ gd:=registerbgidriver(@vgadriver);
if gd<0 then begin
writeln('Error registering graphic driver: ',
grapherrormsg(graphresult));
quit(5);
end;}
gd:=0;gm:=0; {VGA 640x480 16 color}
initgraph(gd,gm,'');
if graphresult<>0 then quit(2);
gr_mode:=true;
if not(mouse_reset) then quit(3);
if memavail<150000 then quit(4);
maxx:=getmaxx;maxy:=getmaxy;
mouseoff;
end;
{### Main ###################################################################}
var b1,b2,b3,x:_button;
ext:boolean;
ch:char;
begin
ext:=false;
init;
window_(0,0,639,468,'Menu demo');
i_bar('Press 1 to 3 to activate menus, arrows to navigate, Esc to quit');
mouseon;
set_arrow_cursor;
b1.init(10,24,70,42,0,'Menu 1','Menu 1',nil);
b2.init(74,24,134,42,0,'Menu 2','Menu 2',nil);
b3.init(138,24,198,42,0,'Menu 3','Menu 3',nil);
x.init(569,24,629,42,0,'Exit','Exit',nil);
repeat
if leftbutton then begin { left mouse button was pressed }
if b1.isdom then begin
b1.push;
menu(5,5,'Menu 1','Item1/Item2/Item3//Item5',
'Key1/Key2/Key3//Key5');
end;
if b2.isdom then begin
b2.push;
menu(69,5,'Menu 2','Item1/Item2/Item3//Item5',
'Key1/Key2/Key3//Key5');
end;
if b3.isdom then begin
b3.push;
menu(133,5,'Menu 3','Item1/Item2/Item3//Item5',
'Key1/Key2/Key3//Key5');
end;
if x.isdom then begin
x.push;
ext:=lwindow(' Really want to quit ? ','Quit','Cancel');
end;
end;
if keypressed then begin { keyboard input }
ch:=readkey;
case ch of
'1':menu(5,5,'Menu 1','Item1/Item2/Item3//Item5',
'Key1/Key2/Key3//Key5');
'2':menu(69,5,'Menu 2','Item1/Item2/Item3//Item5',
'Key1/Key2/Key3//Key5');
'3':menu(133,5,'Menu 3','Item1/Item2/Item3//Item5',
'Key1/Key2/Key3//Key5');
#27:ext:=lwindow(' Really want to quit ? ','Quit','Cancel');
end;
end;
until ext;
x.done;
b3.done;
b2.done;
b1.done;
mouseoff;
closegraph;
end.