1 /*
2 ** Copyright 2002-2011, Double Precision Inc.
3 **
4 ** See COPYING for distribution information.
5 */
6 
7 #ifndef curses_H
8 #define curses_H
9 
10 #include "../curses/curses_config.h"
11 #include <courier-unicode.h>
12 #include <string.h>
13 
14 #include <wchar.h>
15 #include <string>
16 #include <vector>
17 
18 #include "cursesobject.H"
19 #include "widechar.H"
20 
21 class Curses;
22 class CursesContainer;
23 
24 ///////////////////////////////////////////////////////////////////////////
25 //
26 // A simple OO interface to libcurses.
27 //
28 // The Curses object is the common abstract superclass.  All other objects
29 // subclass from Curses.
30 //
31 // Curses objects are arranged in a tree hierarchy.  The root of the tree
32 // is the CursesScreen objects, which implements the WriteText() methods
33 // that use libcurses.  All Curses objects are anchored at some row/column
34 // pair, relative to its hierarchy parent.  The Curses object provides a
35 // default WriteText() implementation that adds the given text position to
36 // its row/column position, and then calls its parent's WriteText() method.
37 //
38 // Two WriteText methods are provided: one for text in the current
39 // (possibly multibyte) character set; and one for wide-character text.
40 //
41 // The remaining methods generally follow a similar path - a default
42 // Curses implementation that performs local processing, then calls its
43 // parent's method.
44 
45 class Curses : public CursesObj {
46 
47 	// My parent, possibly NULL;
48 
49 	CursesContainer *parent;
50 
51 	int row, col;	// My location.
52 
53 	// Comparison function compares Curses objects based on their
54 	// location.  This is used to determine input focus tabbing.
55 
56 	static bool childPositionCompareFunc(Curses *, Curses *);
57 
58 public:
59 
60 	// Curses object that receives keyboard input at this time.
61 	// May be NULL
62 
63 	static Curses *currentFocus;
64 
65 	// Keepgoing is initialized to true.  Some objects, (FileReq,
66 	// StatusBar) reset it to false to indicate that they're done.
67 	// keepgoing must be manually reset to true.
68 
69 	static bool keepgoing;
70 
71 	// Emulate SHIFT keys for keyboards that can't directly generate
72 	// then.  shiftmode is set to true if the previous keypress was the
73 	// SHIFT keypress.
74 
75 	static bool shiftmode;
76 
77 	static std::string suspendCommand; // Run this instead of SIGSTOP
78 
79 	static int runCommand(std::vector<const char *> &argv,
80 			      int stdinpipe,
81 			      std::string continuePrompt);
82 	// Disable curses, run the command, reenable curses
83 
84 	// CursesAttr encapsulates generic text attributes, for WriteText
85 
86 	class CursesAttr {
87 
88 		int bgcolor;
89 		int fgcolor;
90 		bool highlight;
91 		bool reverse;
92 		bool underline;
93 	public:
CursesAttr()94 		CursesAttr() : bgcolor(0),
95 			       fgcolor(0),
96 			       highlight(0), reverse(0), underline(0)
97 		{
98 		}
~CursesAttr()99 		~CursesAttr()
100 		{
101 		}
102 
setBgColor(int c)103 		CursesAttr &setBgColor(int c)
104 		{
105 			bgcolor=c;
106 			return *this;
107 		}
108 
setFgColor(int c)109 		CursesAttr &setFgColor(int c)
110 		{
111 			fgcolor=c;
112 			return *this;
113 		}
114 
115 		CursesAttr &setHighlight(bool h=true)
116 		{
117 			highlight=h;
118 			return *this;
119 		}
120 
121 		CursesAttr &setReverse(bool r=1)
122 		{
123 			reverse=r;
124 			return *this;
125 		}
126 
127 		CursesAttr &setUnderline(bool u=1)
128 		{
129 			underline=u;
130 			return *this;
131 		}
132 
getBgColor()133 		int getBgColor() const { return bgcolor; }
getFgColor()134 		int getFgColor() const { return fgcolor; }
getHighlight()135 		bool getHighlight() const { return highlight; }
getReverse()136 		bool getReverse() const { return reverse; }
getUnderline()137 		bool getUnderline() const { return underline; }
138 	};
139 
140 	// Generic encapsulation of keyboard input.  Keyboard input is either
141 	// a key, wchar_t, or a special function key, like a cursor key.
142 	// Rather than pull in all the baggage of curses.h, just to get
143 	// the key definition, we define our own constants.  Which also
144 	// makes it possible to define magic keys that are not defined by
145 	// curses.h
146 
147 	class Key {
148 	public:
149 		char32_t ukey;
150 		const char *keycode;
151 
Key(char32_t ch)152 		Key(char32_t ch) : ukey(ch), keycode(0) {}
153 
Key(const char * k)154 		Key(const char *k) : ukey(0), keycode(k) {}
155 
plain()156 		bool plain() const { return keycode == 0; }
157 
nokey()158 		bool nokey() const { return ukey == 0 && keycode == 0; }
159 
fkey()160 		bool fkey() const { return keycode &&
161 				strcmp(keycode, "FKEY") == 0; }
162 		// This is a function key
163 
fkeynum()164 		int fkeynum() const { return (int)ukey; }
165 
166 		static const char LEFT[],
167 			RIGHT[],
168 			SHIFTLEFT[],
169 			SHIFTRIGHT[],
170 			UP[],
171 			DOWN[],
172 			SHIFTUP[],
173 			SHIFTDOWN[],
174 			DEL[],
175 			CLREOL[],
176 			BACKSPACE[],
177 			ENTER[],
178 			PGUP[],
179 			PGDN[],
180 			SHIFTPGUP[],
181 			SHIFTPGDN[],
182 			HOME[],
183 			END[],
184 			SHIFTHOME[],
185 			SHIFTEND[],
186 			SHIFT[],
187 			RESIZE[];
188 
189 		bool operator==(const char *p) const
190 		{
191 			return keycode != 0 && strcmp(keycode, p) == 0;
192 		}
193 
194 #if 0
195 		bool operator==(char32_t k) const
196 		{
197 			return keycode == 0 && key == k;
198 		}
199 #endif
200 
201 		bool operator==(const Key &k) const
202 		{
203 			return strcmp(keycode ? keycode:"",
204 				      k.keycode ? k.keycode:"") == 0 &&
205 				ukey == k.ukey;
206 		}
207 
208 		bool operator==(const std::u32string &v) const;
209 
210 		bool operator!=(const char *p) const
211 		{
212 			return !operator==(p);
213 		}
214 
215 #if 0
216 		bool operator!=(wchar_t k) const
217 		{
218 			return !operator==(k);
219 		}
220 #endif
221 		bool operator!=(const std::u32string &v) const
222 		{
223 			return !operator==(v);
224 		}
225 	};
226 
227 	// This humble function received and handles keyboard input.
228 	// processKey() runs either an installed key handler, or runs
229 	// currentFocus->processKeyInFocus().  When a file requester, or
230 	// StatusBar input prompt is active, at exit keepgoing may be set
231 	// to false (ENTER key closes the file requester or status bar input
232 	// field).
233 
234 	static bool processKey(const Key &k);
235 
236 	// How to interpret Curses::col
237 
238 	enum Alignment {
239 		LEFT,		// col is the left corner
240 		CENTER,		// col is the center of this Curses object
241 		RIGHT,		// col is the right corner
242 		PARENTCENTER};	// Ignore col, center this object in its parent
243 
244 	Curses(CursesContainer *parent=0);
245 	virtual ~Curses();
246 
247 	// Subclasses must define getWidth() and getHeight() to provide their
248 	// sizes.
249 
250 	virtual int getWidth() const=0;
251 	virtual int getHeight() const=0;
252 
253 	// Children of CursesVScroll may not have their entire contents
254 	// shown.  To optimize their draw() implementation, instead of
255 	// writing out their contents in entire, getVerticalViewport may
256 	// be called to obtain the first line of this object that's actually
257 	// viewable, and the total number of rows that are viewable.
258 	// Calls to write text to lines outside this range will be no-oped.
259 	// nrows may be 0, if this object is entirely off-screen.
260 	//
261 	// The default Curses implementation sets first_row to 0, and
262 	// nrows to getHeight(), then calls the getVerticalViewPort() method
263 	// of its parent.  The results of parent's GetVerticalViewPort(),
264 	// combined with this object's getRow() method, is used to potentially
265 	// narrow down the first_row/nrows range.  For example, if the parent's
266 	// vertical viewport is rows 5-9, and this object's row is 4, and
267 	// its height is 10, then the resulting first_row/nrows will be 1/5
268 	// (instead of 0/10).
269 
270 	virtual void getVerticalViewport(size_t &first_row,
271 					 size_t &nrows);
272 
273 	// The default implementation of getScreenWidth()/getScreenHeight()
274 	// walk up the parent chain, and invoke the hierarchy root's Curses
275 	// object's getWidth/getHeight methods, which should reflect the
276 	// should be the actual screen size.
277 
278 	int getScreenWidth() const;
279 	int getScreenHeight() const;
280 
281 	// get/set row/col methods have an obvious default implementation,
282 	// that some subclasses may override (the usual reason is to
283 	// automatically redraw the curses object if it moves)
284 
285 	virtual int getRow() const;
286 	virtual int getCol() const;
287 	virtual void setRow(int row);
288 	virtual void setCol(int col);
289 
290 	// The default implementation of scrollTo adds the supplied row number
291 	// to the starting row of this curses object, and recursively
292 	// calls the parent's scrollTo() method.  CursesVScroll overrides
293 	// this method to make sure that the indicated row is currently
294 	// visible.
295 
296 	virtual void scrollTo(size_t row);
297 
getParent()298 	CursesContainer *getParent() { return (parent); }
getParent()299 	const CursesContainer *getParent() const { return (parent); }
setParent(CursesContainer * p)300 	void setParent(CursesContainer *p) { parent=p; }
301 
302 	// If CursesContainer sees an isDialog() child, it will get drawn
303 	// instead of all the other children.  Uses by CursesFileReq, for
304 	// example, to take over the display.
305 
306 	virtual bool isDialog() const;
307 
308 	// Find my dialog child
309 
310 	virtual Curses *getDialogChild() const;
311 
312 	// draw() must be subclassed to invoked WriteText() to actually
313 	// print the Curses object's contents.
314 
315 	virtual void draw()=0;
316 
317 	// The default implementation of erase() calls getWidth()/getHeight()
318 	// then writes out a bunch of whitespace to clear everything out.
319 
320 	virtual void erase();
321 
322 	// The default implementation of flush() calls the parent's flush()
323 	// method.  The top level CursesScreen object calls libcurses.a
324 	// instead.
325 
326 	virtual void flush();
327 
328 	//  The screen has been resized.
329 	//  The default implementation of resized() just calls draw()
330 	//
331 
332 	virtual void resized();
333 
334 	static int getColorCount();
335 	// # of colors supported by display (0 if no colors)
336 
337 	//  See the beginning of this file for a description of writeText().
338 
339 	virtual bool writeText(const char *text, int row, int col,
340 			       const CursesAttr &attr) const;
341 	virtual bool writeText(const std::u32string &text,
342 			       int row, int col,
343 			       const Curses::CursesAttr &attr) const;
344 
345 	void writeText(std::string text, int row, int col,
346 		       const CursesAttr &attr) const;
347 
348 	// Beep the terminal.
349 
350 	virtual void beepError();
351 
352 private:
353 	Alignment alignment;
354 
355 public:
356 	// Return the coordinates of the top/left corner of this object,
357 	// in the context of this parent, after taking into account all
358 	// the alignment information.
359 
360 	int getRowAligned() const;
361 	int getColAligned() const;
362 
363 	virtual void setAlignment(Alignment alignmentArg);
364 	virtual Alignment getAlignment();
365 
366 	// Indicate whether this object can handle keyboard input
367 	// (default: no).
368 
369 	virtual bool isFocusable();
370 
371 	// If this object is handling keyboard input, return the next or the
372 	// previous object, in the natural tabbing order, that should receive
373 	// keyboard input.
374 
375 	virtual Curses *getNextFocus();
376 	virtual Curses *getPrevFocus();
377 
378 	// Actually move the keyboard focus to the next or prev curses object.
379 
380 	virtual void transferNextFocus();
381 	virtual void transferPrevFocus();
382 
383 	// Explicitly request keyboard input
384 
385 	virtual void requestFocus();
386 
387 	// Callback function that is invoked whenever this object begins
388 	// handling keyboard input.  The default implementation just calls
389 	// draw()
390 
391 	virtual void focusGained();
392 
393 	// Callback function that is invoked whenever this object stops
394 	// handling keyboard input.  The default implementation just calls
395 	// draw()
396 
397 	virtual void focusLost();
398 
399 	// Remove keyboard input from any object that's currently receiving
400 	// keyboard input (explicitly calling focusLost()).  This can be
401 	// useful to force focusLost() processing (to make sure that any
402 	// further popup notice activity won't cause any side effects).
403 	// Eventually, somebody's requestFocus() method should be called
404 	// to reenable input processing
405 
406 	static void dropFocus();
407 
408 	// Return whether this object is handling keyboard input
409 
410 	virtual bool hasFocus();
411 
412 	// Handle keyboard input.  The default implementation changes
413 	// keyboard input focus in response to basic cursor movement
414 	// keys.  Subclasses typically override, but also call the superclass's
415 	// method for the default action.
416 	// processKeyInFocus returns true if the key was processed, or if the
417 	// function did not recognize and process the key.
418 
419 	virtual bool processKeyInFocus(const Key &key);
420 
421 	// Map the coordinates of a character sell in this Curses object to
422 	// the screen coordinates.  The default implementation just adds
423 	// row/col to the top/left starting coords of this object, then runs
424 	// the parent's getCursorPosition() method.
425 
426 	virtual int getCursorPosition(int &row, int &col);
427 
428 
429 	// Set a callback function invoked after a suspend
430 
431 	static void setSuspendHook( void (*)(void) );
432 
433 	static void (*suspendedHook)(void);
434 private:
435 	static void suspendedStub(void);
436 
437 };
438 
439 #endif
440