summaryrefslogtreecommitdiffstats
path: root/ncurses-5.3/Ada95/samples/ncurses2-demo_pad.adb
diff options
context:
space:
mode:
Diffstat (limited to 'ncurses-5.3/Ada95/samples/ncurses2-demo_pad.adb')
-rw-r--r--ncurses-5.3/Ada95/samples/ncurses2-demo_pad.adb671
1 files changed, 671 insertions, 0 deletions
diff --git a/ncurses-5.3/Ada95/samples/ncurses2-demo_pad.adb b/ncurses-5.3/Ada95/samples/ncurses2-demo_pad.adb
new file mode 100644
index 0000000..3e37a2a
--- /dev/null
+++ b/ncurses-5.3/Ada95/samples/ncurses2-demo_pad.adb
@@ -0,0 +1,671 @@
+------------------------------------------------------------------------------
+-- --
+-- GNAT ncurses Binding Samples --
+-- --
+-- ncurses --
+-- --
+-- B O D Y --
+-- --
+------------------------------------------------------------------------------
+-- Copyright (c) 2000 Free Software Foundation, Inc. --
+-- --
+-- Permission is hereby granted, free of charge, to any person obtaining a --
+-- copy of this software and associated documentation files (the --
+-- "Software"), to deal in the Software without restriction, including --
+-- without limitation the rights to use, copy, modify, merge, publish, --
+-- distribute, distribute with modifications, sublicense, and/or sell --
+-- copies of the Software, and to permit persons to whom the Software is --
+-- furnished to do so, subject to the following conditions: --
+-- --
+-- The above copyright notice and this permission notice shall be included --
+-- in all copies or substantial portions of the Software. --
+-- --
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS --
+-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF --
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. --
+-- IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, --
+-- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR --
+-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR --
+-- THE USE OR OTHER DEALINGS IN THE SOFTWARE. --
+-- --
+-- Except as contained in this notice, the name(s) of the above copyright --
+-- holders shall not be used in advertising or otherwise to promote the --
+-- sale, use or other dealings in this Software without prior written --
+-- authorization. --
+------------------------------------------------------------------------------
+-- Author: Eugene V. Melaragno <aldomel@ix.netcom.com> 2000
+-- Version Control
+-- $Revision$
+-- Binding Version 01.00
+------------------------------------------------------------------------------
+with ncurses2.util; use ncurses2.util;
+
+with Terminal_Interface.Curses; use Terminal_Interface.Curses;
+
+with Interfaces.C;
+with System.Storage_Elements;
+with System.Address_To_Access_Conversions;
+
+with Ada.Text_IO;
+-- with Ada.Real_Time; use Ada.Real_Time;
+-- TODO is there a way to use Real_Time or Ada.Calendar in place of
+-- gettimeofday?
+
+-- Demonstrate pads.
+procedure ncurses2.demo_pad is
+
+ type timestruct is record
+ seconds : Integer;
+ microseconds : Integer;
+ end record;
+
+ type myfunc is access function (w : Window) return Key_Code;
+
+ function gettime return timestruct;
+ procedure do_h_line (y : Line_Position;
+ x : Column_Position;
+ c : Attributed_Character;
+ to : Column_Position);
+ procedure do_v_line (y : Line_Position;
+ x : Column_Position;
+ c : Attributed_Character;
+ to : Line_Position);
+ function padgetch (win : Window) return Key_Code;
+ function panner_legend (line : Line_Position) return Boolean;
+ procedure panner_legend (line : Line_Position);
+ procedure panner_h_cleanup (from_y : Line_Position;
+ from_x : Column_Position;
+ to_x : Column_Position);
+ procedure panner_v_cleanup (from_y : Line_Position;
+ from_x : Column_Position;
+ to_y : Line_Position);
+ procedure panner (pad : Window;
+ top_xp : Column_Position;
+ top_yp : Line_Position;
+ portyp : Line_Position;
+ portxp : Column_Position;
+ pgetc : myfunc);
+
+ function gettime return timestruct is
+
+ retval : timestruct;
+
+ use Interfaces.C;
+ type timeval is record
+ tv_sec : long;
+ tv_usec : long;
+ end record;
+ pragma Convention (C, timeval);
+
+ -- TODO function from_timeval is new Ada.Unchecked_Conversion(
+ -- timeval_a, System.Storage_Elements.Integer_Address);
+ -- should Interfaces.C.Pointers be used here?
+
+ package myP is new System.Address_To_Access_Conversions (timeval);
+ use myP;
+
+ t : Object_Pointer := new timeval;
+
+ function gettimeofday
+ (TP : System.Storage_Elements.Integer_Address;
+ TZP : System.Storage_Elements.Integer_Address) return int;
+ pragma Import (C, gettimeofday, "gettimeofday");
+ tmp : int;
+ begin
+ tmp := gettimeofday (System.Storage_Elements.To_Integer
+ (myP.To_Address (t)),
+ System.Storage_Elements.To_Integer
+ (myP.To_Address (null)));
+ retval.seconds := Integer (t.tv_sec);
+ retval.microseconds := Integer (t.tv_usec);
+ return retval;
+ end gettime;
+
+
+ -- in C, The behavior of mvhline, mvvline for negative/zero length is
+ -- unspecified, though we can rely on negative x/y values to stop the
+ -- macro. Except Ada makes Line_Position(-1) = Natural - 1 so forget it.
+ procedure do_h_line (y : Line_Position;
+ x : Column_Position;
+ c : Attributed_Character;
+ to : Column_Position) is
+ begin
+ if to > x then
+ Move_Cursor (Line => y, Column => x);
+ Horizontal_Line (Line_Size => Natural (to - x), Line_Symbol => c);
+ end if;
+ end do_h_line;
+
+ procedure do_v_line (y : Line_Position;
+ x : Column_Position;
+ c : Attributed_Character;
+ to : Line_Position) is
+ begin
+ if to > y then
+ Move_Cursor (Line => y, Column => x);
+ Vertical_Line (Line_Size => Natural (to - y), Line_Symbol => c);
+ end if;
+ end do_v_line;
+
+
+
+
+ function padgetch (win : Window) return Key_Code is
+ c : Key_Code;
+ c2 : Character;
+ begin
+ c := Getchar (win);
+ c2 := Code_To_Char (c);
+
+ case c2 is
+ when '!' =>
+ ShellOut (False);
+ return Key_Refresh;
+ when Character'Val (Character'Pos ('r') mod 16#20#) => -- CTRL('r')
+ End_Windows;
+ Refresh;
+ return Key_Refresh;
+ when Character'Val (Character'Pos ('l') mod 16#20#) => -- CTRL('l')
+ return Key_Refresh;
+ when 'U' =>
+ return Key_Cursor_Up;
+ when 'D' =>
+ return Key_Cursor_Down;
+ when 'R' =>
+ return Key_Cursor_Right;
+ when 'L' =>
+ return Key_Cursor_Left;
+ when '+' =>
+ return Key_Insert_Line;
+ when '-' =>
+ return Key_Delete_Line;
+ when '>' =>
+ return Key_Insert_Char;
+ when '<' =>
+ return Key_Delete_Char;
+ -- when ERR=> /* FALLTHRU */
+ when 'q' =>
+ return (Key_Exit);
+ when others =>
+ return (c);
+ end case;
+ end padgetch;
+
+ show_panner_legend : Boolean := True;
+
+ function panner_legend (line : Line_Position) return Boolean is
+ legend : constant array (0 .. 3) of String (1 .. 61) :=
+ (
+ "Use arrow keys (or U,D,L,R) to pan, q to quit (?,t,s flags) ",
+ "Use ! to shell-out. Toggle legend:?, timer:t, scroll mark:s.",
+ "Use +,- (or j,k) to grow/shrink the panner vertically. ",
+ "Use <,> (or h,l) to grow/shrink the panner horizontally. ");
+ legendsize : constant := 4;
+
+ n : Integer := legendsize - Integer (Lines - line);
+ begin
+ if line < Lines and n >= 0 then
+ Move_Cursor (Line => line, Column => 0);
+ if show_panner_legend then
+ Add (Str => legend (n));
+ end if;
+ Clear_To_End_Of_Line;
+ return show_panner_legend;
+ end if;
+ return False;
+ end panner_legend;
+
+ procedure panner_legend (line : Line_Position) is
+ tmp : Boolean;
+ begin
+ tmp := panner_legend (line);
+ end panner_legend;
+
+ procedure panner_h_cleanup (from_y : Line_Position;
+ from_x : Column_Position;
+ to_x : Column_Position) is
+ begin
+ if not panner_legend (from_y) then
+ do_h_line (from_y, from_x, Blank2, to_x);
+ end if;
+ end panner_h_cleanup;
+
+ procedure panner_v_cleanup (from_y : Line_Position;
+ from_x : Column_Position;
+ to_y : Line_Position) is
+ begin
+ if not panner_legend (from_y) then
+ do_v_line (from_y, from_x, Blank2, to_y);
+ end if;
+ end panner_v_cleanup;
+
+
+ procedure panner (pad : Window;
+ top_xp : Column_Position;
+ top_yp : Line_Position;
+ portyp : Line_Position;
+ portxp : Column_Position;
+ pgetc : myfunc) is
+
+ function f (y : Line_Position) return Line_Position;
+ function f (x : Column_Position) return Column_Position;
+ function greater (y1, y2 : Line_Position) return Integer;
+ function greater (x1, x2 : Column_Position) return Integer;
+
+ top_x : Column_Position := top_xp;
+ top_y : Line_Position := top_yp;
+ porty : Line_Position := portyp;
+ portx : Column_Position := portxp;
+
+ -- f[x] returns max[x - 1, 0]
+ function f (y : Line_Position) return Line_Position is
+ begin
+ if y > 0 then
+ return y - 1;
+ else
+ return y; -- 0
+ end if;
+ end f;
+
+ function f (x : Column_Position) return Column_Position is
+ begin
+ if x > 0 then
+ return x - 1;
+ else
+ return x; -- 0
+ end if;
+ end f;
+
+ function greater (y1, y2 : Line_Position) return Integer is
+ begin
+ if y1 > y2 then
+ return 1;
+ else
+ return 0;
+ end if;
+ end greater;
+
+ function greater (x1, x2 : Column_Position) return Integer is
+ begin
+ if x1 > x2 then
+ return 1;
+ else
+ return 0;
+ end if;
+ end greater;
+
+
+ pymax : Line_Position;
+ basey : Line_Position := 0;
+ pxmax : Column_Position;
+ basex : Column_Position := 0;
+ c : Key_Code;
+ scrollers : Boolean := True;
+ before, after : timestruct;
+ timing : Boolean := True;
+
+ package floatio is new Ada.Text_IO.Float_IO (Long_Float);
+ begin
+ Get_Size (pad, pymax, pxmax);
+ Allow_Scrolling (Mode => False); -- we don't want stdscr to scroll!
+
+ c := Key_Refresh;
+ loop
+ -- During shell-out, the user may have resized the window. Adjust
+ -- the port size of the pad to accommodate this. Ncurses
+ -- automatically resizes all of the normal windows to fit on the
+ -- new screen.
+ if top_x > Columns then
+ top_x := Columns;
+ end if;
+ if portx > Columns then
+ portx := Columns;
+ end if;
+ if top_y > Lines then
+ top_y := Lines;
+ end if;
+ if porty > Lines then
+ porty := Lines;
+ end if;
+
+ case c is
+ when Key_Refresh | Character'Pos ('?') =>
+ if c = Key_Refresh then
+ Erase;
+ else -- '?'
+ show_panner_legend := not show_panner_legend;
+ end if;
+ panner_legend (Lines - 4);
+ panner_legend (Lines - 3);
+ panner_legend (Lines - 2);
+ panner_legend (Lines - 1);
+ when Character'Pos ('t') =>
+ timing := not timing;
+ if not timing then
+ panner_legend (Lines - 1);
+ end if;
+ when Character'Pos ('s') =>
+ scrollers := not scrollers;
+
+ -- Move the top-left corner of the pad, keeping the
+ -- bottom-right corner fixed.
+ when Character'Pos ('h') =>
+ -- increase-columns: move left edge to left
+ if top_x <= 0 then
+ Beep;
+ else
+ panner_v_cleanup (top_y, top_x, porty);
+ top_x := top_x - 1;
+ end if;
+
+ when Character'Pos ('j') =>
+ -- decrease-lines: move top-edge down
+ if top_y >= porty then
+ Beep;
+ else
+ if top_y /= 0 then
+ panner_h_cleanup (top_y - 1, f (top_x), portx);
+ end if;
+ top_y := top_y + 1;
+ end if;
+ when Character'Pos ('k') =>
+ -- increase-lines: move top-edge up
+ if top_y <= 0 then
+ Beep;
+ else
+ top_y := top_y - 1;
+ panner_h_cleanup (top_y, top_x, portx);
+ end if;
+
+ when Character'Pos ('l') =>
+ -- decrease-columns: move left-edge to right
+ if top_x >= portx then
+ Beep;
+ else
+ if top_x /= 0 then
+ panner_v_cleanup (f (top_y), top_x - 1, porty);
+ end if;
+ top_x := top_x + 1;
+ end if;
+
+ -- Move the bottom-right corner of the pad, keeping the
+ -- top-left corner fixed.
+ when Key_Insert_Char =>
+ -- increase-columns: move right-edge to right
+ if portx >= pxmax or portx >= Columns then
+ Beep;
+ else
+ panner_v_cleanup (f (top_y), portx - 1, porty);
+ portx := portx + 1;
+ -- C had ++portx instead of portx++, weird.
+ end if;
+ when Key_Insert_Line =>
+ -- increase-lines: move bottom-edge down
+ if porty >= pymax or porty >= Lines then
+ Beep;
+ else
+ panner_h_cleanup (porty - 1, f (top_x), portx);
+ porty := porty + 1;
+ end if;
+
+ when Key_Delete_Char =>
+ -- decrease-columns: move bottom edge up
+ if portx <= top_x then
+ Beep;
+ else
+ portx := portx - 1;
+ panner_v_cleanup (f (top_y), portx, porty);
+ end if;
+
+ when Key_Delete_Line =>
+ -- decrease-lines
+ if porty <= top_y then
+ Beep;
+ else
+ porty := porty - 1;
+ panner_h_cleanup (porty, f (top_x), portx);
+ end if;
+ when Key_Cursor_Left =>
+ -- pan leftwards
+ if basex > 0 then
+ basex := basex - 1;
+ else
+ Beep;
+ end if;
+ when Key_Cursor_Right =>
+ -- pan rightwards
+ -- if (basex + portx - (pymax > porty) < pxmax)
+ if (basex + portx -
+ Column_Position (greater (pymax, porty)) < pxmax) then
+ -- if basex + portx < pxmax or
+ -- (pymax > porty and basex + portx - 1 < pxmax) then
+ basex := basex + 1;
+ else
+ Beep;
+ end if;
+
+ when Key_Cursor_Up =>
+ -- pan upwards
+ if basey > 0 then
+ basey := basey - 1;
+ else
+ Beep;
+ end if;
+
+ when Key_Cursor_Down =>
+ -- pan downwards
+ -- same as if (basey + porty - (pxmax > portx) < pymax)
+ if (basey + porty -
+ Line_Position (greater (pxmax, portx)) < pymax) then
+ -- if (basey + porty < pymax) or
+ -- (pxmax > portx and basey + porty - 1 < pymax) then
+ basey := basey + 1;
+ else
+ Beep;
+ end if;
+
+ when Character'Pos ('H') |
+ Key_Home |
+ Key_Find =>
+ basey := 0;
+
+ when Character'Pos ('E') |
+ Key_End |
+ Key_Select =>
+ basey := pymax - porty;
+ if basey < 0 then -- basey := max(basey, 0);
+ basey := 0;
+ end if;
+
+ when others =>
+ Beep;
+ end case;
+
+ -- more writing off the screen.
+ -- Interestingly, the exception is not handled if
+ -- we put a block around this.
+ -- delcare --begin
+ if top_y /= 0 and top_x /= 0 then
+ Add (Line => top_y - 1, Column => top_x - 1,
+ Ch => ACS_Map (ACS_Upper_Left_Corner));
+ end if;
+ if top_x /= 0 then
+ do_v_line (top_y, top_x - 1, ACS_Map (ACS_Vertical_Line), porty);
+ end if;
+ if top_y /= 0 then
+ do_h_line (top_y - 1, top_x, ACS_Map (ACS_Horizontal_Line), portx);
+ end if;
+ -- exception when Curses_Exception => null; end;
+
+ -- in C was ... pxmax > portx - 1
+ if scrollers and pxmax >= portx then
+ declare
+ length : Column_Position := portx - top_x - 1;
+ lowend, highend : Column_Position;
+ begin
+ -- Instead of using floats, I'll use integers only.
+ lowend := top_x + (basex * length) / pxmax;
+ highend := top_x + ((basex + length) * length) / pxmax;
+
+ do_h_line (porty - 1, top_x, ACS_Map (ACS_Horizontal_Line),
+ lowend);
+ if highend < portx then
+ Switch_Character_Attribute
+ (Attr => (Reverse_Video => True, others => False),
+ On => True);
+ do_h_line (porty - 1, lowend, Blank2, highend + 1);
+ Switch_Character_Attribute
+ (Attr => (Reverse_Video => True, others => False),
+ On => False);
+ do_h_line (porty - 1, highend + 1,
+ ACS_Map (ACS_Horizontal_Line), portx);
+ end if;
+ end;
+ else
+ do_h_line (porty - 1, top_x, ACS_Map (ACS_Horizontal_Line), portx);
+ end if;
+
+ if scrollers and pymax >= porty then
+ declare
+ length : Line_Position := porty - top_y - 1;
+ lowend, highend : Line_Position;
+ begin
+ lowend := top_y + (basey * length) / pymax;
+ highend := top_y + ((basey + length) * length) / pymax;
+
+ do_v_line (top_y, portx - 1, ACS_Map (ACS_Vertical_Line),
+ lowend);
+ if highend < porty then
+ Switch_Character_Attribute
+ (Attr => (Reverse_Video => True, others => False),
+ On => True);
+ do_v_line (lowend, portx - 1, Blank2, highend + 1);
+ Switch_Character_Attribute
+ (Attr => (Reverse_Video => True, others => False),
+ On => False);
+ do_v_line (highend + 1, portx - 1,
+ ACS_Map (ACS_Vertical_Line), porty);
+ end if;
+ end;
+ else
+ do_v_line (top_y, portx - 1, ACS_Map (ACS_Vertical_Line), porty);
+ end if;
+
+ if top_y /= 0 then
+ Add (Line => top_y - 1, Column => portx - 1,
+ Ch => ACS_Map (ACS_Upper_Right_Corner));
+ end if;
+ if top_x /= 0 then
+ Add (Line => porty - 1, Column => top_x - 1,
+ Ch => ACS_Map (ACS_Lower_Left_Corner));
+ end if;
+ declare
+ begin
+ -- Here is another place where it is possible
+ -- to write to the corner of the screen.
+ Add (Line => porty - 1, Column => portx - 1,
+ Ch => ACS_Map (ACS_Lower_Right_Corner));
+ exception
+ when Curses_Exception => null;
+ end;
+
+ before := gettime;
+
+ Refresh_Without_Update;
+
+ declare
+ -- the C version allows the panel to have a zero height
+ -- wich raise the exception
+ begin
+ Refresh_Without_Update
+ (
+ pad,
+ basey, basex,
+ top_y, top_x,
+ porty - Line_Position (greater (pxmax, portx)) - 1,
+ portx - Column_Position (greater (pymax, porty)) - 1);
+ exception
+ when Curses_Exception => null;
+ end;
+
+ Update_Screen;
+
+ if timing then declare
+ s : String (1 .. 7);
+ elapsed : Long_Float;
+ begin
+ after := gettime;
+ elapsed := (Long_Float (after.seconds - before.seconds) +
+ Long_Float (after.microseconds - before.microseconds)
+ / 1.0e6);
+ Move_Cursor (Line => Lines - 1, Column => Columns - 20);
+ floatio.Put (s, elapsed, Aft => 3, Exp => 0);
+ Add (Str => s);
+ Refresh;
+ end;
+ end if;
+
+ c := pgetc (pad);
+ exit when c = Key_Exit;
+
+ end loop;
+
+ Allow_Scrolling (Mode => True);
+
+ end panner;
+
+ Gridsize : constant := 3;
+ Gridcount : Integer := 0;
+
+ Pad_High : constant Line_Count := 200;
+ Pad_Wide : constant Column_Count := 200;
+ panpad : Window := New_Pad (Pad_High, Pad_Wide);
+begin
+ if panpad = Null_Window then
+ Cannot ("cannot create requested pad");
+ return;
+ end if;
+
+ for i in 0 .. Pad_High - 1 loop
+ for j in 0 .. Pad_Wide - 1 loop
+ if i mod Gridsize = 0 and j mod Gridsize = 0 then
+ if i = 0 or j = 0 then
+ Add (panpad, '+');
+ else
+ -- depends on ASCII?
+ Add (panpad,
+ Ch => Character'Val (Character'Pos ('A') +
+ Gridcount mod 26));
+ Gridcount := Gridcount + 1;
+ end if;
+ elsif i mod Gridsize = 0 then
+ Add (panpad, '-');
+ elsif j mod Gridsize = 0 then
+ Add (panpad, '|');
+ else
+ declare
+ -- handle the write to the lower right corner error
+ begin
+ Add (panpad, ' ');
+ exception
+ when Curses_Exception => null;
+ end;
+ end if;
+ end loop;
+ end loop;
+ panner_legend (Lines - 4);
+ panner_legend (Lines - 3);
+ panner_legend (Lines - 2);
+ panner_legend (Lines - 1);
+
+ Set_KeyPad_Mode (panpad, True);
+ -- Make the pad (initially) narrow enough that a trace file won't wrap.
+ -- We'll still be able to widen it during a test, since that's required
+ -- for testing boundaries.
+
+ panner (panpad, 2, 2, Lines - 5, Columns - 15, padgetch'Access);
+
+ Delete (panpad);
+ End_Windows; -- Hmm, Erase after End_Windows
+ Erase;
+end ncurses2.demo_pad;