[GB.NCURSES]

* BUG: Input: Comment all NoDelay related stuff out
* BUG: Window: PrintCenter() handles empty lines now
* NEW: Pair: Allocate all pairs at initialisation and inhibit any change to
  them. Array accessors can be used to get the pair number for a given
  fore-/background combination
* NEW: Window: Rewrite the Window class
* NEW: Remove the Insert() method
* NEW: Remove .Window.Attrs' Color property
* NEW: BorderFrame is an optional argument to the constructor (default True)
  to specify if there shall be a border frame around the window setting the
  border apart from the content
* NEW: Ask() returns the choice number to ease translation
* NEW: Ask() supports a default choice in upper case
* NEW: Make Read event work
* NEW: Screen: Rewrite it mostly (is a static class again)
* NEW: Remove Read event
* NEW: Make Resize event work
* NEW: Rename .Cols and .Lines to .Width resp. .Height
* NEW: Declare gb.ncurses "Unfinished"
* OPT: Tidy up sources
* OPT: Window: Use werase() instead of wclear() to clear

[EXAMPLES]
* NEW: Add 'Pong' in the Games section



git-svn-id: svn://localhost/gambas/trunk@5543 867c0c6c-44f3-4631-809d-bfa615b0a4ec
This commit is contained in:
Tobias Boege 2013-02-10 20:06:36 +00:00
parent ff507f5dde
commit cf20462abc
20 changed files with 1500 additions and 1775 deletions

View File

@ -0,0 +1,2 @@
[Desktop Entry]
Icon=./.icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,15 @@
# Gambas Project File 3.0
# Compiled with Gambas 3.4.0
Title=Pong
Startup=MMain
UseTerminal=1
Icon=pong.png
Version=1.0.2
Component=gb.ncurses
Description="The classic Pong game as a gb.ncurses example."
Authors="(C) 2013 Tobias Boege <tobias@gambas-buch.de>"
TabSize=2
Translate=1
Language=en_GB
SourcePath=/home/tab/Desktop/exchg
Packager=1

View File

@ -0,0 +1,134 @@
' Gambas class file
Property HDir As Integer
Property VDir As Integer
Property X As Integer
Property Y As Integer
Private $hWindow As Window
' Used in a simulation (of NPC)?
Private $bSimulate As Boolean
Private $iX As Integer
Private $iY As Integer
' Horizontal and vertical movement deltas on screen
Private $iHD As Integer
Private $iVD As Integer
Public Sub _new(hWnd As Window, Optional bSim As Boolean = False)
$hWindow = hWnd
$bSimulate = bSim
End
Public Sub Reset()
Undraw()
$iX = $hWindow.Width / 2 + 1
$iY = Rnd(0, $hWindow.Height)
$iHD = IIf(CInt(Rnd(0, 2)), 1, -1)
$iVD = IIf(CInt(Rnd(0, 2)), 1, -1)
End
'' Returns the .Dir of the paddle that made the point
Public Sub Move(hP1 As Paddle, hP2 As Paddle) As Integer
Undraw()
$iX += $iHD
$iY += $iVD
Return EvaluateCollisions(hP1, hP2)
End
Private Function EvaluateCollisions(hP1 As Paddle, hP2 As Paddle) As Integer
' On left/right paddle?
If $iX = hP1.X And If $iY >= hP1.Y And If $iY < hP1.Y + hP1.Height Then GoSub _OnPaddle
If hP2 And If $iX = hP2.X And If $iY >= hP2.Y And If $iY < hP2.Y + hP2.Height Then GoSub _OnPaddle
' Flip at top/bottom border?
If $iY < 0 Or $iY >= $hWindow.Height Then
GoSub _UndoMovement
$iVD = - $iVD
Move(hP1, hP2)
Endif
' Made a point (left/right border)?
If $iX < 0 Or $iX >= $hWindow.Width Then
GoSub _UndoMovement
Return $iHD
Endif
Return 0
_UndoMovement:
$iX -= $iHD
$iY -= $iVD
Return
_OnPaddle:
GoSub _UndoMovement
$iHD = - $iHD
Move(hP1, hP2)
End
Public Sub Draw()
If $bSimulate Then Return
$hWindow.Print("o", $iX, $iY)
End
Public Sub Undraw()
If $bSimulate Then Return
$hWindow.Print(" ", $iX, $iY)
End
Private Sub HDir_Read() As Integer
Return $iHD
End
Private Sub HDir_Write(Value As Integer)
$iHD = Value
End
Private Sub VDir_Read() As Integer
Return $iVD
End
Private Sub VDir_Write(Value As Integer)
$iVD = Value
End
Private Function X_Read() As Integer
Return $iX
End
Private Sub X_Write(Value As Integer)
$iX = Value
End
Private Function Y_Read() As Integer
Return $iY
End
Private Sub Y_Write(Value As Integer)
$iY = Value
End

View File

@ -0,0 +1,191 @@
' Gambas module file
Private $hConfig As Window
Private $hTimer As Timer
' Scores
Private $iS1 As Integer
Private $iS2 As Integer
' Players' paddles
Private $hP1 As Paddle
Private $hP2 As Paddle
' If Paddle2 shall be controlled by an NPC object
Private $bNPC As Boolean
Private $hNPC As NPC
' The ball
Private $hBall As Ball
Public Sub Main()
' Make our Window raise events
Object.Attach(Window, Me, "Window")
Window.SetFocus()
Screen.Cursor = Cursor.Hidden
Screen.Echo = False
Screen.Input = Input.CBreak
Window.Border = Border.Ascii
Window.Caption = Subst$(("Pong v&1 - gb.ncurses Example"), Application.Version)
Window.Clear()
$hConfig = New Window(True, 0, 0, 30, 5)
$hConfig.Border = Border.Ascii
$hConfig.Center()
$hTimer = New Timer As "Timer"
' See SPEED. The width means actually the intra-paddle width:
$hTimer.Delay = 4000 / Sqr(2 * (Window.Width - 4) ^ 2)
$iS1 = 0
$iS2 = 0
$bNPC = True
GameInit()
End
Private Sub Configure()
$hConfig.Show()
$hConfig.Clear()
$hConfig.PrintCenter(("What to do?\nPlay again: [P]\nChange opponent: [o]\n\nQuit [q]"))
Select Case Window.Ask(("Poq"))
Case 2
Configure_Opponent()
Case 3
Quit
End Select
$hConfig.Hide()
End
Private Sub Configure_Opponent()
$hConfig.Clear()
$hConfig.PrintCenter(("Play against whom?\n[h]uman, [N]ormal, [m]aster"))
$bNPC = True
Select Case Window.Ask(("hNm"))
Case 1
$bNPC = False
Case 2
$hNPC.Mode = NPC.Normal
Case 3
$hNPC.Mode = NPC.Master
End Select
End
Private Sub GameInit()
' If both as 'master' NPCs we could make a screensaver out of it :-)
$hP1 = New Paddle(Window, 1)
$hP2 = New Paddle(Window, -1)
$hBall = New Ball(Window)
$hNPC = New NPC(Window, $hBall, $hP2)
GameStart()
End
Private Sub GameStart()
Window.Buffered = False
Configure()
$hP1.Reset()
$hP2.Reset()
$hBall.Reset()
$hNPC.Init()
Window.Buffered = True
Redraw()
$hTimer.Start()
End
Public Sub Timer_Timer()
If $bNPC Then $hNPC.Move()
Select Case $hBall.Move($hP1, $hP2)
Case -1
Inc $iS2
Goto _NewGame
Case 1
Inc $iS1
Goto _NewGame
End Select
Redraw()
Return
_NewGame:
' We want to see it
Redraw()
$hTimer.Stop()
' FIXME: Makes stack overflow eventually
GameStart()
End
Public Sub Window_Read()
Dim iKey As Integer
iKey = Window.Read()
Window.Drain()
' Go two steps per keystroke
' FIXME: Can't reach some coordinate with odd Window.Height
Select Case iKey
' Player 1
Case Key.Up
If $hP1.Y > 0 Then $hP1.Y -= 2
Case Key.Down
If $hP1.Y + $hP1.Height < Window.Height Then $hP1.Y += 2
' Human player 2
Case Asc("j")
If Not $bNPC And $hP2.Y > 0 Then $hP2.Y -= 2
Case Asc("k")
If Not $bNPC And $hP2.Y + $hP2.Height < Window.Height Then $hP2.Y += 2
' Change ball speed :-)
Case Asc("+")
If $hTimer.Delay > 10 Then $hTimer.Delay -= 10
Case Asc("-")
$hTimer.Delay += 10
' Pause
Case Asc(("p"))
Pause()
' Quit
Case Asc(("q"))
Quit
Case Else
Return
End Select
Redraw()
End
Private Sub Redraw()
Dim iX As Integer = Window.Width / 4
' Scores and net
Window.Attributes.Reverse = True
Window.Print(" " & Str$($iS1) & " ", iX, 1)
Window.Print(" " & Str$($iS2) & " ", iX * 3, 1)
Window.Attributes.Reverse = False
Window.DrawVLine(Window.Width / 2 + 1, 0, Window.Height, ".")
' Players and ball may overwrite the unimportant stuff above
$hP1.Draw()
$hP2.Draw()
$hBall.Draw()
Screen.Refresh()
End
Private Sub Pause()
$hTimer.Stop()
Window.PrintCenter(("PAUSE"))
Screen.Refresh()
Window.Ask(("p"))
Window.Clear()
Redraw()
$hTimer.Start()
End

View File

@ -0,0 +1,116 @@
' Gambas class file
Public Const Normal As Integer = 0
Public Const Master As Integer = 1
Property Mode As Integer
Private $hWindow As Window
' Ball is needed to calculate movements, of course >:-)
Private $hBall As Ball
Private $hPaddle As Paddle
Private $iMode As Integer
' This is the Y coordinate we wish to reach with the middle of our paddle
Private $iY As Integer
Private $bReady As Boolean
' Master's control data
Private $iLastDir As Integer
Private $hMyPaddle As Paddle
Public Sub _new(hWnd As Window, hBall As Ball, hPaddle As Paddle, Optional iMode As Integer = Normal)
$hWindow = hWnd
$hBall = hBall
$hPaddle = hPaddle
$iMode = iMode
End
Public Sub Init()
$bReady = False
$iLastDir = $hBall.HDir
' We need to insert an opponent paddle that would block everything to not
' go into an infinite loop when trying to calculate the ball's positions
$hMyPaddle = New Paddle($hWindow, - $hPaddle.Dir)
$hMyPaddle.Reset()
$hMyPaddle.Y = 0
$hMyPaddle.Height = $hWindow.Height
End
Public Sub Move()
If $iMode = Normal Then
Move_Normal()
Else If $iMode = Master Then
Move_Master()
Endif
End
Private Sub Move_Normal()
' Make him beatable...
If CInt(Rnd(0, 2)) Then Return
' Just follow the ball
$iY = $hBall.Y
Move_Generic()
End
Private Sub Move_Master()
' Calculate the future ball's position and move accordingly
If Not $bReady Then MasterCalc()
Move_Generic()
' If the ball hits this paddle, we can begin calculating again
If $hBall.HDir <> $iLastDir And $iLastDir = - $hPaddle.Dir Then
$bReady = False
Endif
$iLastDir = $hBall.HDir
End
Private Sub Move_Generic()
Dim iMid As Integer = $hPaddle.Y + ($hPaddle.Height / 2)
Dim iDiff As Integer = $iY - iMid
If Abs(iDiff) <= 1 Then Return
$hPaddle.Y += 2 * Sgn(iDiff)
End
Private Sub MasterCalc()
Dim hMyBall As New Ball($hWindow, True)
' Use the CBall class to sneakily get the position we have to sit on
' when the ball arrives at this end
hMyBall.HDir = $hBall.HDir
hMyBall.VDir = $hBall.VDir
hMyBall.X = $hBall.X
hMyBall.Y = $hBall.Y
' Simulate the ball flying thither and back again
While hMyBall.X <> $hPaddle.X
hMyBall.Move($hMyPaddle, Null)
Wend
$iY = hMyBall.Y
$bReady = True
End
Private Sub Mode_Read() As Integer
Return $iMode
End
Private Sub Mode_Write(Value As Integer)
$iMode = Value
End

View File

@ -0,0 +1,96 @@
' Gambas class file
Property X As Integer
Property Y As Integer
Property Height As Integer
Property Read Dir As Integer
' Direction in which to play
Private $iDir As Integer
Private $hWindow As Window
Private $iOrigX As Integer
Private $iOrigY As Integer
Private $iX As Integer
Private $iY As Integer
Private $iHeight As Integer
Public Sub _new(hWnd As Window, iDir As Integer)
$hWindow = hWnd
$iHeight = hWnd.Height / 6 + 1
$iDir = iDir
If iDir > 0 Then
$iOrigX = 1
Else
$iOrigX = hWnd.Width - 2
Endif
$iOrigY = (hWnd.Height - $iHeight) / 2
If Odd($iOrigY) Then Inc $iOrigY
End
Public Sub Reset()
Undraw()
$iX = $iOrigX
$iY = $iOrigY
End
Public Sub Draw()
$hWindow.DrawVLine($iX, $iY, $iHeight, "|")
End
Public Sub Undraw()
$hWindow.DrawVLine($iX, $iY, $iHeight, " ")
End
Private Sub X_Read() As Integer
Return $iX
End
Private Sub X_Write(Value As Integer)
If Value < 0 Or If Value + 1 > $hWindow.Width Then Return
Undraw()
$iX = Value
End
Private Sub Y_Read() As Integer
Return $iY
End
Private Sub Y_Write(Value As Integer)
If Value < 0 Or If Value + $iHeight > $hWindow.Height Then Return
Undraw()
$iY = Value
End
Private Function Height_Read() As Integer
Return $iHeight
End
Private Sub Height_Write(Value As Integer)
$iHeight = Value
End
Private Function Dir_Read() As Integer
Return $iDir
End

View File

@ -0,0 +1,45 @@
Different people have different terminal dimensions. The following shall
outline my attempt to make Pong soundly playable with every one.
Consider this picture. Assume that it is your terminal:
........... Legend: +, -, | = Real border (of terminal)
. '. . = Imaginary border
. ' . o = Ball
. ' . " = Real flying behaviour
. ' . ' = Equivalent imaginary flying behaviour
+----'----+ The real and imaginary border make a square w^2.
| " | \
| " " "| |
| " " " | | Height h
|o " | /
+---------+
\_______/
Width w
We clearly want that the ball gets some velocity linearly proportional to
the distance it has to fly so that the time the ball needs (and the human
player has time to react) is constant.
As you can see, the distance from paddle 1 to paddle 2 is sqrt(2w^2) units.
The ball goes one unit per Timer event. We need a Timer.Delay that makes the
constant time elapse after sqrt(2w^2) Timer events.
Let's arbitrarily set the time from one paddle to the other to 4s:
Timer.Delay = 4000 / Sqr(2 * w ^ 2).
This was tested with ANSI's 80*24 terminal dimensions in xterm and my home
180*74 on the Linux console. Feel free to set the LINES and COLUMNS
environment variables to try different proportions.
One may see the crux with this approach: The larger/smaller the terminal,
the faster/slower the ball. I found both scenarios equally hard: with a
large terminal, the paddle is large; with a small terminal, the paddle is
small. It compensates.
TODO: The above is not true for terminals which are much _wider_ than high.
I found it problematic to play "LINES=10" but easy with "COLUMNS=30".
BTW: The NPCs make one step per each ball step. You may have to resize your
terminal to be able to win against 'master' ;-)

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

View File

@ -1,7 +1,7 @@
/*
* c_color.c - gb.ncurses Color static class
*
* Copyright (C) 2012 Tobias Boege <tobias@gambas-buch.de>
* Copyright (C) 2012/3 Tobias Boege <tobias@gambas-buch.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -26,127 +26,35 @@
#include "../gambas.h"
#include "main.h"
#include "c_color.h"
#include "c_screen.h"
static int _color;
static int _pair;
#define PAIR_VALID(p) (p >= 0 && p < COLOR_PAIRS)
#define COLOR_VALID(c) (c >= -1 && c < COLORS)
static int _color;
static short colors[] = {
COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
};
/**
* Colour initialisation
*/
void COLOR_init()
{
start_color();
use_default_colors();
}
//use_default_colors();
/**
* Initialise a colour
* @index: the color number
* @r: red
* @g: green
* @b: blue
* Note that one gives colour amounts in floats 0.0 - 1.0
*/
int COLOR_setcolor(short index, float r, float g, float b)
{
return init_color(index, r * 1000, g * 1000, b * 1000);
}
/*
* Initialise all possible pairs
*/
#define ARRAY_NUM(arr) (sizeof(arr) / sizeof(arr[0]))
int i, j, n;
/**
* Initialise one field of a colour
* @index: color number
* @val: value as float 0.0 - 1.0
* @what: field number
*/
int COLOR_setcolor_one(short index, float val, int what)
{
short r, g, b;
float rf, gf, bf;
color_content(index, &r, &g, &b);
rf = ((float) r) / 1000;
gf = ((float) g) / 1000;
bf = ((float) b) / 1000;
switch (what) {
case 0:
rf = val;
break;
case 1:
gf = val;
break;
case 2:
bf = val;
break;
default:
return -1;
}
return COLOR_setcolor(index, rf, gf, bf);
}
/**
* Initialise a colour pair
* @index: colour pair index
* @fg: foreground value
* @bg: background value
*/
int COLOR_setpair(short index, short fg, short bg)
{
/* FIXME: on my setup, giving -1 doesn't work after
use_default_colors(). It gives no error but does nothing. I
workaround this issue by assuming COLOR_BLACK and COLOR_WHITE as
defaults for back- and foreground respectively */
if (fg == -1)
fg = COLOR_WHITE;
if (bg == -1)
bg = COLOR_BLACK;
if (index)
init_pair(index, fg, bg);
else
assume_default_colors(fg, bg);
return 0;
}
/**
* Set either foreground or background of a colour pair
* @index: colour pair
* @val: colour
* @what: SETPAIR_* constant to indicate what should be set
*/
int COLOR_setpair_one(short index, short val, int what)
{
short f, b;
pair_content(index, &f, &b);
switch (what) {
case SETPAIR_FORE:
return COLOR_setpair(index, val, b);
case SETPAIR_BACK:
return COLOR_setpair(index, f, val);
}
return -1;
}
/**
* Return the RGB contents of a colour
* @color: colour value to examine
* @r: pointer to variable to be containing red portion
* @g: green
* @b: blue
* The @r, @g, @b values may be NULL in which case the value is discarded
*/
static int COLOR_content(short color, short *r, short *g, short *b)
{
short ar, ag, ab;
color_content(color, r ? r : &ar, g ? g : &ag, b ? b : &ab);
return 0;
for (n = 0, i = 0; i < ARRAY_NUM(colors); i++)
for (j = 0; j < ARRAY_NUM(colors); j++)
init_pair(++n, colors[i], colors[j]);
}
/*
* Color static class
* Color
*/
BEGIN_PROPERTY(Color_Available)
@ -178,125 +86,22 @@ BEGIN_METHOD(Color_get, GB_INTEGER index)
END_METHOD
BEGIN_METHOD(Color_Set, GB_INTEGER color; GB_INTEGER r; GB_INTEGER g; GB_INTEGER b)
int CCOLOR_setcolor(short index, float r, float g, float b)
{
return init_color(index, r * 1000, g * 1000, b * 1000);
}
BEGIN_METHOD(Color_Set, GB_INTEGER color; GB_FLOAT r; GB_FLOAT g;GB_FLOAT b)
if (!COLOR_VALID(VARG(color))) {
GB.Error(GB_ERR_BOUND);
return;
}
init_color(VARG(color), VARG(r), VARG(g), VARG(b));
REFRESH();
CCOLOR_setcolor(VARG(color), VARG(r), VARG(g), VARG(b));
REAL_REFRESH();
END_METHOD
/*
* .ColorInfo virtual class
*/
BEGIN_PROPERTY(ColorInfo_Red)
short red;
if (READ_PROPERTY) {
COLOR_content(_color, &red, NULL, NULL);
GB.ReturnInteger(red);
return;
}
COLOR_setcolor_one(_color, VPROP(GB_FLOAT), 0);
REAL_REFRESH();
END_PROPERTY
BEGIN_PROPERTY(ColorInfo_Green)
short green;
if (READ_PROPERTY) {
COLOR_content(_color, NULL, &green, NULL);
GB.ReturnInteger(green);
return;
}
COLOR_setcolor_one(_color, VPROP(GB_FLOAT), 1);
END_PROPERTY
BEGIN_PROPERTY(ColorInfo_Blue)
short blue;
if (READ_PROPERTY) {
COLOR_content(_color, NULL, NULL, &blue);
GB.ReturnInteger(blue);
return;
}
COLOR_setcolor_one(_color, VPROP(GB_FLOAT), 2);
END_PROPERTY
/*
* Pair static class
*/
BEGIN_PROPERTY(Pair_Count)
GB.ReturnInteger(COLOR_PAIRS);
END_PROPERTY
BEGIN_METHOD(Pair_get, GB_INTEGER index)
if (!PAIR_VALID(VARG(index))) {
GB.Error(GB_ERR_BOUND);
return;
}
_pair = VARG(index);
RETURN_SELF();
END_METHOD
/*
* .PairInfo virtual class
*/
BEGIN_PROPERTY(PairInfo_Background)
short f, b;
pair_content(_pair, &f, &b);
if (READ_PROPERTY) {
GB.ReturnInteger(b);
return;
}
if (!COLOR_VALID(VPROP(GB_INTEGER))) {
GB.Error(GB_ERR_BOUND);
return;
}
b = VPROP(GB_INTEGER);
COLOR_setpair(_pair, f, b);
REAL_REFRESH();
END_PROPERTY
BEGIN_PROPERTY(PairInfo_Foreground)
short f, b;
pair_content(_pair, &f, &b);
if (READ_PROPERTY) {
GB.ReturnInteger(f);
return;
}
if (!COLOR_VALID(VPROP(GB_INTEGER))) {
GB.Error(GB_ERR_BOUND);
return;
}
f = VPROP(GB_INTEGER);
COLOR_setpair(_pair, f, b);
REAL_REFRESH();
END_PROPERTY
GB_DESC CColorDesc[] = {
GB_DECLARE("Color", 0),
GB_NOT_CREATABLE(),
@ -320,6 +125,95 @@ GB_DESC CColorDesc[] = {
GB_END_DECLARE
};
/*
* .ColorInfo
*/
enum {
COLOR_R,
COLOR_G,
COLOR_B
};
static int CCOLOR_content(short color, float *r, float *g, float *b)
{
short ar, ag, ab;
color_content(color, &ar, &ag, &ab);
if (r)
*r = (float) ar / 1000;
if (g)
*g = (float) ag / 1000;
if (b)
*b = (float) ab / 1000;
return 0;
}
int CCOLOR_setcolor_one(short index, float val, int which)
{
short r, g, b;
float rf, gf, bf;
color_content(index, &r, &g, &b);
rf = ((float) r) / 1000;
gf = ((float) g) / 1000;
bf = ((float) b) / 1000;
switch (which) {
case COLOR_R:
rf = val;
break;
case COLOR_G:
gf = val;
break;
case COLOR_B:
bf = val;
break;
default:
return -1;
}
return CCOLOR_setcolor(index, rf, gf, bf);
}
BEGIN_PROPERTY(ColorInfo_Red)
float red;
if (READ_PROPERTY) {
CCOLOR_content(_color, &red, NULL, NULL);
GB.ReturnFloat(red);
return;
}
CCOLOR_setcolor_one(_color, VPROP(GB_FLOAT), COLOR_R);
REAL_REFRESH();
END_PROPERTY
BEGIN_PROPERTY(ColorInfo_Green)
float green;
if (READ_PROPERTY) {
CCOLOR_content(_color, NULL, &green, NULL);
GB.ReturnFloat(green);
return;
}
CCOLOR_setcolor_one(_color, VPROP(GB_FLOAT), COLOR_G);
END_PROPERTY
BEGIN_PROPERTY(ColorInfo_Blue)
float blue;
if (READ_PROPERTY) {
CCOLOR_content(_color, NULL, NULL, &blue);
GB.ReturnFloat(blue);
return;
}
CCOLOR_setcolor_one(_color, VPROP(GB_FLOAT), COLOR_B);
END_PROPERTY
GB_DESC CColorInfoDesc[] = {
GB_DECLARE(".ColorInfo", 0),
GB_VIRTUAL_CLASS(),
@ -331,23 +225,55 @@ GB_DESC CColorInfoDesc[] = {
GB_END_DECLARE
};
/*
* Pair
*/
BEGIN_PROPERTY(Pair_Count)
GB.ReturnInteger(COLOR_PAIRS);
END_PROPERTY
short CPAIR_get(short fg, short bg)
{
short i, j;
int n;
i = j = -1;
for (n = 0; n < ARRAY_NUM(colors); n++) {
if (colors[n] == fg)
i = fg;
if (colors[n] == bg)
j = bg;
if (i != -1 && j != -1)
break;
}
if (n == ARRAY_NUM(colors))
return -1;
/* See COLOR_init() */
return i * ARRAY_NUM(colors) + j + 1;
}
BEGIN_METHOD(Pair_get, GB_INTEGER fore; GB_INTEGER back)
short pairn = CPAIR_get(VARG(fore), VARG(back));
if (pairn == -1) {
GB.Error(GB_ERR_BOUND);
return;
}
GB.ReturnInteger(pairn);
END_METHOD
GB_DESC CPairDesc[] = {
GB_DECLARE("Pair", 0),
GB_NOT_CREATABLE(),
GB_STATIC_PROPERTY_READ("Count", "i", Pair_Count),
GB_STATIC_METHOD("_get", ".PairInfo", Pair_get, "(Index)i"),
GB_END_DECLARE
};
GB_DESC CPairInfoDesc[] = {
GB_DECLARE(".PairInfo", 0),
GB_VIRTUAL_CLASS(),
GB_STATIC_PROPERTY("Background", "i", PairInfo_Background),
GB_STATIC_PROPERTY("Foreground", "i", PairInfo_Foreground),
GB_STATIC_METHOD("_get", "i", Pair_get, "(Fore)i(Back)i"),
GB_END_DECLARE
};

View File

@ -1,27 +1,13 @@
#ifndef __C_COLOR_H
#define __C_COLOR_H
#include <ncurses.h>
#define PAIR_VALID(p) (p >= 0 && p < COLOR_PAIRS)
#define COLOR_VALID(c) (c >= -1 && c < COLORS)
#ifndef __C_COLOR_C
extern GB_DESC CColorDesc[];
extern GB_DESC CColorInfoDesc[];
extern GB_DESC CPairDesc[];
extern GB_DESC CPairInfoDesc[];
#endif
enum {
SETPAIR_FORE,
SETPAIR_BACK
};
void COLOR_init();
int COLOR_setcolor(short, float, float, float);
int COLOR_setcolor_one(short, float, int);
int COLOR_setpair(short, short, short);
int COLOR_setpair_one(short, short, int);
extern void COLOR_init();
extern int CCOLOR_setcolor(short index, float r, float g, float b);
extern int CCOLOR_setcolor_one(short index, float val, int which);
extern short CPAIR_get(short fg, short bg);
#endif /* __C_COLOR_H */

View File

@ -1,7 +1,7 @@
/*
* c_input.c - gb.ncurses opaque input routines
*
* Copyright (C) 2012 Tobias Boege <tobias@gambas-buch.de>
* Copyright (C) 2012/3 Tobias Boege <tobias@gambas-buch.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -23,9 +23,11 @@
#include <fcntl.h>
#include <unistd.h>
/*
#include <sys/ioctl.h>
#include <termios.h>
#include <linux/kd.h>
*/
#include <time.h>
#include <sys/time.h>
#include <errno.h>
@ -39,93 +41,44 @@
#include "c_input.h"
#include "c_window.h"
#define E_UNSUPP "Unsupported value"
#define E_NO_NODELAY "Could not initialise NoDelay mode"
#define E_UNSUPP "Unsupported input mode"
/* True input mode is inherited from terminal, we need a surely invalid
* value to be reset upon initialisation */
static int _input = -1;
#define IN_NODELAY (_input == INPUT_NODELAY)
static char _watch_fd = -1;
/**
* Input initialisation
*/
int INPUT_init()
{
INPUT_mode(INPUT_CBREAK);
INPUT_watch(0);
NODELAY_repeater_delay(1);
return 0;
}
/**
* Input cleanup
*/
void INPUT_exit()
{
/* If we are still in NoDelay mode, exit it */
if (IN_NODELAY) {
INPUT_mode(INPUT_CBREAK);
}
INPUT_watch(-1);
}
#define MY_DEBUG() fprintf(stderr, "in %s\n", __func__)
/**
* Begin watching the given fd (for read)
* @fd: fd to watch. -1 means to stop watching at all.
* This automatically stops watching the previously watched fd, if any
*/
static int INPUT_watch(int fd)
static void INPUT_watch(int fd)
{
MY_DEBUG();
if (fd == _watch_fd)
return 0;
return;
if (_watch_fd != -1)
GB.Watch(_watch_fd, GB_WATCH_NONE, NULL, 0);
if (fd == -1)
return 0;
return;
GB.Watch(fd, GB_WATCH_READ, INPUT_callback, 0);
_watch_fd = fd;
return 0;
}
/**
* Function to be called by Gambas when data arrives
* Params currently not used
*/
static void INPUT_callback(int fd, int flag, intptr_t arg)
{
MY_DEBUG();
/* if (IN_NODELAY)
NODELAY_change_pressed(NODELAY_get(-1));
else
*/ WINDOW_raise_read(NULL);
CWINDOW_raise_read(NULL);
}
/**
* Return or set the current input mode
* @mode: one of INPUT_* enums
*/
int INPUT_mode(int mode)
void INPUT_mode(CSCREEN *scr, int mode)
{
if (mode == INPUT_RETURN)
return _input;
if (mode == _input)
return 0;
if (IN_NODELAY)
NODELAY_exit();
if (mode == scr->input)
return;
switch (mode) {
case INPUT_COOKED:
@ -137,38 +90,18 @@ int INPUT_mode(int mode)
case INPUT_RAW:
raw();
break;
case INPUT_NODELAY:
if (NODELAY_init() == -1) {
GB.Error(E_NO_NODELAY);
/* We return 0 to not override the previous
* error message with the one emitted by the
* caller if we return error */
return 0;
}
break;
default:
GB.Error(E_UNSUPP);
return -1;
return;
}
_input = mode;
return 0;
scr->input = mode;
}
/**
* Drain the input queue
*/
void INPUT_drain()
{
if (IN_NODELAY)
NODELAY_drain();
else
flushinp();
flushinp();
}
/**
* Retrieve input from ncurses
*/
static int INPUT_get_ncurses(int timeout)
{
int ret;
@ -189,19 +122,12 @@ static int INPUT_get_ncurses(int timeout)
return ret;
}
/**
* Get a keypress within the given timeout
* @timeout: number of milliseconds to wait. If no key is pressed during it,
* 0 will be returned.
*/
int INPUT_get(int timeout)
{
if (IN_NODELAY)
return NODELAY_get(timeout);
else
return INPUT_get_ncurses(timeout);
return INPUT_get_ncurses(timeout);
}
#if 0
BEGIN_PROPERTY(Input_IsConsole)
int fd = NODELAY_consolefd();
@ -218,7 +144,7 @@ END_PROPERTY
BEGIN_PROPERTY(Input_RepeatDelay)
if (READ_PROPERTY) {
GB.ReturnInteger(NODELAY_repeater_delay(REPEATER_RETURN));
GB.ReturnInteger(NODELAY_repeater_delay(INPUT_RETURN));
return;
}
if (NODELAY_repeater_delay(VPROP(GB_INTEGER)) == -1) {
@ -227,6 +153,7 @@ BEGIN_PROPERTY(Input_RepeatDelay)
}
END_PROPERTY
#endif
GB_DESC CInputDesc[] = {
GB_DECLARE("Input", 0),
@ -237,12 +164,15 @@ GB_DESC CInputDesc[] = {
GB_CONSTANT("Cooked", "i", INPUT_COOKED),
GB_CONSTANT("CBreak", "i", INPUT_CBREAK),
GB_CONSTANT("Raw", "i", INPUT_RAW),
#if 0
GB_CONSTANT("NoDelay", "i", INPUT_NODELAY),
GB_STATIC_PROPERTY_READ("IsConsole", "b", Input_IsConsole),
GB_STATIC_PROPERTY("RepeatDelay", "i", Input_RepeatDelay),
#endif
};
#if 0
/*
* NODELAY routines
*/
@ -406,7 +336,7 @@ static inline void NODELAY_drain()
*/
static int NODELAY_repeater_delay(int val)
{
if (val == REPEATER_RETURN)
if (val == INPUT_RETURN)
return no_delay.delay;
if (val < 1)
return -1;
@ -698,3 +628,4 @@ cleanup:
tcsetattr(no_delay.fd, TCSANOW, &old);
return ret;
}
#endif

View File

@ -23,6 +23,8 @@
#ifndef __C_INPUT_H
#define __C_INPUT_H
#include "c_screen.h"
enum {
/* Return the current mode */
INPUT_RETURN = -1,
@ -32,41 +34,30 @@ enum {
INPUT_CBREAK,
/* No line discipline, no signal generation */
INPUT_RAW,
#if 0
/* Use terminal driver, enabled to use raw scancodes
(which are internally converted to ncurses keys but enable to
distinguish key press and release) */
INPUT_NODELAY
#endif
};
enum {
TIMEOUT_NOTIMEOUT = -1
};
enum {
REPEATER_RETURN = -1
};
#ifndef __C_INPUT_C
extern GB_DESC CInputDesc[];
#endif
int INPUT_init();
void INPUT_exit();
int INPUT_mode(int);
void INPUT_mode(CSCREEN *scr, int mode);
int INPUT_get(int);
void INPUT_drain();
#ifdef __C_INPUT_C
static int INPUT_watch(int);
static void INPUT_watch(int);
static void INPUT_callback(int, int, intptr_t);
static int NODELAY_init();
static int NODELAY_exit();
static void NODELAY_error_hook();
static int NODELAY_consolefd();
static inline void NODELAY_drain();
static int NODELAY_repeater();
static int NODELAY_repeater_delay(int);
static void NODELAY_change_pressed(int);
static int NODELAY_get(int);
#endif
#endif /* __C_INPUT_H */

View File

@ -1,7 +1,7 @@
/*
* c_key.c - gb.ncurses Key static class
*
* Copyright (C) 2012 Tobias Boege <tobias@gambas-buch.de>
* Copyright (C) 2012/3 Tobias Boege <tobias@gambas-buch.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -67,6 +67,8 @@ GB_DESC CKeyDesc[] = {
GB_CONSTANT("F11", "i", KEY_F(11)),
GB_CONSTANT("F12", "i", KEY_F(12)),
/* ncurses.h is full of other ones. Just tell me what you need. */
GB_STATIC_METHOD("_get", "i", Key_get, "(Key)s"),
GB_END_DECLARE

View File

@ -1,7 +1,7 @@
/*
* c_screen.c - gb.ncurses Screen class
*
* Copyright (C) 2012 Tobias Boege <tobias@gambas-buch.de>
* Copyright (C) 2012/3 Tobias Boege <tobias@gambas-buch.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -23,6 +23,7 @@
#include <stdio.h>
#include <signal.h>
#include <assert.h>
#include <ncurses.h>
#include <panel.h>
@ -33,76 +34,37 @@
#include "c_screen.h"
#include "c_input.h"
#define THIS ((CSCREEN *) _object)
#define IS_BUFFERED (THIS->buffered)
#define THIS _active
#define E_UNSUPP "Unsupported value"
static CSCREEN *active = NULL;
static CSCREEN *_active;
GB_SIGNAL_CALLBACK *_sigwinch_cb;
DECLARE_EVENT(EVENT_Read);
DECLARE_EVENT(EVENT_Resize);
/*
* Signal handler for the SIGWINCH signal.
* @signum: signal number given
* @arg: unused
* This routine dispatches the Resize Event
*/
static void SCREEN_sigwinch_handler(int signum, intptr_t arg)
static void SCREEN_sigwinch(int signum, intptr_t data)
{
/* TODO: ncurses may be configured to provide its own SIGWINCH
* handler. See resizeterm(3X). */
if (signum == SIGWINCH)
GB.Raise(active, EVENT_Resize, 0);
GB.Raise(_active, EVENT_Resize, 0);
}
/**
* Screen initialisation
*/
int SCREEN_init()
{
/* Global variable default setup */
CURSOR_mode(CURSOR_VISIBLE);
ECHO_mode(ECHO_NOECHO);
INPUT_init();
// _sigwinch_cb = GB.Signal.Register(SIGWINCH,
// SCREEN_sigwinch_handler, (intptr_t) NULL);
_sigwinch_cb = GB.Signal.Register(SIGWINCH, SCREEN_sigwinch,
(intptr_t) NULL);
return 0;
}
/**
* Screen cleanup
*/
void SCREEN_exit()
{
INPUT_exit();
// GB.Signal.Unregister(SIGWINCH, _sigwinch_cb);
GB.Signal.Unregister(SIGWINCH, _sigwinch_cb);
}
/**
* Get the active Screen
* If @active is NULL, the default Screen will be made active and then returned
*/
CSCREEN *SCREEN_get_active()
{
GB_CLASS screen_class;
if (active)
return active;
screen_class = GB.FindClass("Screen");
active = GB.AutoCreate(screen_class, 0);
return active;
}
/**
* Redraw the screen no matter what the buffer settings are.
* Note that this function may not be used to return into ncurses mode once left.
*/
void SCREEN_real_refresh()
void SCREEN_refresh()
{
if (!NCURSES_RUNNING)
return;
@ -110,210 +72,179 @@ void SCREEN_real_refresh()
doupdate();
}
/**
* Refresh the screen. This respects the currently active buffering wishes
*/
void SCREEN_refresh(void *_object)
{
if (!NCURSES_RUNNING)
return;
BEGIN_METHOD_VOID(Screen_init)
if (!_object)
_object = SCREEN_get_active();
_active = GB.AutoCreate(GB.FindClass("Screen"), 0);
if (!IS_BUFFERED)
SCREEN_real_refresh();
}
END_METHOD
/**
* Let the specified screen raise its Read event. If the _object is NULL,
* the currently active screen will raise. The latter case is the last
* resort for the difficulty of raising Read event in Window-Screen
* relation, while there need not be a focused window to raise this event,
* there is always an active screen.
*/
void SCREEN_raise_read(void *_object)
{
bool risen;
#if 0
BEGIN_METHOD(Screen_new, GB_STRING termpath)
if (!_object)
risen = GB.Raise(active, EVENT_Read, 0);
else
risen = GB.Raise(_object, EVENT_Read, 0);
char path[LENGTH(termpath) + 1];
FILE *finout;
/* Reduce watch callback calling overhead */
if (!risen)
INPUT_drain();
}
strncpy(path, STRING(termpath), LENGTH(termpath));
path[LENGTH(termpath)] = 0;
BEGIN_PROPERTY(Screen_Buffered)
if (READ_PROPERTY) {
GB.ReturnBoolean(IS_BUFFERED);
finout = fopen(path, "r+");
if (!finout) {
GB.Error(NULL);
return;
}
THIS->buffered = VPROP(GB_BOOLEAN);
assert(_maxscreen < MAX_SCREENS);
_screens[_maxscreen] = THIS;
THIS->index = _curscreen = _maxscreen++;
THIS->screen = newterm(NULL, finout, finout);
set_term(THIS->screen);
THIS->finout = finout;
THIS->buffered = 1;
CSCREEN_cursor(THIS, 0);
CSCREEN_echo(THIS, 0);
INPUT_mode(THIS, INPUT_CBREAK);
refresh();
END_PROPERTY
END_METHOD
BEGIN_METHOD_VOID(Screen_free)
void *dst, *src;
if (THIS->index != _maxscreen - 1) {
dst = &_screens[THIS->index];
src = dst + sizeof(_screens[0]);
memmove(dst, src, _maxscreen - THIS->index);
}
_screens[THIS->index] = NULL;
if (_curscreen)
_curscreen--;
_maxscreen--;
endwin();
fclose(THIS->finout);
delscreen(THIS->screen);
if (!_maxscreen) {
SCREEN_exit();
return;
}
set_term(_active->screen);
END_METHOD
#endif
BEGIN_METHOD_VOID(Screen_Refresh)
SCREEN_refresh();
END_METHOD
BEGIN_METHOD(Screen_Resize, GB_INTEGER lines; GB_INTEGER cols)
resizeterm(VARG(lines), VARG(cols));
END_METHOD
GB_DESC CCursorDesc[] = {
GB_DECLARE("Cursor", 0),
GB_NOT_CREATABLE(),
/* According to curs_set */
GB_CONSTANT("Hidden", "i", 0),
GB_CONSTANT("Visible", "i", 1),
GB_CONSTANT("VeryVisible", "i", 2),
GB_END_DECLARE
};
static int CSCREEN_cursor(CSCREEN *scr, int mode)
{
if (mode >= 0 && mode <= 2)
curs_set(mode);
else
return -1;
scr->cursor = mode;
return 0;
}
BEGIN_PROPERTY(Screen_Cursor)
if (READ_PROPERTY) {
GB.ReturnInteger(CURSOR_mode(CURSOR_RETURN));
GB.ReturnInteger(THIS->cursor);
return;
}
if (CURSOR_mode(VPROP(GB_INTEGER)) == -1)
if (CSCREEN_cursor(THIS, VPROP(GB_INTEGER)) == -1)
GB.Error(E_UNSUPP);
END_PROPERTY
static void CSCREEN_echo(CSCREEN *scr, int mode)
{
if (mode)
echo();
else
noecho();
scr->echo = mode;
}
BEGIN_PROPERTY(Screen_Echo)
if (READ_PROPERTY) {
GB.ReturnBoolean(ECHO_mode(ECHO_RETURN));
GB.ReturnBoolean(THIS->echo);
return;
}
if (ECHO_mode(!!VPROP(GB_BOOLEAN)) == -1)
GB.Error(E_UNSUPP);
CSCREEN_echo(THIS, !!VPROP(GB_BOOLEAN));
END_PROPERTY
BEGIN_PROPERTY(Screen_Input)
if (READ_PROPERTY) {
GB.ReturnInteger(INPUT_mode(INPUT_RETURN));
GB.ReturnInteger(THIS->input);
return;
}
if (INPUT_mode(VPROP(GB_INTEGER)) == -1)
GB.Error(E_UNSUPP);
INPUT_mode(THIS, VPROP(GB_INTEGER));
END_PROPERTY
BEGIN_PROPERTY(Screen_Lines)
GB.ReturnInteger(LINES);
if (READ_PROPERTY) {
GB.ReturnInteger(LINES);
return;
}
resizeterm(VPROP(GB_INTEGER), COLS);
END_PROPERTY
BEGIN_PROPERTY(Screen_Cols)
GB.ReturnInteger(COLS);
if (READ_PROPERTY) {
GB.ReturnInteger(COLS);
return;
}
resizeterm(LINES, VPROP(GB_INTEGER));
END_PROPERTY
BEGIN_METHOD_VOID(Screen_new)
active = THIS;
END_METHOD
BEGIN_METHOD_VOID(Screen_free)
/* TODO: for now, while Screen instantiation wouldn't do anything
* useful */
SCREEN_exit();
END_METHOD
BEGIN_METHOD_VOID(Screen_Refresh)
SCREEN_real_refresh();
END_METHOD
GB_DESC CScreenDesc[] = {
GB_DECLARE("Screen", sizeof(CSCREEN)),
GB_AUTO_CREATABLE(),
GB_NOT_CREATABLE(),
GB_EVENT("Read", NULL, NULL, &EVENT_Read),
GB_EVENT("Resize", NULL, NULL, &EVENT_Resize),
GB_PROPERTY("Buffered", "b", Screen_Buffered),
GB_STATIC_METHOD("_init", NULL, Screen_init, NULL),
GB_STATIC_METHOD("Refresh", NULL, Screen_Refresh, NULL),
GB_STATIC_METHOD("Resize", NULL, Screen_Resize, NULL),
GB_STATIC_PROPERTY("Cursor", "i", Screen_Cursor),
GB_STATIC_PROPERTY("Echo", "b", Screen_Echo),
GB_STATIC_PROPERTY("Input", "i", Screen_Input),
GB_STATIC_PROPERTY_READ("Lines", "i", Screen_Lines), //GB_PROPERTY
GB_STATIC_PROPERTY_READ("Cols", "i", Screen_Cols),
GB_METHOD("_new", NULL, Screen_new, NULL),
GB_METHOD("_free", NULL, Screen_free, NULL),
GB_METHOD("Refresh", NULL, Screen_Refresh, NULL),
GB_STATIC_PROPERTY("Height", "i", Screen_Lines),
GB_STATIC_PROPERTY("H", "i", Screen_Lines),
GB_STATIC_PROPERTY("Width", "i", Screen_Cols),
GB_STATIC_PROPERTY("W", "i", Screen_Cols),
GB_END_DECLARE
};
/*
* CURSOR routines
*/
static int _cursor;
/**
* Return or set cursor mode
* @mode: choose operation
*/
int CURSOR_mode(int mode)
{
switch (mode) {
case CURSOR_RETURN:
return _cursor;
case CURSOR_HIDDEN:
curs_set(0);
break;
case CURSOR_VISIBLE:
curs_set(1);
break;
case CURSOR_VERY:
curs_set(2);
break;
default:
return -1;
}
_cursor = mode;
return 0;
}
GB_DESC CCursorDesc[] = {
GB_DECLARE("Cursor", 0),
GB_NOT_CREATABLE(),
GB_CONSTANT("Hidden", "i", CURSOR_HIDDEN),
GB_CONSTANT("Visible", "i", CURSOR_VISIBLE),
GB_CONSTANT("Very", "i", CURSOR_VERY),
GB_END_DECLARE
};
/*
* ECHO routines
*/
static int _echo;
/**
* Return or set echo mode
* @mode: choose operation
*/
int ECHO_mode(int mode)
{
switch (mode) {
case ECHO_RETURN:
return _echo;
case ECHO_NOECHO:
noecho();
break;
case ECHO_ECHO:
echo();
break;
default:
return -1;
}
_echo = mode;
return 0;
}

View File

@ -19,39 +19,14 @@
* MA 02110-1301, USA.
*/
#ifndef __C_SCREEN_H
#define __C_SCREEN_H
#include "gambas.h"
#include "c_input.h"
#ifndef __C_SCREEN_H
#define __C_SCREEN_H
/* This will produce final output on terminal screen */
#define REAL_REFRESH() SCREEN_real_refresh()
/* This macro is mostly called by Gambas implementation functions to request output on screen
(read: to check if the output is buffered and if not produce output by means of
REAL_REFRESH()) */
#define REFRESH() SCREEN_refresh(NULL)
/* The Screen - like in ncurses - is the sole source of input */
#define SCREEN_get(t) INPUT_get(t)
/*
* Cursor modes
*/
enum {
CURSOR_RETURN = -1,
CURSOR_HIDDEN,
CURSOR_VISIBLE,
CURSOR_VERY
};
/*
* Echo modes
*/
enum {
ECHO_RETURN = -1,
ECHO_NOECHO,
ECHO_ECHO
};
#define REAL_REFRESH() SCREEN_refresh()
#ifndef __C_SCREEN_C
extern GB_DESC CScreenDesc[];
@ -60,18 +35,15 @@ extern GB_DESC CCursorDesc[];
typedef struct {
GB_BASE ob;
bool buffered; /* Whether output will be buffered, i.e.
only done via Screen.Refresh() */
int index;
int echo;
int cursor;
int input;
int buffered;
} CSCREEN;
int SCREEN_init();
void SCREEN_exit();
CSCREEN *SCREEN_get_active();
void SCREEN_refresh();
void SCREEN_real_refresh();
void SCREEN_raise_read(void *);
int CURSOR_mode(int);
int ECHO_mode(int);
#endif /* __C_SCREEN_H */

File diff suppressed because it is too large Load Diff

View File

@ -28,8 +28,6 @@
#include "gambas.h"
#include "gb_common.h"
#include "c_screen.h"
/* Border constants */
enum {
BORDER_NONE = 0,
@ -37,32 +35,17 @@ enum {
BORDER_ACS
};
/* @reqs for *_attrs_driver() */
enum
{
/* Return current attributes */
ATTR_DRV_RET,
/* Enable given attributes */
ATTR_DRV_ON,
/* Disable given attributes */
ATTR_DRV_OFF,
/* Set a color */
ATTR_DRV_COL
};
typedef struct {
GB_BASE ob;
CSCREEN *parent; /* The parent Screen */
WINDOW *main; /* The main window */
WINDOW *content; /* This window is used for all content-related operations. Its purpose is turning
the ncurses window borders which are inner-window to outer-window ones thus
separating border from content. If there is no border, this is the same as @main
otherwise a subwindow of it */
PANEL *pan; /* Panel of the main window to provide overlapping windows */
int border; /* What kind of border */
bool wrap; /* Whether text shall be truncated or wrapped on line ends */
char *caption; /* Text to be displayed in the main window if there is a border */
struct { /* This structure is used to pass a line and a column number to virtual objects */
WINDOW *main;
WINDOW *content;
PANEL *pan;
bool has_border;
int border;
bool buffered;
bool wrap;
char *caption;
struct {
int line;
int col;
} pos;
@ -75,6 +58,6 @@ extern GB_DESC CCharAttrsDesc[];
extern GB_DESC CBorderDesc[];
#endif
void WINDOW_raise_read(void *);
void CWINDOW_raise_read(CWINDOW *win);
#endif /* __C_WINDOW_C */

View File

@ -1,4 +1,3 @@
[Component]
Author=Tobias Boege
State=Unstable
State=Unfinished

View File

@ -1,7 +1,7 @@
/*
* main.c - gb.ncurses main object
*
* Copyright (C) 2012 Tobias Boege <tobias@gambas-buch.de>
* Copyright (C) 2012/3 Tobias Boege <tobias@gambas-buch.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -45,26 +45,17 @@ GB_DESC *GB_CLASSES[] EXPORT = {
CColorDesc,
CColorInfoDesc,
CPairDesc,
CPairInfoDesc,
NULL
};
static bool _init = FALSE;
/**
* Return if we are in ncurses mode
*/
bool MAIN_running()
{
return _init && (!isendwin() || stdscr);
}
/**
* Component-global initialisation
* Start ncurses and prepare stdscr. Call other relevant initialisation
* routines.
*/
static void MAIN_init()
{
if (_init)
@ -81,9 +72,6 @@ static void MAIN_init()
_init = TRUE;
}
/**
* Cleanup and exit ncurses
*/
static void MAIN_exit()
{
if (_init) {
@ -93,17 +81,11 @@ static void MAIN_exit()
}
}
/**
* Error hook
*/
static void MAIN_hook_error(int code, char *error, char *where)
{
MAIN_exit();
}
/**
* Main hook
*/
static void MAIN_hook_main(int *argc, char **argv)
{
MAIN_init();