• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // * this is for making emacs happy: -*-Mode: C++;-*-
2 /****************************************************************************
3  * Copyright 2020 Thomas E. Dickey                                          *
4  * Copyright 1999-2012,2013 Free Software Foundation, Inc.                  *
5  *                                                                          *
6  * Permission is hereby granted, free of charge, to any person obtaining a  *
7  * copy of this software and associated documentation files (the            *
8  * "Software"), to deal in the Software without restriction, including      *
9  * without limitation the rights to use, copy, modify, merge, publish,      *
10  * distribute, distribute with modifications, sublicense, and/or sell       *
11  * copies of the Software, and to permit persons to whom the Software is    *
12  * furnished to do so, subject to the following conditions:                 *
13  *                                                                          *
14  * The above copyright notice and this permission notice shall be included  *
15  * in all copies or substantial portions of the Software.                   *
16  *                                                                          *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
20  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
23  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
24  *                                                                          *
25  * Except as contained in this notice, the name(s) of the above copyright   *
26  * holders shall not be used in advertising or otherwise to promote the     *
27  * sale, use or other dealings in this Software without prior written       *
28  * authorization.                                                           *
29  ****************************************************************************/
30 
31 /****************************************************************************
32  *   Author: Juergen Pfeifer, 1999                                          *
33  ****************************************************************************/
34 
35 #include "internal.h"
36 
37 #include <cursesw.h>
38 
39 MODULE_ID("$Id: cursespad.cc,v 1.18 2020/02/02 23:34:34 tom Exp $")
40 
NCursesPad(int nlines,int ncols)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 
driver(int key)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 
operator ()(void)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 
refresh()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 
noutrefresh()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 
setSubWindow(NCursesWindow & sub)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 
OnOperation(int pad_req)221 void NCursesFramedPad::OnOperation(int pad_req)
222 {
223   (void) pad_req;
224   NCursesWindow* W = Win();
225   NCursesWindow* W2 = getWindow();
226 
227   if ((static_cast<NCursesWindow*>(0) != W) && (static_cast<NCursesWindow*>(0) != W2)) {
228     int Width  = W->width();
229     int Height = W->height();
230     int i, row, col, h_len, v_len;
231 
232     int my_width = width();
233 
234     if (my_width != 0) {
235       h_len = (Width*Width + my_width - 1) / my_width;
236       if (h_len==0)
237 	h_len = 1;
238       if (h_len > Width)
239 	h_len = Width;
240     } else {
241       h_len = 1;
242     }
243 
244     int my_height = height();
245 
246     if (my_height != 0) {
247       v_len = (Height*Height + my_height - 1) / my_height;
248       if (v_len==0)
249 	v_len = 1;
250       if (v_len > Height)
251 	v_len = Height;
252     } else {
253       v_len = 1;
254     }
255 
256     if (my_width != 0) {
257       col  = (min_col * Width + my_width - 1) / my_width;
258       if (col + h_len > Width)
259         col = Width - h_len;
260     } else {
261       col = 0;
262     }
263 
264     if (my_height != 0) {
265       row  = (min_row * Height + my_height - 1) / my_height;
266       if (row + v_len > Height)
267         row = Height - v_len;
268     } else {
269       row = 0;
270     }
271 
272     W2->vline(1,Width+1,Height);
273     W2->attron(A_REVERSE);
274     if (v_len>=2) {
275       W2->addch(row+1,Width+1,ACS_UARROW);
276       for(i=2;i<v_len;i++)
277 	W2->addch(row+i,Width+1,' ');
278       W2->addch(row+v_len,Width+1,ACS_DARROW);
279     }
280     else {
281       for(i=1;i<=v_len;i++)
282 	W2->addch(row+i,Width+1,' ');
283     }
284     W2->attroff(A_REVERSE);
285 
286     W2->hline(Height+1,1,Width);
287     W2->attron(A_REVERSE);
288     if (h_len >= 2) {
289       W2->addch(Height+1,col+1,ACS_LARROW);
290       for(i=2;i<h_len;i++)
291 	W2->addch(Height+1,col+i,' ');
292       W2->addch(Height+1,col+h_len,ACS_RARROW);
293     }
294     else {
295       for(i=1;i<=h_len;i++)
296 	W2->addch(Height+1,col+i,' ');
297     }
298     W2->attroff(A_REVERSE);
299   }
300 }
301