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
39MODULE_ID("$Id: cursespad.cc,v 1.13 2008/08/04 18:59:22 tom Exp $")
40
41NCursesPad::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
57int 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
84void 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
170int 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
179int 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
197void 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
211void 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
221void 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}
280