ncurses 5.0
[ncurses.git] / c++ / cursespad.cc
1 // * this is for making emacs happy: -*-Mode: C++;-*-
2 /****************************************************************************
3  * Copyright (c) 1999 Free Software Foundation, Inc.                        *
4  *                                                                          *
5  * Permission is hereby granted, free of charge, to any person obtaining a  *
6  * copy of this software and associated documentation files (the            *
7  * "Software"), to deal in the Software without restriction, including      *
8  * without limitation the rights to use, copy, modify, merge, publish,      *
9  * distribute, distribute with modifications, sublicense, and/or sell       *
10  * copies of the Software, and to permit persons to whom the Software is    *
11  * furnished to do so, subject to the following conditions:                 *
12  *                                                                          *
13  * The above copyright notice and this permission notice shall be included  *
14  * in all copies or substantial portions of the Software.                   *
15  *                                                                          *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
19  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
23  *                                                                          *
24  * Except as contained in this notice, the name(s) of the above copyright   *
25  * holders shall not be used in advertising or otherwise to promote the     *
26  * sale, use or other dealings in this Software without prior written       *
27  * authorization.                                                           *
28  ****************************************************************************/
29
30 /****************************************************************************
31  *   Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1999                 *
32  ****************************************************************************/
33
34 #include "etip.h"
35 #include "cursesw.h"
36 #include "internal.h"
37
38 MODULE_ID("$Id: cursespad.cc,v 1.2 1999/09/11 23:25:54 tom Exp $")
39
40 NCursesPad::NCursesPad(int lines, int cols)
41   : NCursesWindow(),
42     viewWin((NCursesWindow*)0),
43     viewSub((NCursesWindow*)0),
44     h_gridsize(0), v_gridsize(0),
45     min_row(0), min_col(0)
46 {
47   w = ::newpad(lines,cols);
48   if ((WINDOW*)0==w) {
49     count--;
50     err_handler("Cannot construct window");
51   }
52   alloced = TRUE;
53 }
54
55
56 int NCursesPad::driver (int key) {
57   // Default implementation
58   switch(key) {
59   case KEY_UP:
60     // =======
61     return REQ_PAD_UP;
62   case KEY_DOWN:
63     // =========
64     return REQ_PAD_DOWN;
65   case KEY_LEFT:
66     // =========
67     return REQ_PAD_LEFT;
68   case KEY_RIGHT:
69     // ==========
70     return REQ_PAD_RIGHT;
71   case KEY_EXIT:
72     // =========
73   case CTRL('X'):
74     // ==========
75     return REQ_PAD_EXIT;
76
77   default: return(key);
78   }
79 }
80
81
82 void NCursesPad::operator()(void) {
83   NCursesWindow* W = Win();
84
85   if ((NCursesWindow*)0 != W) {
86     int Width  = W->width();
87     int Height = W->height();
88
89     int req = REQ_PAD_REFRESH;
90
91     W->keypad(TRUE);
92     W->meta(TRUE);
93     refresh();
94
95     do {
96       bool changed = FALSE;
97
98       switch (req) {
99       case REQ_PAD_REFRESH:
100         // ================
101         changed = TRUE;
102         break;
103       case REQ_PAD_LEFT:
104         // =============
105         if (min_col > 0) {
106           changed = TRUE;
107           if (min_col < h_gridsize)
108             min_col = 0;
109           else
110             min_col -= h_gridsize;
111         }
112         else
113           OnNavigationError(req);
114         break;
115       case REQ_PAD_RIGHT:
116         // ==============
117         if (min_col < (width() - Width - 1)) {
118           changed = TRUE;
119           if (min_col > (width() - Width - h_gridsize - 1))
120             min_col = width() - Width - 1;
121           else
122             min_col += h_gridsize;
123         }
124         else
125           OnNavigationError(req);
126         break;
127       case REQ_PAD_UP:
128         // ===========
129         if (min_row > 0) {
130           changed = TRUE;
131           if (min_row < v_gridsize)
132             min_row = 0;
133           else
134             min_row -= v_gridsize;
135         }
136         else
137           OnNavigationError(req);
138         break;
139       case REQ_PAD_DOWN:
140         // =============
141         if (min_row < (height() - Height - 1)) {
142           changed = TRUE;
143           if (min_row > (height() - Height - v_gridsize - 1))
144             min_row = height() - Height - 1;
145           else
146             min_row += v_gridsize;
147         }
148         else
149           OnNavigationError(req);
150         break;
151
152       default:
153         OnUnknownOperation(req);
154       }
155
156       if (changed) {
157         noutrefresh();
158         W->syncup();
159         OnOperation(req);
160         viewWin->refresh();
161       }
162     } while( (req=driver(W->getch())) != REQ_PAD_EXIT );
163   }
164 }
165
166
167 int NCursesPad::refresh() {
168   int res = noutrefresh();
169   if (res==OK && ((NCursesWindow*)0 != viewWin)) {
170     res = (viewWin->refresh());
171   }
172   return(res);
173 }
174
175 int NCursesPad::noutrefresh() {
176   int res = OK;
177   NCursesWindow* W = Win();
178   if ((NCursesWindow*)0 != W) {
179     res = copywin(*W,min_row,min_col,
180                   0,0,W->maxy(),W->maxx(),
181                   FALSE);
182     if (res==OK) {
183       W->syncup();
184       res = viewWin->noutrefresh();
185     }
186   }
187   return (res);
188 }
189
190 void NCursesPad::setWindow(NCursesWindow& view,
191                            int v_grid NCURSES_PARAM_INIT(1),
192                            int h_grid NCURSES_PARAM_INIT(1))
193 {
194   viewWin = &view;
195   min_row = min_col = 0;
196   if (h_grid <=0 || v_grid <= 0)
197     err_handler("Illegal Gridsize");
198   else {
199     h_gridsize = h_grid;
200     v_gridsize = v_grid;
201   }
202 }
203
204 void NCursesPad::setSubWindow(NCursesWindow& sub)
205 {
206   if ((NCursesWindow*)0 == viewWin)
207     err_handler("Pad has no viewport");
208   if (!viewWin->isDescendant(sub))
209     THROW(new NCursesException("NCursesFramePad", E_SYSTEM_ERROR));
210   viewSub = &sub;
211 }
212
213 void NCursesFramedPad::OnOperation(int pad_req) {
214   NCursesWindow* W = Win();
215   NCursesWindow* Win = getWindow();
216
217   if (((NCursesWindow*)0 != W) && ((NCursesWindow*)0 != Win)) {
218     int Width  = W->width();
219     int Height = W->height();
220     int i, row, col, h_len, v_len;
221
222     h_len = (Width*Width + width() - 1)/width();
223     if (h_len==0)
224       h_len = 1;
225     if (h_len > Width)
226       h_len = Width;
227
228     v_len = (Height*Height + height() - 1)/height();
229     if (v_len==0)
230       v_len = 1;
231     if (v_len > Height)
232       v_len = Height;
233
234     col  = (min_col * Width + width() - 1)  / width();
235     if (col + h_len > Width)
236       col = Width - h_len;
237
238     row  = (min_row * Height + height() - 1) / height();
239     if (row + v_len > Height)
240       row = Height - v_len;
241
242     Win->vline(1,Width+1,Height);
243     Win->attron(A_REVERSE);
244     if (v_len>=2) {
245       Win->addch(row+1,Width+1,ACS_UARROW);
246       for(i=2;i<v_len;i++)
247         Win->addch(row+i,Width+1,' ');
248       Win->addch(row+v_len,Width+1,ACS_DARROW);
249     }
250     else {
251       for(i=1;i<=v_len;i++)
252         Win->addch(row+i,Width+1,' ');
253     }
254     Win->attroff(A_REVERSE);
255
256     Win->hline(Height+1,1,Width);
257     Win->attron(A_REVERSE);
258     if (h_len >= 2) {
259       Win->addch(Height+1,col+1,ACS_LARROW);
260       for(i=2;i<h_len;i++)
261         Win->addch(Height+1,col+i,' ');
262       Win->addch(Height+1,col+h_len,ACS_RARROW);
263     }
264     else {
265       for(i=1;i<=h_len;i++)
266         Win->addch(Height+1,col+i,' ');
267     }
268     Win->attroff(A_REVERSE);
269   }
270 }