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