b3bd3071c5f218ab2ab410143b1cb4bcde683991
[ncurses.git] / c++ / cursesw.cc
1 // * this is for making emacs happy: -*-Mode: C++;-*-
2
3 /*
4   Copyright (C) 1989 Free Software Foundation
5   written by Eric Newton (newton@rocky.oswego.edu)
6
7   This file is part of the GNU C++ Library.  This library is free
8   software; you can redistribute it and/or modify it under the terms of
9   the GNU Library General Public License as published by the Free
10   Software Foundation; either version 2 of the License, or (at your
11   option) any later version.  This library is distributed in the hope
12   that it will be useful, but WITHOUT ANY WARRANTY; without even the
13   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14   PURPOSE.  See the GNU Library General Public License for more details.
15   You should have received a copy of the GNU Library General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18
19   modified by Ulrich Drepper  (drepper@karlsruhe.gmd.de)
20           and Anatoly Ivasyuk (anatoly@nick.csh.rit.edu)
21
22   modified by Juergen Pfeifer (Juergen.Pfeifer@T-Online.de)       
23 */
24
25 #include "cursesw.h"
26 #include "internal.h"
27
28 MODULE_ID("$Id: cursesw.cc,v 1.10 1997/10/20 21:26:35 juergen Exp $")
29
30 #define COLORS_NEED_INITIALIZATION  -1
31 #define COLORS_NOT_INITIALIZED       0
32 #define COLORS_MONOCHROME            1
33 #define COLORS_ARE_REALLY_THERE      2
34
35 // declare static variables for the class
36 long NCursesWindow::count = 0L;
37 bool NCursesWindow::b_initialized = FALSE;
38
39 int
40 NCursesWindow::scanw(const char* fmt, ...)
41 {
42 #if defined(__GNUG__)
43     va_list args;
44     va_start(args, fmt);
45     char buf[BUFSIZ];
46     int result = wgetstr(w, buf);
47     if (result == OK) {
48         strstreambuf ss(buf, BUFSIZ);
49         result = ss.vscan(fmt, args);
50     }
51     va_end(args);
52     return result;
53 #else
54     return ERR;
55 #endif
56 }
57
58
59 int
60 NCursesWindow::scanw(int y, int x, const char* fmt, ...)
61 {
62 #if defined(__GNUG__)
63     va_list args;
64     va_start(args, fmt);
65     char buf[BUFSIZ];
66     int result = wmove(w, y, x);
67     if (result == OK) {
68         result = wgetstr(w, buf);
69         if (result == OK) {
70             strstreambuf ss(buf, BUFSIZ);
71             result = ss.vscan(fmt, args);
72         }
73     }
74     va_end(args);
75     return result;
76 #else
77     return ERR;
78 #endif
79 }
80
81
82 int
83 NCursesWindow::printw(const char * fmt, ...)
84 {
85     va_list args;
86     va_start(args, fmt);
87     char buf[BUFSIZ];
88     vsprintf(buf, fmt, args);
89     va_end(args);
90     return waddstr(w, buf);
91 }
92
93
94 int
95 NCursesWindow::printw(int y, int x, const char * fmt, ...)
96 {
97     va_list args;
98     va_start(args, fmt);
99     int result = wmove(w, y, x);
100     if (result == OK) {
101         char buf[BUFSIZ];
102         vsprintf(buf, fmt, args);
103         result = waddstr(w, buf);
104     }
105     va_end(args);
106     return result;
107 }
108
109
110 void
111 NCursesWindow::init(void)
112 {
113     leaveok(0);
114     keypad(1);
115     meta(1);
116 }
117
118 void
119 NCursesWindow::err_handler(const char *msg) const THROWS(NCursesException)
120 {
121   THROW(new NCursesException(msg));
122 }
123
124 void
125 NCursesWindow::initialize() {
126   if (!b_initialized) {
127     ::initscr();
128     b_initialized = TRUE;
129     if (colorInitialized==COLORS_NEED_INITIALIZATION) {
130       colorInitialized=COLORS_NOT_INITIALIZED;
131       useColors();
132     }
133     ::noecho();
134     ::cbreak();
135   }
136 }
137
138 NCursesWindow::NCursesWindow() {
139   if (!b_initialized)
140     initialize();
141   
142   w = (WINDOW *)0;
143   init();
144   alloced = FALSE;
145   subwins = par = sib = 0;
146   count++;
147 }
148
149 NCursesWindow::NCursesWindow(int lines, int cols, int begin_y, int begin_x)
150 {
151     if (!b_initialized)
152       initialize();
153
154     w = ::newwin(lines, cols, begin_y, begin_x);
155     if (w == 0) {
156         err_handler("Cannot construct window");
157     }
158     init();
159
160     alloced = TRUE;
161     subwins = par = sib = 0;
162     count++;
163 }
164
165 NCursesWindow::NCursesWindow(WINDOW* &window)
166 {
167     if (!b_initialized)
168       initialize();
169     
170     w = window;
171     init();
172     alloced = FALSE;
173     subwins = par = sib = 0;
174     count++;
175 }
176
177 NCursesWindow::NCursesWindow(NCursesWindow& win, int l, int c,
178                              int begin_y, int begin_x, char absrel)
179 {
180     if (absrel == 'a') { // absolute origin 
181         begin_y -= win.begy();
182         begin_x -= win.begx();
183     }
184
185     // Even though we treat subwindows as a tree, the standard curses
186     // library needs the `subwin' call to link to the parent in
187     // order to correctly perform refreshes, etc.
188     // Friendly enough, this also works for pads.
189     w = ::derwin(win.w, l, c, begin_y, begin_x);
190     if (w == 0) {
191         err_handler("Cannot construct subwindow");
192     }
193
194     par = &win;
195     sib = win.subwins;
196     win.subwins = this;
197     subwins = 0;
198     alloced = TRUE;
199     count++;
200 }
201   
202 NCursesWindow NCursesWindow::Clone() {
203   WINDOW *d = ::dupwin(w);
204   NCursesWindow W(d);
205   W.subwins = subwins;
206   W.sib = sib;
207   W.par = par;
208   W.alloced = alloced;
209   return W;
210 }
211
212 typedef int (*RIPOFFINIT)(NCursesWindow&);
213 static RIPOFFINIT R_INIT[5];       // There can't be more
214 static int r_init_idx   = 0;
215 static RIPOFFINIT* prip = R_INIT;
216
217 extern "C" int _nc_ripoffline(int,int (*init)(WINDOW*,int));
218
219 NCursesWindow::NCursesWindow(WINDOW *win, int cols) {
220   w = win;
221   assert((w->_maxx+1)==cols);
222   alloced = FALSE;
223   subwins = par = sib = 0;
224 }
225
226 int NCursesWindow::ripoff_init(WINDOW *w, int cols)
227 {
228   int res = ERR;
229
230   RIPOFFINIT init = *prip++;
231   if (init) {
232     NCursesWindow* W = new NCursesWindow(w,cols);
233     res = init(*W);
234   }
235   return res;
236 }
237
238 int NCursesWindow::ripoffline(int ripoff_lines,
239                               int (*init)(NCursesWindow& win)) {
240   int code = ::_nc_ripoffline(ripoff_lines,ripoff_init);
241   if (code==OK && init && ripoff_lines) {
242     R_INIT[r_init_idx++] = init;
243   }
244   return code;
245 }
246
247 bool
248 NCursesWindow::isDescendant(NCursesWindow& win) {
249   for (NCursesWindow* p = subwins; p != NULL; p = p->sib) {
250     if (p==&win)
251       return TRUE;
252     else {
253       if (p->isDescendant(win))
254         return TRUE;
255     }
256   }
257   return FALSE;
258 }
259
260 void
261 NCursesWindow::kill_subwindows()
262 {
263     for (NCursesWindow* p = subwins; p != 0; p = p->sib) {
264         p->kill_subwindows();
265         if (p->alloced) {
266             if (p->w != 0)
267                 ::delwin(p->w);
268             p->alloced = FALSE;
269         }
270         p->w = 0; // cause a run-time error if anyone attempts to use...
271     }
272 }
273
274
275 NCursesWindow::~NCursesWindow()
276 {
277     kill_subwindows();
278
279     if (par != 0) {  // Snip us from the parent's list of subwindows.
280         NCursesWindow * win = par->subwins;
281         NCursesWindow * trail = 0;
282         for (;;) {
283             if (win == 0)
284                 break;
285             else if (win == this) {
286                 if (trail != 0)
287                     trail->sib = win->sib;
288                 else
289                     par->subwins = win->sib;
290                 break;
291             } else {
292                 trail = win;
293                 win = win->sib;
294             }
295         }
296     }
297
298     if (alloced && w != 0)
299         delwin(w);
300
301     if (alloced) {
302       --count;
303       if (count == 0) {
304         ::endwin();
305       }
306       else if (count < 0) { // cannot happen!
307         err_handler("Too many windows destroyed");
308       }
309     }
310 }
311
312 // ---------------------------------------------------------------------
313 // Color stuff
314 //
315 int NCursesWindow::colorInitialized = COLORS_NOT_INITIALIZED;
316
317 void
318 NCursesWindow::useColors(void)
319 {
320     if (colorInitialized == COLORS_NOT_INITIALIZED) {        
321       if (b_initialized) {
322         if (::has_colors()) {
323           ::start_color();
324           colorInitialized = COLORS_ARE_REALLY_THERE;
325         }
326         else
327           colorInitialized = COLORS_MONOCHROME;
328       }
329       else
330         colorInitialized = COLORS_NEED_INITIALIZATION;
331     }
332 }
333
334 short
335 NCursesWindow::getcolor(int getback) const 
336 {
337     short fore, back;
338
339     if (colorInitialized==COLORS_ARE_REALLY_THERE) {
340       if (pair_content(PAIR_NUMBER(w->_attrs), &fore, &back))
341         err_handler("Can't get color pair");
342     }
343     else {
344       // Monochrome means white on black
345       back = COLOR_BLACK;
346       fore = COLOR_WHITE;
347     }
348     return getback ? back : fore;
349 }
350
351 int NCursesWindow::NumberOfColors()
352 {
353   if (colorInitialized==COLORS_ARE_REALLY_THERE)
354     return COLORS;
355   else
356     return 1; // monochrome (actually there are two ;-)
357 }
358
359 short
360 NCursesWindow::getcolor() const 
361 {
362   if (colorInitialized==COLORS_ARE_REALLY_THERE)
363     return PAIR_NUMBER(w->_attrs);
364   else
365     return 0; // we only have pair zero
366 }
367
368 int
369 NCursesWindow::setpalette(short fore, short back, short pair)
370 {
371   if (colorInitialized==COLORS_ARE_REALLY_THERE)
372     return init_pair(pair, fore, back);
373   else
374     return OK;
375 }
376
377 int
378 NCursesWindow::setpalette(short fore, short back)
379 {
380   if (colorInitialized==COLORS_ARE_REALLY_THERE)
381     return setpalette(fore, back, PAIR_NUMBER(w->_attrs));
382   else
383     return OK;
384 }
385
386
387 int
388 NCursesWindow::setcolor(short pair)
389 {
390   if (colorInitialized==COLORS_ARE_REALLY_THERE) {
391     if ((pair < 1) || (pair > COLOR_PAIRS))
392       err_handler("Can't set color pair");
393     
394     attroff(A_COLOR);
395     attrset(COLOR_PAIR(pair));
396   }
397   return OK;
398 }
399
400 extern "C" int _nc_has_mouse(void);
401
402 bool NCursesWindow::has_mouse() const {
403   return ((::has_key(KEY_MOUSE) || ::_nc_has_mouse()) 
404           ? TRUE : FALSE);
405 }
406
407 NCursesPad::NCursesPad(int lines, int cols) : NCursesWindow() {
408   w = ::newpad(lines,cols);
409   if (w==(WINDOW*)0) {
410     count--;
411     err_handler("Cannot construct window");
412   }
413   alloced = TRUE;
414 }