From cf20462abc7eb7b3a0ba7680f39b09f8ddab8037 Mon Sep 17 00:00:00 2001 From: Tobias Boege Date: Sun, 10 Feb 2013 20:06:36 +0000 Subject: [PATCH] [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 --- examples/examples/Games/Pong/.directory | 2 + examples/examples/Games/Pong/.icon.png | Bin 0 -> 3906 bytes examples/examples/Games/Pong/.project | 15 + examples/examples/Games/Pong/.src/Ball.class | 134 ++ .../examples/Games/Pong/.src/MMain.module | 191 ++ examples/examples/Games/Pong/.src/NPC.class | 116 ++ .../examples/Games/Pong/.src/Paddle.class | 96 + examples/examples/Games/Pong/SPEED | 45 + examples/examples/Games/Pong/pong.png | Bin 0 -> 204 bytes gb.ncurses/src/c_color.c | 392 ++-- gb.ncurses/src/c_color.h | 22 +- gb.ncurses/src/c_input.c | 117 +- gb.ncurses/src/c_input.h | 21 +- gb.ncurses/src/c_key.c | 4 +- gb.ncurses/src/c_screen.c | 325 ++-- gb.ncurses/src/c_screen.h | 46 +- gb.ncurses/src/c_window.c | 1689 ++++++----------- gb.ncurses/src/c_window.h | 37 +- gb.ncurses/src/gb.ncurses.component | 3 +- gb.ncurses/src/main.c | 20 +- 20 files changed, 1500 insertions(+), 1775 deletions(-) create mode 100644 examples/examples/Games/Pong/.directory create mode 100644 examples/examples/Games/Pong/.icon.png create mode 100644 examples/examples/Games/Pong/.project create mode 100644 examples/examples/Games/Pong/.src/Ball.class create mode 100644 examples/examples/Games/Pong/.src/MMain.module create mode 100644 examples/examples/Games/Pong/.src/NPC.class create mode 100644 examples/examples/Games/Pong/.src/Paddle.class create mode 100644 examples/examples/Games/Pong/SPEED create mode 100644 examples/examples/Games/Pong/pong.png diff --git a/examples/examples/Games/Pong/.directory b/examples/examples/Games/Pong/.directory new file mode 100644 index 000000000..06dab1c8a --- /dev/null +++ b/examples/examples/Games/Pong/.directory @@ -0,0 +1,2 @@ +[Desktop Entry] +Icon=./.icon.png diff --git a/examples/examples/Games/Pong/.icon.png b/examples/examples/Games/Pong/.icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9d902bf529bfb2d90d5292af4542fce5e69bed01 GIT binary patch literal 3906 zcmV-I554e-P)hD@DupSD(Zu@7xQWUSwgQi|{0m%|V4o5Z)DJpaExd%3_p-(vmVl?Wv_GbWc*;;Z^D^fj@LQBbDf|0R-=A7~ znfCxN{johDBvQZwOH+CLo-EF2#cvKlZD+6C`*Ehj&xu1-gw1ZA{7N)#6 zAT+3ic_Smh(Ga%vl`{a$&(`su)rjps+tRl3nIR<1e&Qh7(WJz6nd=Db9n+XZiz4DRRldO!;V23l(j8?>XraUnb@mz=K{ z?&Qz6w(42wBO?HM2`q0Bj6_AB2OI~>vUz*cLn#joy>?**I3p(jU~0=<`*P@#|VB4DA1AuG03q& z1T25Pg`I!gC92~(@tfCH477GjII`OStjP0X`O^oVi}M-xgK+hqG?YvfTw5Uk5VCd0 zxg#Cw@`tyIfBJoW=e(R~6&do5CVKp*_xVE#dLlk^sHVp@K0Rf2@2|E7)dMaiu1Nwy zw(g2Nb{tz9AzS#ph8pCs7`8mR`XPsG00u*j-%wJTO3LVqb-Y%fh8|048cHd@QfkPB z@tf4RVu-Spa{PwuRluMNQjFaS;MifRD?X;P`WW+9eiz3MBh{a2A4U#lKuT#EE~x^> z5Cw=aBEWHM_7=Z{o{`7&yd^YMm(tpBoa=7=`k2_iQb;|R0GD(EhBBn71TmNZrR;zql{D3mHa6%Toq!a=bB^=vVLu$?q?0M(coN7J6l!bR9<@gmHVn_%`B~3#~VGfM| zJ%SYQ);~VT55BpUhkvt~?XUlqU;J(t*5q7NR5YnB=oVo<+4D9={XtyW=|m@bF_awF zC3k3nr=&0qLrGJq!B?CsOacC`R$lp!LY~T;$ZL=O1>0YKiJWP9JpTM!obK}DPfo*k z{R&cV^7YL`qD~&gZ5ZQPbPZLTp`>X@!FdX}64?G0IPoSs{_;m`U$B5#ot?x8$^1FF z%wMyf{q13twsEXLFS9}rY^`TXTpC_q%(xOT)K4ierJL-Q#r zkL+Z2Qa#g_FDDL&PD`V{shOw$c@v?i7(!ti$Lz+j0t4}9TLE-!B^gOs7>4VjV~u$m z;-{gMX(*|?loSHaE&dnE0S#sQ>2iheJ3)>&*0FA8Do$z^FPGHw*pWv5>xJhj`NO-2 zoLRiMuZB~d0i-yWe6-eBr)!y$HHQgVGd_PHWg13oD& zA}6+sPIodrQ7I$~$-HUl9Bd2VXn5|$tvq=5T|_N=gp!lBG#soY=z!si!R|SWPzJ%K z8YTw9J@7e_0IdJibc>QgC@JV`VyIN!|KN4*S~8Ie zS0b&ZO;6B535~?T425yRVdRWO{9D13{Ac0MDcM_0hh@>--AQxNn^>K#SnZ9(HZ^eT zvIlW{Jm<;rLaleQnvEMbj);IrTSNVHDcxd7$7qs zZQ4ao?GfVUE}^HZgKjHKk}nQJNrVtgylE9Lyitf%@)oCrL5fH5%#w$wvn4~3$lB6jcI zeaZfV6`%(avH)wt3Rge^7*d!Kv4IqVV9<{@)PmzcTYMJ64ijvt$E>R)Hg^$cD~=Fr z2zHh?qssSV#3s^t{4;28BzDqVJd5w<+uwPXj7hUbwR8=K!oouG^Ybt0^s;5k28fEZ z6`2DJDNN{lJW{f^7*f4b5mJI6%<1|{N)H~u?CvHucOl*h*#z4fu-Y0)%giA)Wo zvGRRHh%EnApSl4w_@R#gLt+xafN~%JV00|CQqGJ0$^bVLY9B?A3hrdsQP z$L8ziE#@P_tY12ZKh#^4?JLF=HJh44#k6-cbIR$&tZhUkr6XM~`fVsFD6MN{e%=D! ze(N=E47F2Tx{q~tJwjY^#uYnJP*6ZoQPGG9h|Hsr#TE31K<_Fb1}DM(&$00d%*~j> z%P;*m#(`}lrljBq!8`A7#g0oxE?UW=6|3M(6Iu(j)&m==ZbNaPt`*npTj*)6=Z8=H zJ*AaC3f8P|i>eMAUcN}{kSt!m=vYws~RJsp2b6(PrA zR^I#(Idr9n^re3p1dx3>psx-faE>KVLt6IKJXX(Lh&$vZGd=+s<;4kE#5Y%Sn^$r7 z9rv*?E|%btJ!r>4^zHi#<-$5#%yk)=EOvwEbOR!!IDT{=R!`S?;|$kEi%45ioKv?U zBUS;aq}l&0XiEkupdSgzX)McMP1dmz-mI;~otj0L&@{I+a_5RK!^}BMJ-VMioj63Z zio%;c1C7QrdogDNJtRuW(wVcFIAs>qWrtCQ8khaR3o1ZF6hbbEsZ?*qloEBZ!esKy zxx_bD1E6D*C`-!bUtiorM@v0Du&{8T|||Z^#IcLMtt#5JKo^m(v4%A<)_0Q4w|}xc$Mf3^e4z2cGEvX=oZ0|Wr8fn2}` zxHKX{sOPt#ZoH7xFa^j91$>%wryV7Ps_y$R$^f&BbM7)p?u=;hv9Ck=b= zn7plI))gbva*os({PL}OwidV2-qJ+-{^#jB^2S&UaZyal%BHHR8N;1`CngOibcWPK zjSvv!HZJHqjG^Qwtl5k&eKOKenDr%`et!c_@a$Nbza*AEv;{}S<92%?P{zEe785cj zvEgr4U-Z5)dta^T-EWSSsSzP9B?gZX#I^%$dEr~Ee{~lrDWm^$^)-+G2lQjFT@^et QNB{r;07*qoM6N<$f(86rQ~&?~ literal 0 HcmV?d00001 diff --git a/examples/examples/Games/Pong/.project b/examples/examples/Games/Pong/.project new file mode 100644 index 000000000..096454c7f --- /dev/null +++ b/examples/examples/Games/Pong/.project @@ -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 " +TabSize=2 +Translate=1 +Language=en_GB +SourcePath=/home/tab/Desktop/exchg +Packager=1 diff --git a/examples/examples/Games/Pong/.src/Ball.class b/examples/examples/Games/Pong/.src/Ball.class new file mode 100644 index 000000000..f82275335 --- /dev/null +++ b/examples/examples/Games/Pong/.src/Ball.class @@ -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 diff --git a/examples/examples/Games/Pong/.src/MMain.module b/examples/examples/Games/Pong/.src/MMain.module new file mode 100644 index 000000000..3f012c666 --- /dev/null +++ b/examples/examples/Games/Pong/.src/MMain.module @@ -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 diff --git a/examples/examples/Games/Pong/.src/NPC.class b/examples/examples/Games/Pong/.src/NPC.class new file mode 100644 index 000000000..68e2389c9 --- /dev/null +++ b/examples/examples/Games/Pong/.src/NPC.class @@ -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 diff --git a/examples/examples/Games/Pong/.src/Paddle.class b/examples/examples/Games/Pong/.src/Paddle.class new file mode 100644 index 000000000..09a745fb3 --- /dev/null +++ b/examples/examples/Games/Pong/.src/Paddle.class @@ -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 diff --git a/examples/examples/Games/Pong/SPEED b/examples/examples/Games/Pong/SPEED new file mode 100644 index 000000000..e229fb9ce --- /dev/null +++ b/examples/examples/Games/Pong/SPEED @@ -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' ;-) diff --git a/examples/examples/Games/Pong/pong.png b/examples/examples/Games/Pong/pong.png new file mode 100644 index 0000000000000000000000000000000000000000..b58111cb933a09b2d7807590968fa7be89e11147 GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmSQK*5Dp-y;YjHK@;M7UB8wRq z_>O=u<5X=vX`o=9r;B4qMC;q>2e}#yc$|fA{{LTOvog3vu7o?O=+=S>?zeh-8CVvJ zEw^OYlB+1|IAIQ3g1-U-V@B!88^S?M9#%8szWaae72C6Pci1!rmA%FWhqg?wWn&U( uV0iQWz?t+2{c0vg4hM!e3`g$QAJ=}~FA{QFAYBn?GlQqApUXO@geCy{xj + * Copyright (C) 2012/3 Tobias Boege * * 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 }; diff --git a/gb.ncurses/src/c_color.h b/gb.ncurses/src/c_color.h index cd4a2839c..0b7a9a441 100644 --- a/gb.ncurses/src/c_color.h +++ b/gb.ncurses/src/c_color.h @@ -1,27 +1,13 @@ #ifndef __C_COLOR_H #define __C_COLOR_H -#include - -#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 */ diff --git a/gb.ncurses/src/c_input.c b/gb.ncurses/src/c_input.c index 8ec603490..4a240a588 100644 --- a/gb.ncurses/src/c_input.c +++ b/gb.ncurses/src/c_input.c @@ -1,7 +1,7 @@ /* * c_input.c - gb.ncurses opaque input routines * - * Copyright (C) 2012 Tobias Boege + * Copyright (C) 2012/3 Tobias Boege * * 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 #include +/* #include #include #include +*/ #include #include #include @@ -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 diff --git a/gb.ncurses/src/c_input.h b/gb.ncurses/src/c_input.h index da81285f5..839c0b3e5 100644 --- a/gb.ncurses/src/c_input.h +++ b/gb.ncurses/src/c_input.h @@ -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 */ diff --git a/gb.ncurses/src/c_key.c b/gb.ncurses/src/c_key.c index 0a375327f..90352925b 100644 --- a/gb.ncurses/src/c_key.c +++ b/gb.ncurses/src/c_key.c @@ -1,7 +1,7 @@ /* * c_key.c - gb.ncurses Key static class * - * Copyright (C) 2012 Tobias Boege + * Copyright (C) 2012/3 Tobias Boege * * 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 diff --git a/gb.ncurses/src/c_screen.c b/gb.ncurses/src/c_screen.c index 86ccd3484..d16e5e452 100644 --- a/gb.ncurses/src/c_screen.c +++ b/gb.ncurses/src/c_screen.c @@ -1,7 +1,7 @@ /* * c_screen.c - gb.ncurses Screen class * - * Copyright (C) 2012 Tobias Boege + * Copyright (C) 2012/3 Tobias Boege * * 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 #include +#include #include #include @@ -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; -} diff --git a/gb.ncurses/src/c_screen.h b/gb.ncurses/src/c_screen.h index 3183b0a9f..9767dc383 100644 --- a/gb.ncurses/src/c_screen.h +++ b/gb.ncurses/src/c_screen.h @@ -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 */ diff --git a/gb.ncurses/src/c_window.c b/gb.ncurses/src/c_window.c index 13a550a2b..349be8834 100644 --- a/gb.ncurses/src/c_window.c +++ b/gb.ncurses/src/c_window.c @@ -1,7 +1,7 @@ /* * c_window.c - gb.ncurses Window class * - * Copyright (C) 2012 Tobias Boege + * Copyright (C) 2012/3 Tobias Boege * * 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,996 +23,120 @@ #include #include -#include #include #include #include "gambas.h" -#include "gb_common.h" -#include "c_window.h" #include "main.h" +#include "c_window.h" #include "c_screen.h" #include "c_color.h" #define THIS ((CWINDOW *) _object) -#define HAS_BORDER (THIS->border != BORDER_NONE) -#define IS_WRAPPED (THIS->wrap) -/* Windows have their own association to a particular Screen, they don't - * update just the active one */ -#ifdef REFRESH -#undef REFRESH -/* Only refresh if we are on the active screen */ -#define REFRESH() \ - do { \ - if (SCREEN_get_active() == THIS->parent) \ - SCREEN_refresh(THIS->parent); \ - } while (0) -#endif +#define MAKE_THING(snip, win, a, b) \ +do { \ + if ((a) == -1) \ + a = get##snip##x(win); \ + if ((b) == -1) \ + b = get##snip##y(win); \ +} while (0) -/* Translate linear (absolute) memory addresses and x,y coordinates into each other - most useful when wrapping is needed. */ -#define A2XY(win, a, x, y) do { \ - (x) = (a) % getmaxx(win); \ - (y) = (a) / getmaxx(win); \ - } while (0) -#define XY2A(win, x, y, a) do { \ - (a) = (y) * getmaxx(win) + (x); \ - } while (0) -/* Interpret the -1 values in coordinates as to insert the current cursor position */ -#define MAKE_COORDS(win, x, y) do { \ - if ((x) == -1) \ - x = getcurx(win); \ - if ((y) == -1) \ - y = getcury(win); \ - } while (0) -/* Check for out-of-range coordinates */ -#define BAD_COORDS(win, x, y) ((x) < 0 || (x) >= getmaxx(win) || \ - (y) < 0 || (y) >= getmaxy(win)) -#define BAD_DIMENSION(w, h) ((w) <= 0 || (w) > COLS || \ - (h) <= 0 || (h) > LINES) +#define MAKE_CURSOR(win, x, y) MAKE_THING(cur, win, x, y) +#define MAKE_COORDS(win, x, y) MAKE_THING(beg, win, x, y) +#define MAKE_DIM(win, x, y) MAKE_THING(max, win, w, h) -#define WIN_ATTR_METHOD(a) \ - do { \ - if (READ_PROPERTY) \ - GB.ReturnBoolean(WINDOW_attrs_driver( \ - THIS, (a), ATTR_DRV_RET) & (a)); \ - else \ - WINDOW_attrs_driver(THIS, (a), \ - VPROP(GB_BOOLEAN) ? ATTR_DRV_ON \ - : ATTR_DRV_OFF); \ - } while (0) -/* Notice the wtouchln() line in the following macro. It seems that a chgat() from - WINDOW_char_attrs_driver() doesn't mark anything dirty (no output on screen from - a REFRESH()). So to make the new attribute available immidiately, we touch the affected - line manually. A higher-callstack function may call REFRESH() to get output. */ -#define CHAR_ATTR_METHOD(a) \ - do { \ - if (READ_PROPERTY) \ - GB.ReturnBoolean(WINDOW_char_attrs_driver( \ - THIS, (a), THIS->pos.col, THIS->pos.line, \ - ATTR_DRV_RET) & (a)); \ - else \ - WINDOW_char_attrs_driver(THIS, (a), THIS->pos.col, \ - THIS->pos.line, \ - VPROP(GB_BOOLEAN) ? ATTR_DRV_ON \ - : ATTR_DRV_OFF); \ - wtouchln(THIS->main, THIS->pos.line \ - + (HAS_BORDER ? 1 : 0), 1, 1); \ - } while(0) +#define CHECK_RAISE_THING(snip, win, a, b) \ +if ((a) < 0 || (a) > get##snip##x(win) \ + || (b) < 0 || (b) > get##snip##y(win)) { /* >= ? */ \ + GB.Error(GB_ERR_BOUND); \ + return; \ +} -#define WINDOW_main_to_content() WINDOW_copy_window(THIS->main, THIS->content, 0, 0, \ - getmaxx(THIS->content), \ - getmaxy(THIS->content), 0, 0) -#define WINDOW_content_to_main() WINDOW_copy_window(THIS->content, THIS->main, 0, 0, \ - getmaxx(THIS->content), \ - getmaxy(THIS->content), 0, 0) +#define CHECK_RAISE_COORDS(win, x, y) CHECK_RAISE_THING(max, win, x, y) +#define CHECK_RAISE_DIM(win, x, y) CHECK_RAISE_THING(max, win, x, y) -/* The window currently having the focus (raising Read events) */ -static CWINDOW *focused = NULL; +static CWINDOW *_curwin = NULL; DECLARE_EVENT(EVENT_Read); -/* - * C Window interface - * @_object: Reference to the CWINDOW representing the current object. - * - * The theory: Each window has a main and a content window pointer. The main window - * represents the window object outwards. It is linked to a panel structure which - * is managed by the ncurses panel extension library to allow overlapping windows. - * One aim of this design is to turn the ncurses-style inner-window border - * into an outer-window border thus separating the graphics from the content so that the user - * can access the window dimensions specified upon object instanciation whatever border-settings - * the window may have and does not accidentally overwrite the border. - * This is achieved by creating a dedicated content window accessed via the content member - * of the structure. If there is no border (the border member is zero), the content window - * is the same as the main window, both pointers are equal. If there is a border, a new - * content window will be created which has the exact same size and content as the main window - * has, the main window is enlarged to provide a border around the content. - * Technically: the new content window is a subwindow of the enlarged main window so that they - * share memory. All operations on the content window (wherever it points to) affects the memory - * of the main window. The content windows are syncok()ed to their parent windows so that - * any changes are immediately available to the latter and consequently to the physical screen upon - * the next window refresh, that is the update_panel(); doupdate(); sequence of statements which - * also takes care of window overlapping. - */ +/* 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() CWINDOW_refresh(THIS) -#define E_COORDS "Coordinates out of range" -#define E_DIMENSION "Dimensions do not fit on screen" - -/** - * Copies text with attributes from a window to a newly malloced array as if the window - * was linear memory, too (line by line) - this is mainly used by wrapping code. - * @src: source window - * @arrp: pointer to store the newly malloced pointer containing the data in - * @x: x position - * @y: y position to start - * @len: number of characters to read - */ -static int WINDOW_get_mem(WINDOW *src, chtype **arrp, int sx, int sy, int len) +static void CWINDOW_refresh(CWINDOW *win) { - int i; - int ox, oy; - chtype ch; - - getyx(src, oy, ox); - MAKE_COORDS(src, sx, sy); - if (BAD_COORDS(src, sx, sy)) { - GB.Error(E_COORDS); - return -1; - } - len = MinMax(len, 0, (getmaxy(src) - sy) * getmaxx(src) - sx); - - GB.Alloc((void **) arrp, len * sizeof(chtype)); - for (i = 0; i < len; i++) { - ch = mvwinch(src, sy, sx); - (*arrp)[i] = ch; - if (++sx >= getmaxx(src)) { - sy++; - sx = 0; - } - } - - wmove(src, oy, ox); - return 0; -} - -/** - * Copies text with attributes from memory to a window, temporarily turning off any additional - * attributes the destination window may have. - * @arr: data source - * @dst: destination window - * @sx: starting x - * @sy: starting y coordinate - * @len: length of data to copy from @arr - */ -static int WINDOW_put_mem(chtype *arr, WINDOW *dst, int sx, int sy, unsigned int len) -{ - int i; - int a; - int attrs = getattrs(dst); - - MAKE_COORDS(dst, sx, sy); - if (BAD_COORDS(dst, sx, sy)) { - GB.Error(E_COORDS); - return -1; - } - XY2A(dst, sx, sy, a); - len = MinMax(len, 0, getmaxy(dst) * getmaxx(dst) - a); - - wmove(dst, sy, sx); - /* addch() ORs the current attributes but we want the chtypes drawn as they are in the buffer */ - wattrset(dst, A_NORMAL); - for (i = 0; i < len; i++) - waddch(dst, arr[i]); - wattrset(dst, attrs); - return 0; -} - -/** - * Copy the specified rectangle of text - * @src: source window - * @dst: destination window - * @sx: source starting x - * @sy: source starting y - * @nx: number of columns from @sx - * @ny: number of lines from @sy - * @dx: destination starting x - * @dy: destinatino starting y - */ -static int WINDOW_copy_window(WINDOW *src, WINDOW *dst, int sx, int sy, int nx, int ny, int dx, int dy) -{ - int i, j; - chtype *chbuf; /* We ought to have a separate buffer in case @src and @dst overlap */ - int dattrs = getattrs(dst); - int ox, oy; - - MAKE_COORDS(src, sx, sy); - MAKE_COORDS(dst, dx, dy); - if (BAD_COORDS(src, sx, sy) || BAD_COORDS(dst, dx, dy)) { - GB.Error(E_COORDS); - return -1; - } - if (BAD_COORDS(src, sx + nx - 1, sy + ny - 1) || - BAD_COORDS(dst, dx + nx - 1, dy + ny - 1)) { - GB.Error(E_COORDS); - return -1; - } - - GB.Alloc((void **) &chbuf, nx * ny * sizeof(chtype)); - getyx(src, oy, ox); - for (i = 0; i < ny; i++) - for (j = 0; j < nx; j++) - chbuf[i * nx + j] = mvwinch(src, sy + i, sx + j); - wmove(src, oy, ox); - - getyx(dst, oy, ox); - wattrset(dst, A_NORMAL); - for (i = 0; i < ny; i++) { - if (dy + i >= getmaxy(dst)) break; - wmove(dst, dy + i, dx); - for (j = 0; j < nx; j++) - waddch(dst, chbuf[i * nx + j]); - } - wattrset(dst, dattrs); - wmove(dst, oy, ox); - GB.Free((void **) &chbuf); - return 0; -} - -/** - * Unlink and deallocate the main panel together with the window and, if present, the - * content window and caption, refresh the screen to immediately remove leftovers of - * the window. - */ -static int WINDOW_remove(void *_object) -{ - int by, h; - - by = getbegy(THIS->main); - h = getmaxy(THIS->main); - wclear(THIS->content); - if (HAS_BORDER) { - delwin(THIS->content); - wclear(THIS->main); - } - if (THIS->caption) { - GB.FreeString(&THIS->caption); - THIS->caption = NULL; - } - del_panel(THIS->pan); - delwin(THIS->main); - wtouchln(stdscr, by, h, 1); - return 0; -} - -/** - * Create a content window - * The contents of the main window are copied to the newly created content window. - */ -static int WINDOW_add_content(void *_object) -{ - WINDOW *new; - - if (HAS_BORDER) - return 0; - new = derwin(THIS->main, getmaxy(THIS->main) - 2, getmaxx(THIS->main) - 2, 1, 1); - keypad(new, TRUE); - syncok(new, TRUE); - THIS->content = new; - /* Copy main window contents, the library only provides overwrite() and friends for - this purpose but the windows do not overlap entirely as required by these functions */ - WINDOW_main_to_content(); - /* The main window may not have any additional attributes but the content window */ - wattrset(new, getattrs(THIS->main)); - wattrset(THIS->main, A_NORMAL); - return 0; -} - -/** - * Remove a content window - * Free the memory taken up by the content window, substitute its pointer with the - * main window pointer. Textual content in the content window and its attributes are copied - * to the main window. - */ -static int WINDOW_remove_content(void *_object) -{ - if (!HAS_BORDER) - return 0; - WINDOW_content_to_main(); - wattrset(THIS->main, getattrs(THIS->content)); - delwin(THIS->content); - THIS->content = THIS->main; - return 0; -} - -/** - * Draws an inner-window border to the main window which appears as - * outer-window for the content. If a caption was set for the window and the - * border is to be drawn, also the caption is. - * @b: one of the BORDER_* constants - */ -static int WINDOW_draw_border(void *_object, bool b) -{ - int width; - switch (b) { - case BORDER_NONE: - wborder(THIS->main, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); - break; - case BORDER_ASCII: - wborder(THIS->main, '|', '|', '-', '-', '+', '+', '+', '+'); - break; - case BORDER_ACS: - box(THIS->main, 0, 0); - break; - default: - return -1; - } - if (b && THIS->caption) { - width = MIN(getmaxx(THIS->main) - 1, - strlen(THIS->caption)); - mvwaddnstr(THIS->main, 0, 1, THIS->caption, width); - } - return 0; -} - -/** - * Move the cursor associated with the content window. - * @x: x position - * @y: y position relative to the upper left corner of the content window - * Either of the parameters may be -1 which indicates to not change the current - * value - */ -static int WINDOW_cursor_move(void *_object, int x, int y) -{ - MAKE_COORDS(THIS->content, x, y); - if (BAD_COORDS(THIS->content, x, y)) { - GB.Error(E_COORDS); - return -1; - } - - if (wmove(THIS->content, y, x) == ERR) { - GB.Error("Could not move cursor"); - return -1; - } - return 0; -} - -/** - * Move the entire window on screen. - * @x: new x coordinate - * @y: new y coordinate of the upper left corner of the main window relative to the - * screen. Again, -1 denotes to leave the value as is - */ -static int WINDOW_move(void *_object, int x, int y) -{ - int ox, oy; - - getbegyx(THIS->main, oy, ox); - if (x == -1) - x = ox; - if (y == -1) - y = oy; - if (BAD_COORDS(stdscr, x, y)) { - GB.Error(E_COORDS); - return -1; - } - - move_panel(THIS->pan, y, x); - if (HAS_BORDER) { - mvwin(THIS->content, y + 1, x + 1); - WINDOW_draw_border(THIS, 1); - } - return 0; -} - -/** - * Resize the whole window. An enlarged content window is filled with spaces, - * whereas a shortened content window gets truncated with respect to its 0,0 - * upper left corner. - * @w: new width - * @h: new height of the content window. - * The main window is resized accordingly. Values of -1 prevent the present - * dimensions from being altered - */ -static int WINDOW_resize(void *_object, int w, int h) -{ - int ow, oh; - - getmaxyx(THIS->content, oh, ow); - if (w == -1) - w = ow; - if (h == -1) - h = oh; - - if (HAS_BORDER) { - if ((w + 2) <= 0 || (w + 2) > COLS || - (h + 2) <= 0 || (h + 2) > LINES) { - GB.Error(E_DIMENSION); - return -1; - } - - WINDOW_draw_border(THIS, 0); - wresize(THIS->main, h + 2, w + 2); - } - - if (w <= 0 || w > COLS || h <= 0 || h > LINES) { - GB.Error(E_DIMENSION); - return -1; - } - wresize(THIS->content, h, w); - replace_panel(THIS->pan, THIS->main); - - if (HAS_BORDER) - WINDOW_draw_border(THIS, 1); - return 0; -} - -/** - * Print a given string in the content window starting at x,y position overwriting what is - * already there. - * @str: the string to print - * @x: x coordinate - * @y: y coordinate relative to the upper left corner of the content window - * The principle of -1 arguments for x,y as described previously applies also to this function. - * A set wrapping option causes @str to wrap around to the next line if it doesn't fit. Otherwise - * it is truncated at line's end - */ -static int WINDOW_print(void *_object, char *str, int x, int y) -{ - int width; - char *p, *q; - - p = str; - do { - if (WINDOW_cursor_move(THIS, x, y) == -1) - return -1; - width = strlen(p); - if (!IS_WRAPPED) - width = MIN(width, getmaxx(THIS->content) - x); - - /* waddnstr, as being subsequent calls to waddch, - * continuously overrides the last character in a window - * after reached that end. But we want a clear cut there */ - width = MIN(width, getmaxx(THIS->content) * - (getmaxy(THIS->content) - y) - x); - if ((q = strchr(p, '\n'))) - width = MIN(width, q - p); - waddnstr(THIS->content, p, width); - p += width; - x = getcurx(THIS->content); - y = getcury(THIS->content); - if (y == getmaxy(THIS->content) - 1) - break; - if (*p == '\n') { - y++; - p++; - } - if (*p) - x = 0; - } while (*p); - WINDOW_cursor_move(THIS, x, y); - return 0; -} - -/** - * Insert a given string before the cursor position denoted by x,y and shift what follows it - * @str: string to insert - * @x: x coordinate - * @y: y coordinate - * -1 as coordinate value means to leave the current value set. - * If wrapping is set for the window, the entire content, which means all lines, are shifted. If wrapping - * was turned off, only the current line is shifted but not wrapped around if the end is reached. - */ -static int WINDOW_insert(void *_object, char *str, int x, int y) -{ - int a, i, len, slen; - chtype *ins, *shifted; - - if (WINDOW_cursor_move(THIS, x, y) == -1) - return -1; - if (!THIS->wrap) { - winsstr(THIS->content, str); - return 0; - } - - x = getcurx(THIS->content); - y = getcury(THIS->content); - XY2A(THIS->content, x, y, a); - len = strlen(str); - slen = getmaxy(THIS->content) * getmaxx(THIS->content) - a - len + 1; - GB.Alloc((void **) &ins, len * sizeof(chtype)); - for (i = 0; i < len; i++) - ins[i] = (chtype) str[i] | getattrs(THIS->content); - WINDOW_get_mem(THIS->content, &shifted, x, y, getmaxy(THIS->content) * getmaxx(THIS->content) - a); - - WINDOW_put_mem(ins, THIS->content, x, y, len); - getyx(THIS->content, y, x); - WINDOW_put_mem(shifted, THIS->content, x, y, slen); - - /* place the cursor after the last inserted char */ - WINDOW_cursor_move(THIS, x, y); - - GB.Free((void **) &shifted); - GB.Free((void **) &ins); - return 0; -} - -/** - * Get a string from the content window starting at x,y - * @x: x coordinate - * @y: y coordinate to start reading from - * @len: length of string to read - * @ret: to store a newly malloced pointer containing the string from @x,@y and of length @len - * (or what it implied) in - * @x and @y may be -1. If @len is -1 we shall read until the end of line. - * The cursor position is reset after the operation. - */ -static int WINDOW_get_str(void *_object, int x, int y, unsigned int len, char **ret) -{ - int i; - chtype *chbuf; - char *buf; - - if (len == -1) - len = getmaxx(THIS->content) - getcurx(THIS->content); - - GB.Alloc((void **) &buf, len + 1); - WINDOW_get_mem(THIS->content, &chbuf, x, y, len); - for (i = 0; i < len; i++) - buf[i] = chbuf[i] & A_CHARTEXT; - buf[len] = 0; - GB.Free((void **) &chbuf); - - *ret = buf; - return 0; -} - -/** - * Wait for a keypress for the given amount of time - * @timeout: gives the number of milliseconds for a timeout. If the timeout expires, - * 0 will be delivered back. A negative value denotes to not use any timeout. - * @ret: the key value (or 0 in case of timeout expiration) will be stored at this address. - */ -static int WINDOW_key_timeout(void *_object, int timeout, int *ret) -{ - *ret = SCREEN_get(timeout); - return 0; -} - -/** - * Read an entire string form the input queue - * @ret: the pointer to a newly malloced string will be stored there - * This function behaves like getstr(3X). Note that getstr() being a - * sequence of getch(), we must stick to its characteristics, too, i.e. - * beep() when there is a non-printable character typed in and echo all - * characters if we echo. - */ -static int WINDOW_readline(void *_object, char **ret) -{ - int key; - int i, j; - char *line = NULL, *p, c; - - i = j = 0; - while (1) { - if (!(i & 256)) { - if (!(p = realloc(line, (++j * 256) + 1))) { - free(line); - return -1; - } - line = p; - } - key = SCREEN_get(TIMEOUT_NOTIMEOUT); - c = (char) key; - if (c == '\n' || c == '\r') - break; - if (key == KEY_BACKSPACE || key == KEY_LEFT) { - if (i > 0) - i--; - continue; - } - if ((c < 32 && !isspace(c)) || key > 127) { - beep(); - continue; - } - - line[i++] = c; - if (ECHO_mode(ECHO_RETURN)) { - line[i] = 0; - WINDOW_print(THIS, line + i - 1, -1, -1); - } - } - line[i] = 0; - *ret = line; - return 0; -} - -/** - * Drain the input queue - */ -static void WINDOW_drain() -{ - INPUT_drain(); -} - -/** - * Move the main panel to the bottom of the panel stack thus arrange it - * below all other windows that may overlap it - */ -static int WINDOW_bottom(void *_object) -{ - bottom_panel(THIS->pan); - return 0; -} - -/** - * Move the main panel to the top of the panel stack - */ -static int WINDOW_top(void *_object) -{ - top_panel(THIS->pan); - return 0; -} - -/** - * Remove the main panel from the panel stack thus hiding it from the user - */ -static int WINDOW_hide(void *_object) -{ - hide_panel(THIS->pan); - return 0; -} - -/** - * Insert the main panel into the panel stack. note that the panel is moved to the top - * of the stack thus making it "the most" visible - */ -static int WINDOW_show(void *_object) -{ - show_panel(THIS->pan); - return 0; -} - -/** - * Raise the Window_Read event of the given window. If _object is NULL, - * the currently focused window is used. The event is, however, only risen, - * if the window can raise events. Otherwise let the parent screen raise the - * event. If there is not even a parent screen accessible, use the active - * screen. - */ -void WINDOW_raise_read(void *_object) -{ - if (!_object) - _object = focused; - - if (_object && GB.CanRaise(_object, EVENT_Read)) - GB.Raise(_object, EVENT_Read, 0); - else - SCREEN_raise_read(_object ? THIS->parent : NULL); -} - -/** - * Bring the given window to focus. That means that this window now raises the - * Read event whenever data arrives at the input queue _and_ the window can - * raise events. The global variable @focused is used to keep track of that - * very window. - */ -static int WINDOW_setfocus(void *_object) -{ - if (focused) - GB.Unref((void **) &focused); - focused = THIS; - GB.Ref((void *) focused); - /* We watch since SCREEN_init() */ - return 0; -} - -/** - * Import a window and fill the @_object with default values (actual object instanciation) - * @imp: WINDOW to import - */ -static int WINDOW_import(void *_object, WINDOW *imp) -{ - /* Clean up former members */ - if (HAS_BORDER) - WINDOW_remove_content(THIS); - if (THIS->main) - WINDOW_remove(THIS); - - THIS->main = imp; - THIS->pan = new_panel(imp); - keypad(imp, TRUE); - THIS->border = FALSE; - THIS->wrap = TRUE; - THIS->content = THIS->main; - return 0; -} - -/** - * Return the state of, set or unset a given attribute - * @attr: attribute subject - * @req: the operation to perform. One of ATTR_DRV_*, watch the source on what they do - * in particular - * This routine works with "normal" attributes and colors indifferently (as the latter are - * attributes) - */ -static int WINDOW_attrs_driver(void *_object, int attr, int req) -{ - switch (req) { - case ATTR_DRV_RET: - return getattrs(THIS->content); - case ATTR_DRV_ON: - if (attr == A_NORMAL) - wattrset(THIS->content, A_NORMAL); - else - wattron(THIS->content, attr); - break; - case ATTR_DRV_OFF: - wattroff(THIS->content, attr); - break; - case ATTR_DRV_COL: - wbkgd(THIS->content, attr | ' '); - } - return 0; -} - -/** - * Return the state of, set or unset a given attribute on a single character - * @attr: attribute - * @x: x coordinate - * @y: y coordinate - * @req: request to perform - * As this is the character-based counterpart to WINDOW_attrs_driver, this - * also handles colors - */ -static int WINDOW_char_attrs_driver(void *_object, int attr, int x, int y, int req) -{ - int ox, oy; - int res; - chtype ch; - - /* Wish the attribute shift stuff was documented... - For posterity: It's all in */ - - getyx(THIS->content, oy, ox); - WINDOW_cursor_move(THIS, x, y); - ch = winch(THIS->content); - switch (req) { - case ATTR_DRV_RET: - res = ch & A_ATTRIBUTES; - goto cleanup; - case ATTR_DRV_ON: - if (attr == A_NORMAL) - wchgat(THIS->content, 1, A_NORMAL, PAIR_NUMBER(ch), NULL); - else - wchgat(THIS->content, 1, (ch & A_ATTRIBUTES) | attr, PAIR_NUMBER(ch), NULL); - break; - case ATTR_DRV_OFF: - wchgat(THIS->content, 1, (ch & A_ATTRIBUTES) & ~attr, PAIR_NUMBER(ch), NULL); - break; - case ATTR_DRV_COL: - wchgat(THIS->content, 1, (ch & A_ATTRIBUTES), PAIR_NUMBER(attr), NULL); - } - - res = 0; - cleanup: - WINDOW_cursor_move(THIS, ox, oy); - return res; -} - -/* - * Window class - */ - -BEGIN_PROPERTY(Window_Background) - - short pair; - short f, b; - - pair = PAIR_NUMBER(getbkgd(THIS->content)); - pair_content(pair, &f, &b); - if (READ_PROPERTY) { - GB.ReturnInteger(b); + if (win->buffered) return; - } - b = VPROP(GB_INTEGER); - if (!COLOR_VALID(b)) { - GB.Error(GB_ERR_BOUND); - return; - } - COLOR_setpair(pair, f, b); - wbkgd(THIS->content, COLOR_PAIR(pair) | ' '); - REFRESH(); + REAL_REFRESH(); +} -END_PROPERTY - -BEGIN_PROPERTY(Window_Border) - - int b; - int x, y, w, h; - - if (READ_PROPERTY) { - GB.ReturnInteger(THIS->border); - return; +void CWINDOW_raise_read(CWINDOW *win) +{ + if (!win) { + if (!_curwin) + return; + win = _curwin; } - b = VPROP(GB_INTEGER); + if (GB.CanRaise(win, EVENT_Read)) + GB.Raise(win, EVENT_Read, 0); +} - if (b == THIS->border) - return; - - if (b) { - WINDOW_resize(THIS, (w = getmaxx(THIS->main) + 2) > COLS ? getmaxx(THIS->main) : w, - (h = getmaxy(THIS->main) + 2) > LINES ? getmaxy(THIS->main) : h); - WINDOW_move(THIS, (x = getbegx(THIS->main) - 1) < 0 ? 0 : x, - (y = getbegy(THIS->main) - 1) < 0 ? 0 : y); - WINDOW_add_content(THIS); - WINDOW_draw_border(THIS, 1); +static void CWINDOW_from_ncurses(CWINDOW *win, WINDOW *ncwin, bool border) +{ + win->main = ncwin; + win->pan = new_panel(ncwin); + keypad(ncwin, TRUE); + win->has_border = border; + win->border = 0; + win->buffered = 0; + win->wrap = 1; + if (border) { + WINDOW *new = derwin(ncwin, getmaxy(ncwin) - 2, + getmaxx(ncwin) - 2, + 1, 1); + syncok(new, TRUE); + win->content = new; } else { - WINDOW_draw_border(THIS, 0); - /* as long as we have control over the area taken up (before resize), we shall erase - the whole border */ - REAL_REFRESH(); - WINDOW_remove_content(THIS); - /* since HAS_BORDER is still TRUE, resize and move would draw a new border, we prevent this */ - THIS->border = 0; - WINDOW_resize(THIS, getmaxx(THIS->content) - 2, getmaxy(THIS->content) - 2); - WINDOW_move(THIS, (x = getbegx(THIS->main) + 1) >= getmaxx(THIS->main) ? getmaxx(THIS->main) - 1 : x, - (y = getbegy(THIS->main) + 1) >= getmaxy(THIS->main) ? getmaxy(THIS->main) - 1 : y); + win->content = win->main; } - THIS->border = b; - REFRESH(); + win->caption = NULL; +} -END_PROPERTY - -BEGIN_PROPERTY(Window_Caption) - - if (READ_PROPERTY) { - if (!THIS->caption) - GB.ReturnNull(); - else - GB.ReturnString(THIS->caption); - return; - } - - THIS->caption = GB.NewZeroString(PSTRING()); - if (HAS_BORDER) { - WINDOW_draw_border(THIS, 1); - REFRESH(); - } - -END_PROPERTY - -BEGIN_PROPERTY(Window_CursorX) - - if (READ_PROPERTY) { - GB.ReturnInteger(getcurx(THIS->content)); - return; - } - WINDOW_cursor_move(THIS, VPROP(GB_INTEGER), -1); - REFRESH(); - -END_PROPERTY - -BEGIN_PROPERTY(Window_CursorY) - - if (READ_PROPERTY) { - GB.ReturnInteger(getcury(THIS->content)); - return; - } - WINDOW_cursor_move(THIS, -1, VPROP(GB_INTEGER)); - REFRESH(); - -END_PROPERTY - -BEGIN_PROPERTY(Window_Foreground) - - short pair; - short f, b; - - pair = PAIR_NUMBER(getbkgd(THIS->content)); - pair_content(pair, &f, &b); - if (READ_PROPERTY) { - GB.ReturnInteger(f); - return; - } - f = VPROP(GB_INTEGER); - if (!COLOR_VALID(f)) { - GB.Error(GB_ERR_BOUND); - return; - } - COLOR_setpair(pair, f, b); - wbkgd(THIS->content, COLOR_PAIR(pair) | ' '); - REFRESH(); - -END_PROPERTY - -BEGIN_PROPERTY(Window_Height) - - if (READ_PROPERTY) { - GB.ReturnInteger(getmaxy(THIS->content)); - return; - } - WINDOW_resize(THIS, -1, VPROP(GB_INTEGER)); - REFRESH(); - -END_PROPERTY - -BEGIN_PROPERTY(Window_Wrap) - - /* This property only affects subsequent prints */ - if (READ_PROPERTY) { - GB.ReturnBoolean(THIS->wrap); - return; - } - THIS->wrap = VPROP(GB_BOOLEAN); - -END_PROPERTY - -BEGIN_PROPERTY(Window_Width) - - if (READ_PROPERTY) { - GB.ReturnInteger(getmaxx(THIS->content)); - return; - } - WINDOW_resize(THIS, VPROP(GB_INTEGER), -1); - REFRESH(); - -END_PROPERTY - -BEGIN_PROPERTY(Window_X) - - if (READ_PROPERTY) { - GB.ReturnInteger(getbegx(THIS->main)); - return; - } - WINDOW_move(THIS, VPROP(GB_INTEGER), -1); - REFRESH(); - -END_PROPERTY - -BEGIN_PROPERTY(Window_Y) - - if (READ_PROPERTY) { - GB.ReturnInteger(getbegy(THIS->main)); - return; - } - WINDOW_move(THIS, -1, VPROP(GB_INTEGER)); - REFRESH(); - -END_PROPERTY - -BEGIN_METHOD(Window_new, GB_OBJECT parent; GB_INTEGER x; GB_INTEGER y; GB_INTEGER w; GB_INTEGER h) +BEGIN_METHOD(Window_new, GB_BOOLEAN out_border; GB_INTEGER x; GB_INTEGER y; + GB_INTEGER w; GB_INTEGER h) WINDOW *new; + int w, h; - if (!NCURSES_RUNNING) { - GB.Error("Not in NCurses mode"); - return; + w = VARGOPT(w, COLS); + h = VARGOPT(h, LINES); + if (VARGOPT(out_border, 1)) { + w = MIN(w + 2, COLS); + h = MIN(h + 2, LINES); } - new = newwin(VARGOPT(h, LINES), VARGOPT(w, COLS), - VARGOPT(y, 0), VARGOPT(x, 0)); - WINDOW_import(THIS, new); - - THIS->parent = VARGOPT(parent, SCREEN_get_active()); - + new = newwin(h, w, VARGOPT(y, 0), VARGOPT(x, 0)); + CWINDOW_from_ncurses(THIS, new, VARGOPT(out_border, 1)); REFRESH(); END_METHOD BEGIN_METHOD_VOID(Window_free) - WINDOW_remove(THIS); - if (focused == THIS) { - GB.Watch(0, GB_WATCH_NONE, NULL, 0); - focused = NULL; + if (_curwin == THIS) { + _curwin = NULL; + INPUT_exit(); } - GB.Detach(THIS); - /* the REFRESH() makes use of THIS so it would be unwise to call that - since we just invalidated it */ + del_panel(THIS->pan); + if (THIS->has_border) + delwin(THIS->content); + delwin(THIS->main); + if (THIS->caption) + GB.FreeString(&THIS->caption); REAL_REFRESH(); END_METHOD @@ -1027,119 +151,102 @@ END_METHOD BEGIN_METHOD(Window_Ask, GB_STRING opts; GB_INTEGER tries) - bool miss; - int t, ch; - char *o, c[2]; + int t, ch, i; + char *o; - miss = MISSING(tries); t = VARGOPT(tries, -1); - o = GB.ToZeroString(ARG(opts)); + o = STRING(opts); - while (miss || t--) { - WINDOW_key_timeout(THIS, -1, &ch); - /* Per convention, only dealing with byte chars */ - if (ch > 255) + while (t--) { + ch = INPUT_get(TIMEOUT_NOTIMEOUT); + /* XXX: not meant for ncurses special keys */ + if (ch > 127) continue; - *c = (char) ch; - if (strchr(o, *c)) { - c[1] = 0; - GB.ReturnNewZeroString(c); - return; - } + if (ch == '\n') + for (i = 0; i < LENGTH(opts); i++) + if (isupper(o[i])) + goto found; + for (i = 0; i < LENGTH(opts); i++) + if (tolower(o[i]) == (char) ch) + goto found; } - GB.ReturnNull(); + GB.ReturnInteger(0); + return; + +found: + GB.ReturnInteger(i + 1); END_METHOD BEGIN_METHOD_VOID(Window_Lower) - WINDOW_bottom(THIS); + bottom_panel(THIS->pan); REFRESH(); END_METHOD -BEGIN_METHOD_VOID(Window_Cls) +static void CWINDOW_clear(CWINDOW *win) +{ + werase(win->content); +} - /* ncurses sets the cursor to 0,0 after wclear() which may or may not be - surprising. */ - wclear(THIS->content); +BEGIN_METHOD_VOID(Window_Clear) + + CWINDOW_clear(THIS); REFRESH(); END_METHOD BEGIN_METHOD_VOID(Window_Drain) - WINDOW_drain(); + INPUT_drain(); END_METHOD -BEGIN_METHOD(Window_DrawHLine, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len; GB_STRING ch; GB_INTEGER thickness) +BEGIN_METHOD(Window_DrawHLine, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len; + GB_STRING ch) - int ox, oy, gx, gy; - char c; - int length, t; - int i; - - getyx(THIS->content, oy, ox); - c = *(STRING(ch)); - length = VARG(len); - t = VARGOPT(thickness, 1); - - gx = VARG(x); - gy = VARG(y); - for (i = 0; i < t; i++) { - WINDOW_cursor_move(THIS, gx, gy); - whline(THIS->content, c, length); - gy++; - } - WINDOW_cursor_move(THIS, ox, oy); + mvwhline(THIS->content, VARG(y), VARG(x), *STRING(ch), VARG(len)); REFRESH(); END_METHOD -BEGIN_METHOD(Window_DrawVLine, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len; GB_STRING ch; GB_INTEGER thickness) +BEGIN_METHOD(Window_DrawVLine, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len; + GB_STRING ch) - int ox, oy, gx, gy; - char c; - int length, t; - int i; - - getyx(THIS->content, oy, ox); - c = *(STRING(ch)); - length = VARG(len); - t = VARGOPT(thickness, 1); - - gx = VARG(x); - gy = VARG(y); - for (i = 0; i < t; i++) { - WINDOW_cursor_move(THIS, gx, gy); - wvline(THIS->content, c, length); - gx++; - } - WINDOW_cursor_move(THIS, ox, oy); + mvwvline(THIS->content, VARG(y), VARG(x), *STRING(ch), VARG(len)); REFRESH(); END_METHOD -BEGIN_METHOD_VOID(Window_Full) +static void CWINDOW_get(CWINDOW *win, int x, int y, unsigned int len, + char **ret) +{ + char *buf; - WINDOW_move(THIS, 0, 0); - if (HAS_BORDER) - WINDOW_resize(THIS, COLS - 2, LINES - 2); + MAKE_COORDS(win->content, x, y); + CHECK_RAISE_COORDS(win->content, x, y); + if (len == -1) + len = getmaxx(win->content) - getcurx(win->content); + len = MIN(len, (getmaxy(win->content) - getcury(win->content)) * + getmaxx(win->content) - getcurx(win->content) - 1); + + GB.Alloc((void **) &buf, len + 1); + len = mvwinnstr(win->content, y, x, buf, len); + if (len != ERR) + buf[len] = 0; else - WINDOW_resize(THIS, COLS, LINES); - REFRESH(); - -END_METHOD + GB.Free((void **) &buf); + *ret = buf; +} BEGIN_METHOD(Window_Get, GB_INTEGER x; GB_INTEGER y; GB_INTEGER len) - int l; + int len; char *ret; - /* if no @len is given, we return until the end of the line */ - l = VARGOPT(len, -1); - WINDOW_get_str(THIS, VARG(x), VARG(y), l, &ret); + len = VARGOPT(len, -1); + CWINDOW_get(THIS, VARG(x), VARG(y), len, &ret); GB.ReturnNewZeroString(ret); GB.Free((void **) &ret); @@ -1147,42 +254,106 @@ END_METHOD BEGIN_METHOD_VOID(Window_Hide) - WINDOW_hide(THIS); + hide_panel(THIS->pan); REFRESH(); END_METHOD -BEGIN_METHOD(Window_Insert, GB_STRING text; GB_INTEGER x; GB_INTEGER y) - - WINDOW_insert(THIS, GB.ToZeroString(ARG(text)), VARGOPT(x, -1), VARGOPT(y, -1)); - REFRESH(); - -END_METHOD +static void CWINDOW_locate(CWINDOW *win, int x, int y) +{ + MAKE_CURSOR(win->content, x, y); + CHECK_RAISE_COORDS(win->content, x, y); + wmove(win->content, y, x); +} BEGIN_METHOD(Window_Locate, GB_INTEGER x; GB_INTEGER y) - WINDOW_cursor_move(THIS, VARG(x), VARG(y)); + CWINDOW_locate(THIS, VARG(x), VARG(y)); REFRESH(); END_METHOD +static void CWINDOW_move(CWINDOW *win, int x, int y) +{ + MAKE_COORDS(win->main, x, y); + CHECK_RAISE_COORDS(stdscr, x, y); + + move_panel(win->pan, y, x); +#if 0 + if (HAS_BORDER) { + mvwin(THIS->content, y + 1, x + 1); + WINDOW_draw_border(THIS, 1); + } +#endif +} + BEGIN_METHOD(Window_Move, GB_INTEGER x; GB_INTEGER y) - WINDOW_move(THIS, VARGOPT(x, -1), VARGOPT(y, -1)); + CWINDOW_move(THIS, VARGOPT(x, -1), VARGOPT(y, -1)); REFRESH(); END_METHOD +BEGIN_METHOD_VOID(Window_Center) + + int x, y; + + x = (COLS - getmaxx(THIS->main)) / 2; + y = (LINES - getmaxy(THIS->main)) / 2; + CWINDOW_move(THIS, x, y); + REFRESH(); + +END_METHOD + +static void CWINDOW_print(CWINDOW *win, char *str, int x, int y) +{ + int width; + char *p, *q; + + p = str; + do { + CWINDOW_locate(win, x, y); + width = strlen(p); + if (!win->wrap) + width = MIN(width, getmaxx(win->content) - x); + + /* waddnstr, being subsequent calls to waddch, rests at the + * end of the current line but we want to go to the next + * one. */ + width = MIN(width, getmaxx(win->content) * + (getmaxy(win->content) - y) - x); + if ((q = strchr(p, '\n'))) + width = MIN(width, q - p); + waddnstr(win->content, p, width); + p += width; + x = getcurx(win->content); + y = getcury(win->content); + if (y == getmaxy(win->content) - 1) + break; + if (*p == '\n') { + y++; + p++; + } + if (*p) + x = 0; + } while (*p); + CWINDOW_locate(win, x, y); +} + BEGIN_METHOD(Window_Print, GB_STRING text; GB_INTEGER x; GB_INTEGER y) - WINDOW_print(THIS, GB.ToZeroString(ARG(text)), VARGOPT(x, -1), VARGOPT(y, -1)); + char text[LENGTH(text) + 1]; + + strncpy(text, STRING(text), LENGTH(text)); + text[LENGTH(text)] = 0; + CWINDOW_print(THIS, text, VARGOPT(x, -1), VARGOPT(y, -1)); REFRESH(); END_METHOD BEGIN_METHOD_VOID(Window_Raise) - WINDOW_top(THIS); + top_panel(THIS->pan); REFRESH(); END_METHOD @@ -1191,25 +362,32 @@ BEGIN_METHOD(Window_PrintCenter, GB_STRING text) int lines = 1; int x, y; + char text[LENGTH(text) + 1]; char *p, *q; - p = GB.ToZeroString(ARG(text)); + memcpy(text, STRING(text), LENGTH(text)); + text[LENGTH(text)] = 0; + p = text; while ((q = strchr(p, '\n'))) { lines++; p = q + 1; } - p = GB.ToZeroString(ARG(text)); + p = text; y = (getmaxy(THIS->content) - lines) / 2; while (lines--) { if (!lines) { x = (getmaxx(THIS->content) - strlen(p)) / 2; - WINDOW_print(THIS, p, x, y); + CWINDOW_print(THIS, p, x, y); } else { q = strchr(p, '\n'); + if (q == p + 1) { + y++; + continue; + } *q = 0; x = (getmaxx(THIS->content) - (q - p)) / 2; - WINDOW_print(THIS, p, x, y); + CWINDOW_print(THIS, p, x, y); y++; p = q + 1; *q = '\n'; @@ -1219,9 +397,64 @@ BEGIN_METHOD(Window_PrintCenter, GB_STRING text) END_METHOD +static void CWINDOW_draw_border(CWINDOW *win) +{ + switch (win->border) { + case BORDER_NONE: + wborder(win->main, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + break; + case BORDER_ASCII: + wborder(win->main, '|', '|', '-', '-', '+', '+', '+', '+'); + break; + case BORDER_ACS: + box(win->main, 0, 0); + break; + } + if (win->border != BORDER_NONE && win->caption) { + int width = getmaxx(win->main) - 2; + + width = MIN(width, strlen(win->caption)); + mvwaddnstr(win->main, 0, 1, win->caption, width); + } +} + +static void CWINDOW_resize(CWINDOW *win, int w, int h) +{ + int x, y; + + MAKE_DIM(win->main, w, h); + + getbegyx(win->main, y, x); + if (win->has_border) { + w += 2; + h += 2; + } + /* XXX: Not rather raise an error? */ + w = MIN(w, COLS - x); + h = MIN(h, LINES - y); + + /* TODO: With the auto-created Window it does not work properly in + * Screen_Resize() from within xterm (my testcase) */ + if (win->border) + wborder(win->main, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + wresize(win->main, h, w); + if (win->has_border) + wresize(win->content, h - 2, w - 2); + replace_panel(win->pan, win->main); + CWINDOW_draw_border(win); +} + BEGIN_METHOD(Window_Resize, GB_INTEGER w; GB_INTEGER h) - WINDOW_resize(THIS, VARGOPT(w, -1), VARGOPT(h, -1)); + CWINDOW_resize(THIS, VARGOPT(w, -1), VARGOPT(h, -1)); + REAL_REFRESH(); + +END_METHOD + +BEGIN_METHOD_VOID(Window_SetFullscreen) + + CWINDOW_move(THIS, 0, 0); + CWINDOW_resize(THIS, COLS, LINES); REFRESH(); END_METHOD @@ -1233,114 +466,272 @@ BEGIN_METHOD(Window_Read, GB_INTEGER timeout) t = VARGOPT(timeout, -1); - WINDOW_key_timeout(THIS, t, &ret); + ret = INPUT_get(t); GB.ReturnInteger(ret); END_METHOD BEGIN_METHOD_VOID(Window_ReadLine) - char *line; + char line[256]; /* XXX: Must be enough! */ + int len; - if (WINDOW_readline(THIS, &line) == -1) { + len = getnstr(line, sizeof(line) - 1); + if (len == ERR) { GB.ReturnNull(); return; } + line[len] = 0; GB.ReturnNewZeroString(line); - free(line); END_METHOD BEGIN_METHOD_VOID(Window_Show) - WINDOW_show(THIS); + show_panel(THIS->pan); REFRESH(); END_METHOD +static void CWINDOW_setfocus(CWINDOW *win) +{ + if (!_curwin) + INPUT_init(); + _curwin = win; +} + BEGIN_METHOD_VOID(Window_SetFocus) - WINDOW_setfocus(THIS); + CWINDOW_setfocus(THIS); END_METHOD +#define COLOR_METHOD(r, f, b) \ +short pair = PAIR_NUMBER(getbkgd(THIS->content)); \ +short fg, bg; \ + \ +pair_content(pair, &fg, &bg); \ +if (READ_PROPERTY) { \ + GB.ReturnInteger(r); \ + return; \ +} \ +pair = CPAIR_get(f, b); \ +if (pair == -1) { \ + GB.Error(GB_ERR_BOUND); \ + return; \ +} \ +wbkgd(THIS->content, COLOR_PAIR(pair) | ' '); \ +REFRESH(); + +BEGIN_PROPERTY(Window_Background) + + COLOR_METHOD(bg, fg, VPROP(GB_INTEGER)); + +END_PROPERTY + +BEGIN_PROPERTY(Window_Foreground) + + COLOR_METHOD(fg, VPROP(GB_INTEGER), bg); + +END_PROPERTY + +BEGIN_PROPERTY(Window_Border) + + if (READ_PROPERTY) { + GB.ReturnInteger(THIS->border); + return; + } + + THIS->border = VPROP(GB_INTEGER); + CWINDOW_draw_border(THIS); + REFRESH(); + +END_PROPERTY + +BEGIN_PROPERTY(Window_Buffered) + + if (READ_PROPERTY) { + GB.ReturnBoolean(THIS->buffered); + return; + } + THIS->buffered = VPROP(GB_BOOLEAN); + +END_PROPERTY + +BEGIN_PROPERTY(Window_Caption) + + if (READ_PROPERTY) { + GB.ReturnString(THIS->caption); + return; + } + + if (THIS->caption) + GB.FreeString(&THIS->caption); + THIS->caption = GB.NewZeroString(PSTRING()); + CWINDOW_draw_border(THIS); + REFRESH(); + +END_PROPERTY + +BEGIN_PROPERTY(Window_CursorX) + + if (READ_PROPERTY) { + GB.ReturnInteger(getcurx(THIS->content)); + return; + } + CWINDOW_locate(THIS, VPROP(GB_INTEGER), -1); + REFRESH(); + +END_PROPERTY + +BEGIN_PROPERTY(Window_CursorY) + + if (READ_PROPERTY) { + GB.ReturnInteger(getcury(THIS->content)); + return; + } + CWINDOW_locate(THIS, -1, VPROP(GB_INTEGER)); + REFRESH(); + +END_PROPERTY + +BEGIN_PROPERTY(Window_Height) + + if (READ_PROPERTY) { + GB.ReturnInteger(getmaxy(THIS->content)); + return; + } + CWINDOW_resize(THIS, -1, VPROP(GB_INTEGER)); + REFRESH(); + +END_PROPERTY + +BEGIN_PROPERTY(Window_Wrap) + + if (READ_PROPERTY) { + GB.ReturnBoolean(THIS->wrap); + return; + } + THIS->wrap = VPROP(GB_BOOLEAN); + +END_PROPERTY + +BEGIN_PROPERTY(Window_Width) + + if (READ_PROPERTY) { + GB.ReturnInteger(getmaxx(THIS->content)); + return; + } + CWINDOW_resize(THIS, VPROP(GB_INTEGER), -1); + REFRESH(); + +END_PROPERTY + +BEGIN_PROPERTY(Window_X) + + if (READ_PROPERTY) { + GB.ReturnInteger(getbegx(THIS->main)); + return; + } + CWINDOW_move(THIS, VPROP(GB_INTEGER), -1); + REFRESH(); + +END_PROPERTY + +BEGIN_PROPERTY(Window_Y) + + if (READ_PROPERTY) { + GB.ReturnInteger(getbegy(THIS->main)); + return; + } + CWINDOW_move(THIS, -1, VPROP(GB_INTEGER)); + REFRESH(); + +END_PROPERTY + GB_DESC CWindowDesc[] = { GB_DECLARE("Window", sizeof(CWINDOW)), GB_AUTO_CREATABLE(), GB_EVENT("Read", NULL, NULL, &EVENT_Read), - /* Properties */ + /* Methods */ + GB_METHOD("_new", NULL, Window_new, "[(BorderFrame)b(X)i(Y)i(W)i(H)i]"), + GB_METHOD("_free", NULL, Window_free, NULL), + GB_METHOD("_get", ".Char.Attrs", Window_get, "(Y)i(X)i"), + + GB_METHOD("Ask", "i", Window_Ask, "(Opts)s[(Tries)i]"), + GB_METHOD("Read", "i", Window_Read, "[(Timeout)i]"), + GB_METHOD("ReadLine", "s", Window_ReadLine, NULL), + GB_METHOD("Drain", NULL, Window_Drain, NULL), + + GB_METHOD("Get", "s", Window_Get, "[(X)i(Y)i(Len)i]"), + + GB_METHOD("Clear", NULL, Window_Clear, NULL), + GB_METHOD("Cls", NULL, Window_Clear, NULL), + + GB_METHOD("Lower", NULL, Window_Lower, NULL), + GB_METHOD("Raise", NULL, Window_Raise, NULL), + GB_METHOD("Hide", NULL, Window_Hide, NULL), + GB_METHOD("Show", NULL, Window_Show, NULL), + + GB_METHOD("DrawHLine", NULL, Window_DrawHLine,"(X)i(Y)i(Len)i(C)s"), + GB_METHOD("DrawVLine", NULL, Window_DrawVLine,"(X)i(Y)i(Len)i(C)s"), + GB_METHOD("Print", NULL, Window_Print, "(Text)s[(X)i(Y)i]"), + GB_METHOD("PrintCenter", NULL, Window_PrintCenter, "(Text)s"), + + GB_METHOD("Locate", NULL, Window_Locate, "(X)i(Y)i"), + + GB_METHOD("Move", NULL, Window_Move, "[(X)i(Y)i]"), + GB_METHOD("Center", NULL, Window_Center, NULL), + GB_METHOD("Resize", NULL, Window_Resize, "[(W)i(H)i]"), + GB_METHOD("SetFullscreen", NULL, Window_SetFullscreen, NULL), + + GB_METHOD("SetFocus", NULL, Window_SetFocus, NULL), + GB_PROPERTY_SELF("Attributes", ".Window.Attrs"), GB_PROPERTY("Background", "i", Window_Background), GB_PROPERTY("Paper", "i", Window_Background), + GB_PROPERTY("Foreground", "i", Window_Foreground), + GB_PROPERTY("Pen", "i", Window_Foreground), GB_PROPERTY("Border", "i", Window_Border), - + GB_PROPERTY("Buffered", "b", Window_Buffered), GB_PROPERTY("Caption", "s", Window_Caption), GB_PROPERTY("CursorX", "i", Window_CursorX), GB_PROPERTY("CursorY", "i", Window_CursorY), - GB_PROPERTY("Foreground", "i", Window_Foreground), - GB_PROPERTY("Pen", "i", Window_Foreground), - + /* GB_PROPERTY("ClientHeight", ...), etc */ GB_PROPERTY("Height", "i", Window_Height), GB_PROPERTY("H", "i", Window_Height), - - GB_PROPERTY("Wrap", "b", Window_Wrap), - GB_PROPERTY("Width", "i", Window_Width), GB_PROPERTY("W", "i", Window_Width), + GB_PROPERTY("Wrap", "b", Window_Wrap), + GB_PROPERTY("X", "i", Window_X), GB_PROPERTY("Y", "i", Window_Y), - /* Methods */ - GB_METHOD("_new", NULL, Window_new, "[(Parent)Screen;(X)i(Y)i(W)i(H)i]"), - GB_METHOD("_free", NULL, Window_free, NULL), - GB_METHOD("_get", ".Char.Attrs", Window_get, "(Y)i(X)i"), - - GB_METHOD("Ask", "s", Window_Ask, "(Opts)s[(Tries)i]"), - - GB_METHOD("Lower", NULL, Window_Lower, NULL), - GB_METHOD("Raise", NULL, Window_Raise, NULL), - - GB_METHOD("Cls", NULL, Window_Cls, NULL), - - GB_METHOD("Drain", NULL, Window_Drain, NULL), - - GB_METHOD("Full", NULL, Window_Full, NULL), - - GB_METHOD("Get", "s", Window_Get, "(X)i(Y)i[(Len)i]"), - - GB_METHOD("Hide", NULL, Window_Hide, NULL), - GB_METHOD("Show", NULL, Window_Show, NULL), - - GB_METHOD("DrawHLine", NULL, Window_DrawHLine, "(X)i(Y)i(Len)i(Ch)s[(Thickness)i]"), - GB_METHOD("DrawVLine", NULL, Window_DrawVLine, "(X)i(Y)i(Len)i(Ch)s[(Thickness)i]"), - - GB_METHOD("Insert", NULL, Window_Insert, "(Text)s[(X)i(Y)i]"), - GB_METHOD("Print", NULL, Window_Print, "(Text)s[(X)i(Y)i]"), - GB_METHOD("PrintCenter", NULL, Window_PrintCenter, "(Text)s"), - - GB_METHOD("Locate", NULL, Window_Locate, "(X)i(Y)i"), - GB_METHOD("Move", NULL, Window_Move, "[(X)i(Y)i]"), - GB_METHOD("Resize", NULL, Window_Resize, "[(W)i(H)i]"), - - GB_METHOD("Read", "i", Window_Read, "[(Timeout)i]"), - GB_METHOD("ReadLine", "s", Window_ReadLine, NULL), - - GB_METHOD("SetFocus", NULL, Window_SetFocus, NULL), - GB_END_DECLARE }; /* - * .Window.Attrs virtual class + * .Window.Attrs */ +#define WIN_ATTR_METHOD(a) \ +if (READ_PROPERTY) { \ + GB.ReturnBoolean(getattrs(THIS->content) & a); \ + return; \ +} \ +if (VPROP(GB_BOOLEAN)) \ + wattron(THIS->content, a); \ +else \ + wattroff(THIS->content, a); \ +REFRESH(); + BEGIN_PROPERTY(WindowAttrs_Normal) /* Normal is special because it turns off all other attributes and can't itself been turned off */ @@ -1355,46 +746,35 @@ END_PROPERTY BEGIN_PROPERTY(WindowAttrs_Underline) WIN_ATTR_METHOD(A_UNDERLINE); - REFRESH(); END_PROPERTY BEGIN_PROPERTY(WindowAttrs_Reverse) WIN_ATTR_METHOD(A_REVERSE); - REFRESH(); END_PROPERTY BEGIN_PROPERTY(WindowAttrs_Blink) WIN_ATTR_METHOD(A_BLINK); - REFRESH(); END_PROPERTY BEGIN_PROPERTY(WindowAttrs_Bold) WIN_ATTR_METHOD(A_BOLD); - REFRESH(); END_PROPERTY -BEGIN_PROPERTY(WindowAttrs_Color) - - short pair; +/* Set background and foreground at once, more efficiently */ +BEGIN_PROPERTY(WindowAttrs_ColorPair) if (READ_PROPERTY) { - GB.ReturnInteger(PAIR_NUMBER(getattrs(THIS->content))); + GB.ReturnInteger(PAIR_NUMBER(getbkgd(THIS->content))); return; } - pair = VPROP(GB_INTEGER); - if (!PAIR_VALID(pair)) { - GB.Error(GB_ERR_BOUND); - return; - } - WINDOW_attrs_driver(THIS, COLOR_PAIR(pair), ATTR_DRV_COL); - REFRESH(); + wbkgd(THIS->content, COLOR_PAIR(VPROP(GB_INTEGER)) | ' '); END_PROPERTY @@ -1408,23 +788,53 @@ GB_DESC CWindowAttrsDesc[] = { GB_PROPERTY("Blink", "b", WindowAttrs_Blink), GB_PROPERTY("Bold", "b", WindowAttrs_Bold), - GB_PROPERTY("Color", "i", WindowAttrs_Color), + GB_PROPERTY("ColorPair", "i", WindowAttrs_ColorPair), GB_END_DECLARE }; /* - * .Char.Attrs virtual class + * .Char.Attrs */ +/* Seemingly, chgat() doesn't mark the window dirty. We use wtouchln() and + * wsyncup(). */ +#define CHAR_ATTR_METHOD(a) \ +int ox, oy; \ +chtype ch; \ + \ +getyx(THIS->content, oy, ox); \ +ch = mvwinch(THIS->content, THIS->pos.line, THIS->pos.col); \ +if (READ_PROPERTY) { \ + GB.ReturnBoolean(ch & a); \ + return; \ +} \ +if (VPROP(GB_BOOLEAN)) \ + wchgat(THIS->content, 1, (ch & A_ATTRIBUTES) | a, \ + PAIR_NUMBER(ch), NULL); \ +else \ + wchgat(THIS->content, 1, (ch & A_ATTRIBUTES) & ~a, \ + PAIR_NUMBER(ch), NULL); \ +wtouchln(THIS->content, THIS->pos.line, 1, 1); \ +wsyncup(THIS->content); \ +wmove(THIS->content, oy, ox); \ +REFRESH(); + BEGIN_PROPERTY(CharAttrs_Normal) + int ox, oy; + chtype ch; + + getyx(THIS->content, oy, ox); + ch = mvwinch(THIS->content, THIS->pos.line, THIS->pos.col); if (READ_PROPERTY) { - GB.ReturnBoolean(!WINDOW_char_attrs_driver(THIS, A_NORMAL, - THIS->pos.col, THIS->pos.line, ATTR_DRV_RET)); + GB.ReturnBoolean((ch & A_ATTRIBUTES) == A_NORMAL); return; } - WINDOW_char_attrs_driver(THIS, A_NORMAL, THIS->pos.col, THIS->pos.line, ATTR_DRV_ON); + if (VPROP(GB_BOOLEAN)) + wchgat(THIS->content, 1, A_NORMAL, PAIR_NUMBER(ch), NULL); + wtouchln(THIS->content, THIS->pos.line, 1, 1); + wmove(THIS->content, oy, ox); REFRESH(); END_PROPERTY @@ -1432,49 +842,61 @@ END_PROPERTY BEGIN_PROPERTY(CharAttrs_Underline) CHAR_ATTR_METHOD(A_UNDERLINE); - REFRESH(); END_PROPERTY BEGIN_PROPERTY(CharAttrs_Reverse) CHAR_ATTR_METHOD(A_REVERSE); - REFRESH(); END_PROPERTY BEGIN_PROPERTY(CharAttrs_Blink) CHAR_ATTR_METHOD(A_BLINK); - REFRESH(); END_PROPERTY BEGIN_PROPERTY(CharAttrs_Bold) CHAR_ATTR_METHOD(A_BOLD); - REFRESH(); END_PROPERTY -BEGIN_PROPERTY(CharAttrs_Color) +#define CHAR_COLOR_METHOD(r, f, b) \ +short pair; \ +int ox, oy; \ +chtype ch; \ +short fg, bg; \ + \ +getyx(THIS->content, oy, ox); \ +ch = mvwinch(THIS->content, THIS->pos.line, THIS->pos.col);\ +pair = PAIR_NUMBER(ch & A_COLOR); \ +pair_content(pair, &fg, &bg); \ +if (READ_PROPERTY) { \ + GB.ReturnInteger(r); \ + return; \ +} \ +pair = CPAIR_get(f, b); \ +if (pair == -1) { \ + GB.Error(GB_ERR_BOUND); \ + return; \ +} \ +wchgat(THIS->content, 1, (ch & A_ATTRIBUTES), pair, NULL);\ +wtouchln(THIS->content, THIS->pos.line, 1, 1); \ +wsyncup(THIS->content); \ +wmove(THIS->content, oy, ox); \ +REFRESH(); - short pair; +BEGIN_PROPERTY(CharAttrs_Background) - if (READ_PROPERTY) { - pair = PAIR_NUMBER(WINDOW_char_attrs_driver(THIS, 0, - THIS->pos.col, THIS->pos.line, ATTR_DRV_RET)); - GB.ReturnInteger(pair); - return; - } - pair = VPROP(GB_INTEGER); - if (!PAIR_VALID(pair)) { - GB.Error(GB_ERR_BOUND); - return; - } - WINDOW_char_attrs_driver(THIS, COLOR_PAIR(pair), THIS->pos.col, THIS->pos.line, ATTR_DRV_COL); - wtouchln(THIS->main, THIS->pos.line + (HAS_BORDER ? 1 : 0), 1, 1); - REFRESH(); + CHAR_COLOR_METHOD(bg, fg, VPROP(GB_INTEGER)); + +END_PROPERTY + +BEGIN_PROPERTY(CharAttrs_Foreground) + + CHAR_COLOR_METHOD(fg, VPROP(GB_INTEGER), bg); END_PROPERTY @@ -1488,13 +910,14 @@ GB_DESC CCharAttrsDesc[] = { GB_PROPERTY("Blink", "b", CharAttrs_Blink), GB_PROPERTY("Bold", "b", CharAttrs_Bold), - GB_PROPERTY("Color", "i", CharAttrs_Color), + GB_PROPERTY("Background", "i", CharAttrs_Background), + GB_PROPERTY("Foreground", "i", CharAttrs_Foreground), GB_END_DECLARE }; /* - * Border static class + * Border */ GB_DESC CBorderDesc[] = { diff --git a/gb.ncurses/src/c_window.h b/gb.ncurses/src/c_window.h index 542272175..65597531d 100644 --- a/gb.ncurses/src/c_window.h +++ b/gb.ncurses/src/c_window.h @@ -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 */ diff --git a/gb.ncurses/src/gb.ncurses.component b/gb.ncurses/src/gb.ncurses.component index 65cb69692..7bb193212 100644 --- a/gb.ncurses/src/gb.ncurses.component +++ b/gb.ncurses/src/gb.ncurses.component @@ -1,4 +1,3 @@ [Component] Author=Tobias Boege -State=Unstable - +State=Unfinished diff --git a/gb.ncurses/src/main.c b/gb.ncurses/src/main.c index 8fe7facc6..1548e06c4 100644 --- a/gb.ncurses/src/main.c +++ b/gb.ncurses/src/main.c @@ -1,7 +1,7 @@ /* * main.c - gb.ncurses main object * - * Copyright (C) 2012 Tobias Boege + * Copyright (C) 2012/3 Tobias Boege * * 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();