[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:
parent
ff507f5dde
commit
cf20462abc
2
examples/examples/Games/Pong/.directory
Normal file
2
examples/examples/Games/Pong/.directory
Normal file
@ -0,0 +1,2 @@
|
||||
[Desktop Entry]
|
||||
Icon=./.icon.png
|
BIN
examples/examples/Games/Pong/.icon.png
Normal file
BIN
examples/examples/Games/Pong/.icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
15
examples/examples/Games/Pong/.project
Normal file
15
examples/examples/Games/Pong/.project
Normal 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
|
134
examples/examples/Games/Pong/.src/Ball.class
Normal file
134
examples/examples/Games/Pong/.src/Ball.class
Normal 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
|
191
examples/examples/Games/Pong/.src/MMain.module
Normal file
191
examples/examples/Games/Pong/.src/MMain.module
Normal 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
|
116
examples/examples/Games/Pong/.src/NPC.class
Normal file
116
examples/examples/Games/Pong/.src/NPC.class
Normal 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
|
96
examples/examples/Games/Pong/.src/Paddle.class
Normal file
96
examples/examples/Games/Pong/.src/Paddle.class
Normal 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
|
45
examples/examples/Games/Pong/SPEED
Normal file
45
examples/examples/Games/Pong/SPEED
Normal 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' ;-)
|
BIN
examples/examples/Games/Pong/pong.png
Normal file
BIN
examples/examples/Games/Pong/pong.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 204 B |
@ -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
|
||||
};
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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 */
|
||||
|
@ -1,4 +1,3 @@
|
||||
[Component]
|
||||
Author=Tobias Boege
|
||||
State=Unstable
|
||||
|
||||
State=Unfinished
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user