1 ------------------------------------------------------------------------------
3 -- GNAT ncurses Binding Samples --
9 ------------------------------------------------------------------------------
10 -- Copyright (c) 2000-2009,2011 Free Software Foundation, Inc. --
12 -- Permission is hereby granted, free of charge, to any person obtaining a --
13 -- copy of this software and associated documentation files (the --
14 -- "Software"), to deal in the Software without restriction, including --
15 -- without limitation the rights to use, copy, modify, merge, publish, --
16 -- distribute, distribute with modifications, sublicense, and/or sell --
17 -- copies of the Software, and to permit persons to whom the Software is --
18 -- furnished to do so, subject to the following conditions: --
20 -- The above copyright notice and this permission notice shall be included --
21 -- in all copies or substantial portions of the Software. --
23 -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS --
24 -- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF --
25 -- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. --
26 -- IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, --
27 -- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR --
28 -- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR --
29 -- THE USE OR OTHER DEALINGS IN THE SOFTWARE. --
31 -- Except as contained in this notice, the name(s) of the above copyright --
32 -- holders shall not be used in advertising or otherwise to promote the --
33 -- sale, use or other dealings in this Software without prior written --
35 ------------------------------------------------------------------------------
36 -- Author: Eugene V. Melaragno <aldomel@ix.netcom.com> 2000
39 -- $Date: 2011/03/23 00:33:00 $
40 -- Binding Version 01.00
41 ------------------------------------------------------------------------------
42 -- Windows and scrolling tester.
43 -- Demonstrate windows
45 with Ada
.Strings
.Fixed
;
48 with ncurses2
.util
; use ncurses2
.util
;
49 with ncurses2
.genericPuts
;
50 with Terminal_Interface
.Curses
; use Terminal_Interface
.Curses
;
51 with Terminal_Interface
.Curses
.Mouse
; use Terminal_Interface
.Curses
.Mouse
;
52 with Terminal_Interface
.Curses
.PutWin
; use Terminal_Interface
.Curses
.PutWin
;
54 with Ada
.Streams
.Stream_IO
; use Ada
.Streams
.Stream_IO
;
55 with Ada
.Streams
; use Ada
.Streams
;
57 procedure ncurses2
.acs_and_scroll
is
59 Macro_Quit
: constant Key_Code
:= Character'Pos ('Q') mod 16#
20#
;
60 Macro_Escape
: constant Key_Code
:= Character'Pos ('[') mod 16#
20#
;
62 Quit
: constant Key_Code
:= CTRL
('Q');
63 Escape
: constant Key_Code
:= CTRL
('[');
65 Botlines
: constant Line_Position
:= 4;
73 type FrameA
is access Frame
;
76 dumpfile
: constant String := "screendump";
78 procedure Outerbox
(ul
, lr
: pair
; onoff
: Boolean);
79 function HaveKeyPad
(w
: Window
) return Boolean;
80 function HaveScroll
(w
: Window
) return Boolean;
81 procedure newwin_legend
(curpw
: Window
);
82 procedure transient
(curpw
: Window
; msg
: String);
83 procedure newwin_report
(win
: Window
:= Standard_Window
);
84 procedure selectcell
(uli
: Line_Position
;
85 ulj
: Column_Position
;
87 lrj
: Column_Position
;
90 function getwindow
return Window
;
91 procedure newwin_move
(win
: Window
;
93 dx
: Column_Position
);
94 function delete_framed
(fp
: FrameA
; showit
: Boolean) return FrameA
;
97 -- I wish there was a standard library linked list. Oh well.
109 procedure Outerbox
(ul
, lr
: pair
; onoff
: Boolean) is
112 -- Note the fix of an obscure bug
113 -- try making a 1x1 box then enlarging it, the is a blank
114 -- upper left corner!
115 Add
(Line
=> ul
.y
- 1, Column
=> ul
.x
- 1,
116 Ch
=> ACS_Map
(ACS_Upper_Left_Corner
));
117 Add
(Line
=> ul
.y
- 1, Column
=> lr
.x
+ 1,
118 Ch
=> ACS_Map
(ACS_Upper_Right_Corner
));
119 Add
(Line
=> lr
.y
+ 1, Column
=> lr
.x
+ 1,
120 Ch
=> ACS_Map
(ACS_Lower_Right_Corner
));
121 Add
(Line
=> lr
.y
+ 1, Column
=> ul
.x
- 1,
122 Ch
=> ACS_Map
(ACS_Lower_Left_Corner
));
124 Move_Cursor
(Line
=> ul
.y
- 1, Column
=> ul
.x
);
125 Horizontal_Line
(Line_Symbol
=> ACS_Map
(ACS_Horizontal_Line
),
126 Line_Size
=> Integer (lr
.x
- ul
.x
) + 1);
127 Move_Cursor
(Line
=> ul
.y
, Column
=> ul
.x
- 1);
128 Vertical_Line
(Line_Symbol
=> ACS_Map
(ACS_Vertical_Line
),
129 Line_Size
=> Integer (lr
.y
- ul
.y
) + 1);
130 Move_Cursor
(Line
=> lr
.y
+ 1, Column
=> ul
.x
);
131 Horizontal_Line
(Line_Symbol
=> ACS_Map
(ACS_Horizontal_Line
),
132 Line_Size
=> Integer (lr
.x
- ul
.x
) + 1);
133 Move_Cursor
(Line
=> ul
.y
, Column
=> lr
.x
+ 1);
134 Vertical_Line
(Line_Symbol
=> ACS_Map
(ACS_Vertical_Line
),
135 Line_Size
=> Integer (lr
.y
- ul
.y
) + 1);
137 Add
(Line
=> ul
.y
- 1, Column
=> ul
.x
- 1, Ch
=> ' ');
138 Add
(Line
=> ul
.y
- 1, Column
=> lr
.x
+ 1, Ch
=> ' ');
139 Add
(Line
=> lr
.y
+ 1, Column
=> lr
.x
+ 1, Ch
=> ' ');
140 Add
(Line
=> lr
.y
+ 1, Column
=> ul
.x
- 1, Ch
=> ' ');
142 Move_Cursor
(Line
=> ul
.y
- 1, Column
=> ul
.x
);
143 Horizontal_Line
(Line_Symbol
=> Blank2
,
144 Line_Size
=> Integer (lr
.x
- ul
.x
) + 1);
145 Move_Cursor
(Line
=> ul
.y
, Column
=> ul
.x
- 1);
146 Vertical_Line
(Line_Symbol
=> Blank2
,
147 Line_Size
=> Integer (lr
.y
- ul
.y
) + 1);
148 Move_Cursor
(Line
=> lr
.y
+ 1, Column
=> ul
.x
);
149 Horizontal_Line
(Line_Symbol
=> Blank2
,
150 Line_Size
=> Integer (lr
.x
- ul
.x
) + 1);
151 Move_Cursor
(Line
=> ul
.y
, Column
=> lr
.x
+ 1);
152 Vertical_Line
(Line_Symbol
=> Blank2
,
153 Line_Size
=> Integer (lr
.y
- ul
.y
) + 1);
157 function HaveKeyPad
(w
: Window
) return Boolean is
159 return Get_KeyPad_Mode
(w
);
161 when Curses_Exception
=> return False;
164 function HaveScroll
(w
: Window
) return Boolean is
166 return Scrolling_Allowed
(w
);
168 when Curses_Exception
=> return False;
171 procedure newwin_legend
(curpw
: Window
) is
173 package p
is new genericPuts
(200);
177 type string_a
is access String;
181 code
: Integer range 0 .. 3;
184 legend
: constant array (Positive range <>) of rrr
:=
187 new String'("^C = create window"), 0
190 new String'("^N = next window"), 0
193 new String'("^P = previous window"), 0
196 new String'("^F = scroll forward"), 0
199 new String'("^B = scroll backward"), 0
202 new String'("^K = keypad(%s)"), 1
205 new String'("^S = scrollok(%s)"), 2
208 new String'("^W = save window to file"), 0
211 new String'("^R = restore window"), 0
214 new String'("^X = resize"), 0
217 new String'("^Q%s = exit"), 3
221 buf : Bounded_String;
222 do_keypad : constant Boolean := HaveKeyPad (curpw);
223 do_scroll : constant Boolean := HaveScroll (curpw);
229 use Ada.Strings.Fixed;
232 Move_Cursor (Line => Lines - 4, Column => 0);
233 for n in legend'Range loop
234 pos := Ada.Strings.Fixed.Index (Source => legend (n).msg.all,
236 -- buf := (others => ' ');
237 buf := To_Bounded_String (legend (n).msg.all);
238 case legend (n).code is
242 Replace_Slice (buf, pos, pos + 1, "yes");
244 Replace_Slice (buf, pos, pos + 1, "no");
248 Replace_Slice (buf, pos, pos + 1, "yes");
250 Replace_Slice (buf, pos, pos + 1, "no");
254 Replace_Slice (buf, pos, pos + 1, "/ESC");
256 Replace_Slice (buf, pos, pos + 1, "");
259 Get_Cursor_Position (Line => mypair.y, Column => mypair.x);
260 if Columns < mypair.x + 3 + Column_Position (Length (buf)) then
262 elsif n /= 1 then -- n /= legen'First
267 Clear_To_End_Of_Line;
270 procedure transient (curpw : Window; msg : String) is
272 newwin_legend (curpw);
274 Add (Line => Lines - 1, Column => 0, Str => msg);
276 Nap_Milli_Seconds (1000);
279 Move_Cursor (Line => Lines - 1, Column => 0);
281 if HaveKeyPad (curpw) then
282 Add (Str => "Non-arrow");
284 Add (Str => "All other");
286 Add (Str => " characters are echoed, window should ");
287 if not HaveScroll (curpw) then
290 Add (Str => "scroll");
292 Clear_To_End_Of_Line;
295 procedure newwin_report (win : Window := Standard_Window) is
299 tmp2a : String (1 .. 2);
300 tmp2b : String (1 .. 2);
302 if win /= Standard_Window then
305 Get_Cursor_Position (win, y, x);
306 Move_Cursor (Line => Lines - 1, Column => Columns - 17);
307 Put (tmp2a, Integer (y));
308 Put (tmp2b, Integer (x));
309 Add (Str => "Y = " & tmp2a & " X = " & tmp2b);
310 if win /= Standard_Window then
313 Move_Cursor (win, y, x);
317 procedure selectcell (uli : Line_Position;
318 ulj : Column_Position;
320 lrj : Column_Position;
325 i : Line_Position := 0;
326 j : Column_Position := 0;
327 si : constant Line_Position := lri - uli + 1;
328 sj : constant Column_Position := lrj - ulj + 1;
333 Move_Cursor (Line => uli + i, Column => ulj + j);
341 -- on the same line macro calls interfere due to the # comment
342 -- this is needed because keypad off affects all windows.
343 -- try removing the ESCAPE and see what happens.
348 -- same as i := i - 1 because of Modulus arithmetic,
349 -- on Line_Position, which is a Natural
350 -- the C version uses this form too, interestingly.
362 Button : Mouse_Button;
363 State : Button_State;
367 Get_Event (Event => event,
372 if y > uli and x > ulj then
375 -- same as when others =>
397 function getwindow return Window is
402 Move_Cursor (Line => 0, Column => 0);
403 Clear_To_End_Of_Line;
404 Add (Str => "Use arrows to move cursor, anything else to mark corner 1");
406 selectcell (2, 1, Lines - Botlines - 2, Columns - 2, ul, result);
410 Add (Line => ul.y - 1, Column => ul.x - 1,
411 Ch => ACS_Map (ACS_Upper_Left_Corner));
412 Move_Cursor (Line => 0, Column => 0);
413 Clear_To_End_Of_Line;
414 Add (Str => "Use arrows to move cursor, anything else to mark corner 2");
416 selectcell (ul.y, ul.x, Lines - Botlines - 2, Columns - 2, lr, result);
421 rwindow := Sub_Window (Number_Of_Lines => lr.y - ul.y + 1,
422 Number_Of_Columns => lr.x - ul.x + 1,
423 First_Line_Position => ul.y,
424 First_Column_Position => ul.x);
426 Outerbox (ul, lr, True);
431 Move_Cursor (Line => 0, Column => 0);
432 Clear_To_End_Of_Line;
436 procedure newwin_move (win : Window;
438 dx : Column_Position) is
439 cur_y, max_y : Line_Position;
440 cur_x, max_x : Column_Position;
442 Get_Cursor_Position (win, cur_y, cur_x);
443 Get_Size (win, max_y, max_x);
444 cur_x := Column_Position'Min (Column_Position'Max (cur_x + dx, 0),
446 cur_y := Line_Position'Min (Line_Position'Max (cur_y + dy, 0),
449 Move_Cursor (win, Line => cur_y, Column => cur_x);
452 function delete_framed (fp : FrameA; showit : Boolean) return FrameA is
455 fp.all.last.all.next := fp.all.next;
456 fp.all.next.all.last := fp.all.last;
460 Refresh (fp.all.wind);
462 Delete (fp.all.wind);
464 if fp = fp.all.next then
473 Mask : Event_Mask := No_Events;
480 Register_Reportable_Event (
484 Mask2 := Start_Mouse (Mask);
487 Set_Raw_Mode (SwitchOn => True);
489 transient (Standard_Window, "");
491 when Character'Pos ('c
') mod 16#20# => -- Ctrl('c
')
493 neww : constant FrameA := new Frame'(null, null,
497 neww
.all.wind
:= getwindow
;
498 if neww
.all.wind
= Null_Window
then
500 -- was goto breakout; ha ha ha
503 if current
= null then
504 neww
.all.next
:= neww
;
505 neww
.all.last
:= neww
;
507 neww
.all.next
:= current
.all.next
;
508 neww
.all.last
:= current
;
509 neww
.all.last
.all.next
:= neww
;
510 neww
.all.next
.all.last
:= neww
;
514 Set_KeyPad_Mode
(current
.all.wind
, True);
515 current
.all.do_keypad
:= HaveKeyPad
(current
.all.wind
);
516 current
.all.do_scroll
:= HaveScroll
(current
.all.wind
);
519 when Character'Pos ('N') mod 16#
20#
=> -- Ctrl('N')
520 if current
/= null then
521 current
:= current
.all.next
;
523 when Character'Pos ('P') mod 16#
20#
=> -- Ctrl('P')
524 if current
/= null then
525 current
:= current
.all.last
;
527 when Character'Pos ('F') mod 16#
20#
=> -- Ctrl('F')
528 if current
/= null and then HaveScroll
(current
.all.wind
) then
529 Scroll
(current
.all.wind
, 1);
531 when Character'Pos ('B') mod 16#
20#
=> -- Ctrl('B')
532 if current
/= null and then HaveScroll
(current
.all.wind
) then
533 -- The C version of Scroll may return ERR which is ignored
534 -- we need to avoid the exception
535 -- with the 'and HaveScroll(current.wind)'
536 Scroll
(current
.all.wind
, -1);
538 when Character'Pos ('K') mod 16#
20#
=> -- Ctrl('K')
539 if current
/= null then
540 current
.all.do_keypad
:= not current
.all.do_keypad
;
541 Set_KeyPad_Mode
(current
.all.wind
, current
.all.do_keypad
);
543 when Character'Pos ('S') mod 16#
20#
=> -- Ctrl('S')
544 if current
/= null then
545 current
.all.do_scroll
:= not current
.all.do_scroll
;
546 Allow_Scrolling
(current
.all.wind
, current
.all.do_scroll
);
548 when Character'Pos ('W') mod 16#
20#
=> -- Ctrl('W')
549 if current
/= current
.all.next
then
550 Create
(f
, Name
=> dumpfile
); -- TODO error checking
551 if not Is_Open
(f
) then
552 raise Curses_Exception
;
554 Put_Window
(current
.all.wind
, f
);
556 current
:= delete_framed
(current
, True);
558 when Character'Pos ('R') mod 16#
20#
=> -- Ctrl('R')
560 neww
: FrameA
:= new Frame
'(null, null, False, False,
563 Open (f, Mode => In_File, Name => dumpfile);
564 neww := new Frame'(null, null, False, False, Null_Window
);
566 neww
.all.next
:= current
.all.next
;
567 neww
.all.last
:= current
;
568 neww
.all.last
.all.next
:= neww
;
569 neww
.all.next
.all.last
:= neww
;
571 neww
.all.wind
:= Get_Window
(f
);
574 Refresh
(neww
.all.wind
);
576 when Character'Pos ('X') mod 16#
20#
=> -- Ctrl('X')
577 if current
/= null then
580 mx
: Column_Position
;
584 Move_Cursor
(Line
=> 0, Column
=> 0);
585 Clear_To_End_Of_Line
;
586 Add
(Str
=> "Use arrows to move cursor, anything else " &
587 "to mark new corner");
590 Get_Window_Position
(current
.all.wind
, ul
.y
, ul
.x
);
592 selectcell
(ul
.y
, ul
.x
, Lines
- Botlines
- 2, Columns
- 2,
595 -- the C version had a goto. I refuse gotos.
598 Get_Size
(current
.all.wind
, lr
.y
, lr
.x
);
599 lr
.y
:= lr
.y
+ ul
.y
- 1;
600 lr
.x
:= lr
.x
+ ul
.x
- 1;
601 Outerbox
(ul
, lr
, False);
602 Refresh_Without_Update
;
604 Get_Size
(current
.all.wind
, my
, mx
);
605 if my
> tmp
.y
- ul
.y
then
606 Get_Cursor_Position
(current
.all.wind
, lr
.y
, lr
.x
);
607 Move_Cursor
(current
.all.wind
, tmp
.y
- ul
.y
+ 1, 0);
608 Clear_To_End_Of_Screen
(current
.all.wind
);
609 Move_Cursor
(current
.all.wind
, lr
.y
, lr
.x
);
611 if mx
> tmp
.x
- ul
.x
then
612 for i
in 0 .. my
- 1 loop
613 Move_Cursor
(current
.all.wind
, i
, tmp
.x
- ul
.x
+ 1);
614 Clear_To_End_Of_Line
(current
.all.wind
);
617 Refresh_Without_Update
(current
.all.wind
);
620 -- The C version passes invalid args to resize
621 -- which returns an ERR. For Ada we avoid the exception.
622 if lr
.y
/= ul
.y
and lr
.x
/= ul
.x
then
623 Resize
(current
.all.wind
, lr
.y
- ul
.y
+ 0,
627 Get_Window_Position
(current
.all.wind
, ul
.y
, ul
.x
);
628 Get_Size
(current
.all.wind
, lr
.y
, lr
.x
);
629 lr
.y
:= lr
.y
+ ul
.y
- 1;
630 lr
.x
:= lr
.x
+ ul
.x
- 1;
631 Outerbox
(ul
, lr
, True);
632 Refresh_Without_Update
;
634 Refresh_Without_Update
(current
.all.wind
);
635 Move_Cursor
(Line
=> 0, Column
=> 0);
636 Clear_To_End_Of_Line
;
642 declare tmp
: pair
; tmpbool
: Boolean;
644 -- undocumented --- use this to test area clears
645 selectcell
(0, 0, Lines
- 1, Columns
- 1, tmp
, tmpbool
);
646 Clear_To_End_Of_Screen
;
649 when Key_Cursor_Up
=>
650 newwin_move
(current
.all.wind
, -1, 0);
651 when Key_Cursor_Down
=>
652 newwin_move
(current
.all.wind
, 1, 0);
653 when Key_Cursor_Left
=>
654 newwin_move
(current
.all.wind
, 0, -1);
655 when Key_Cursor_Right
=>
656 newwin_move
(current
.all.wind
, 0, 1);
657 when Key_Backspace | Key_Delete_Char
=>
663 Get_Cursor_Position
(current
.all.wind
, y
, x
);
665 -- I got tricked by the -1 = Max_Natural - 1 result
667 if not (x
= 0 and y
= 0) then
670 Get_Size
(current
.all.wind
, tmp
, x
);
673 Delete_Character
(current
.all.wind
, y
, x
);
678 if current
/= null then
681 Add
(current
.all.wind
, Ch
=> Code_To_Char
(c
));
683 when Curses_Exception
=> null;
684 -- this happens if we are at the
685 -- lower right of a window and add a character.
691 newwin_report
(current
.all.wind
);
692 if current
/= null then
693 usescr
:= current
.all.wind
;
695 usescr
:= Standard_Window
;
698 c
:= Getchar
(usescr
);
699 exit when c
= Quit
or (c
= Escape
and HaveKeyPad
(usescr
));
700 -- TODO when does c = ERR happen?
703 -- TODO while current /= null loop
704 -- current := delete_framed(current, False);
707 Allow_Scrolling
(Mode
=> True);
710 Set_Raw_Mode
(SwitchOn
=> True);
714 end ncurses2
.acs_and_scroll
;