28c58fab36acaae85ff1016ecc5effdf639cf842
[ncurses.git] / c++ / cursespad.cc
1 // * this is for making emacs happy: -*-Mode: C++;-*-
2 /****************************************************************************
3  * Copyright (c) 1998-2007,2008 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, 1999                                          *
32  ****************************************************************************/
33
34 #include "internal.h"
35
36 #include <etip.h>
37 #include <cursesw.h>
38
39 MODULE_ID("$Id: cursespad.cc,v 1.13 2008/08/04 18:59:22 tom Exp $")
40
41 NCursesPad::NCursesPad(int nlines, int ncols)
42   : NCursesWindow(),
43     viewWin(static_cast<NCursesWindow*>(0)),
44     viewSub(static_cast<NCursesWindow*>(0)),
45     h_gridsize(0), v_gridsize(0),
46     min_row(0), min_col(0)
47 {
48   w = ::newpad(nlines, ncols);
49   if (static_cast<WINDOW*>(0) == w) {
50     count--;
51     err_handler("Cannot construct window");
52   }
53   alloced = TRUE;
54 }
55
56
57 int NCursesPad::driver (int key)
58 {
59   // Default implementation
60   switch(key) {
61   case KEY_UP:
62     // =======
63     return REQ_PAD_UP;
64   case KEY_DOWN:
65     // =========
66     return REQ_PAD_DOWN;
67   case KEY_LEFT:
68     // =========
69     return REQ_PAD_LEFT;
70   case KEY_RIGHT:
71     // ==========
72     return REQ_PAD_RIGHT;
73   case KEY_EXIT:
74     // =========
75   case CTRL('X'):
76     // ==========
77     return REQ_PAD_EXIT;
78
79   default: return(key);
80   }
81 }
82
83
84 void NCursesPad::operator()(void)
85 {
86   NCursesWindow* W = Win();
87
88   if (static_cast<NCursesWindow*>(0) != W) {
89     int Width  = W->width();
90     int Height = W->height();
91
92     int req = REQ_PAD_REFRESH;
93
94     W->keypad(TRUE);
95     W->meta(TRUE);
96     refresh();
97
98     do {
99       bool changed = FALSE;
100
101       switch (req) {
102       case REQ_PAD_REFRESH:
103         // ================
104         changed = TRUE;
105         break;
106       case REQ_PAD_LEFT:
107         // =============
108         if (min_col > 0) {
109           changed = TRUE;
110           if (min_col < h_gridsize)
111             min_col = 0;
112           else
113             min_col -= h_gridsize;
114         }
115         else
116           OnNavigationError(req);
117         break;
118       case REQ_PAD_RIGHT:
119         // ==============
120         if (min_col < (width() - Width - 1)) {
121           changed = TRUE;
122           if (min_col > (width() - Width - h_gridsize - 1))
123             min_col = width() - Width - 1;
124           else
125             min_col += h_gridsize;
126         }
127         else
128           OnNavigationError(req);
129         break;
130       case REQ_PAD_UP:
131         // ===========
132         if (min_row > 0) {
133           changed = TRUE;
134           if (min_row < v_gridsize)
135             min_row = 0;
136           else
137             min_row -= v_gridsize;
138         }
139         else
140           OnNavigationError(req);
141         break;
142       case REQ_PAD_DOWN:
143         // =============
144         if (min_row < (height() - Height - 1)) {
145           changed = TRUE;
146           if (min_row > (height() - Height - v_gridsize - 1))
147             min_row = height() - Height - 1;
148           else
149             min_row += v_gridsize;
150         }
151         else
152           OnNavigationError(req);
153         break;
154
155       default:
156         OnUnknownOperation(req);
157       }
158
159       if (changed) {
160         noutrefresh();
161         W->syncup();
162         OnOperation(req);
163         viewWin->refresh();
164       }
165     } while( (req=driver(W->getch())) != REQ_PAD_EXIT );
166   }
167 }
168
169
170 int NCursesPad::refresh()
171 {
172   int res = noutrefresh();
173   if (res==OK && (static_cast<NCursesWindow*>(0) != viewWin)) {
174     res = (viewWin->refresh());
175   }
176   return(res);
177 }
178
179 int NCursesPad::noutrefresh()
180 {
181   int res = OK;
182   NCursesWindow* W = Win();
183   if (static_cast<NCursesWindow*>(0) != W) {
184     int high = W->maxy();
185     int wide = W->maxx();
186     res = copywin(*W, min_row, min_col,
187                   0, 0, high, wide,
188                   FALSE);
189     if (res==OK) {
190       W->syncup();
191       res = viewWin->noutrefresh();
192     }
193   }
194   return (res);
195 }
196
197 void NCursesPad::setWindow(NCursesWindow& view,
198                            int v_grid NCURSES_PARAM_INIT(1),
199                            int h_grid NCURSES_PARAM_INIT(1))
200 {
201   viewWin = &view;
202   min_row = min_col = 0;
203   if (h_grid <=0 || v_grid <= 0)
204     err_handler("Illegal Gridsize");
205   else {
206     h_gridsize = h_grid;
207     v_gridsize = v_grid;
208   }
209 }
210
211 void NCursesPad::setSubWindow(NCursesWindow& sub)
212 {
213   if (static_cast<NCursesWindow*>(0) == viewWin)
214     err_handler("Pad has no viewport");
215   assert(viewWin != 0);
216   if (!viewWin->isDescendant(sub))
217     THROW(new NCursesException("NCursesFramePad", E_SYSTEM_ERROR));
218   viewSub = &sub;
219 }
220
221 void NCursesFramedPad::OnOperation(int pad_req)
222 {
223   NCursesWindow* W = Win();
224   NCursesWindow* W2 = getWindow();
225
226   if ((static_cast<NCursesWindow*>(0) != W) && (static_cast<NCursesWindow*>(0) != W2)) {
227     int Width  = W->width();
228     int Height = W->height();
229     int i, row, col, h_len, v_len;
230
231     h_len = (Width*Width + width() - 1)/width();
232     if (h_len==0)
233       h_len = 1;
234     if (h_len > Width)
235       h_len = Width;
236
237     v_len = (Height*Height + height() - 1)/height();
238     if (v_len==0)
239       v_len = 1;
240     if (v_len > Height)
241       v_len = Height;
242
243     col  = (min_col * Width + width() - 1)  / width();
244     if (col + h_len > Width)
245       col = Width - h_len;
246
247     row  = (min_row * Height + height() - 1) / height();
248     if (row + v_len > Height)
249       row = Height - v_len;
250
251     W2->vline(1,Width+1,Height);
252     W2->attron(A_REVERSE);
253     if (v_len>=2) {
254       W2->addch(row+1,Width+1,ACS_UARROW);
255       for(i=2;i<v_len;i++)
256         W2->addch(row+i,Width+1,' ');
257       W2->addch(row+v_len,Width+1,ACS_DARROW);
258     }
259     else {
260       for(i=1;i<=v_len;i++)
261         W2->addch(row+i,Width+1,' ');
262     }
263     W2->attroff(A_REVERSE);
264
265     W2->hline(Height+1,1,Width);
266     W2->attron(A_REVERSE);
267     if (h_len >= 2) {
268       W2->addch(Height+1,col+1,ACS_LARROW);
269       for(i=2;i<h_len;i++)
270         W2->addch(Height+1,col+i,' ');
271       W2->addch(Height+1,col+h_len,ACS_RARROW);
272     }
273     else {
274       for(i=1;i<=h_len;i++)
275         W2->addch(Height+1,col+i,' ');
276     }
277     W2->attroff(A_REVERSE);
278   }
279 }