ncurses 5.6 - patch 20081025
[ncurses.git] / c++ / demo.cc
1 // * This makes 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  *   Silly demo program for the NCursesPanel class.
32  *
33  *   written by Anatoly Ivasyuk (anatoly@nick.csh.rit.edu)
34  *
35  *   Demo code for NCursesMenu and NCursesForm written by
36  *   Juergen Pfeifer
37  *
38  * $Id: demo.cc,v 1.38 2008/08/04 17:16:57 tom Exp $
39  */
40
41 #include "internal.h"
42 #include "cursesapp.h"
43 #include "cursesm.h"
44 #include "cursesf.h"
45
46 extern "C" unsigned int sleep(unsigned int);
47
48 #undef index // needed for NeXT
49
50 //
51 // -------------------------------------------------------------------------
52 //
53 class SillyDemo
54 {
55   public:
56   void run(int sleeptime) {
57
58     NCursesPanel *mystd = new NCursesPanel();
59
60     //  Make a few small demo panels
61
62     NCursesPanel *u = new NCursesPanel(8, 20, 12, 4);
63     NCursesPanel *v = new NCursesPanel(8, 20, 10, 6);
64     NCursesPanel *w = new NCursesPanel(8, 20, 8, 8);
65     NCursesPanel *x = new NCursesPanel(8, 20, 6, 10);
66     NCursesPanel *y = new NCursesPanel(8, 20, 4, 12);
67     NCursesPanel *z = new NCursesPanel(8, 30, 2, 14);
68
69     //  Draw something on the main screen, so we can see what happens
70     //  when panels get moved or deleted.
71
72     mystd->box();
73     mystd->move(mystd->height()/2, 1);
74     mystd->hline(mystd->width()-2);
75     mystd->move(1, mystd->width()/2);
76     mystd->vline(mystd->height()-2);
77     mystd->addch(0, mystd->width()/2, ACS_TTEE);
78     mystd->addch(mystd->height()-1, mystd->width()/2, ACS_BTEE);
79     mystd->addch(mystd->height()/2, 0, ACS_LTEE);
80     mystd->addch(mystd->height()/2, mystd->width()-1, ACS_RTEE);
81     mystd->addch(mystd->height()/2, mystd->width()/2, ACS_PLUS);
82
83     //  Draw frames with titles around panels so that we can see where
84     //  the panels are located.
85     u->boldframe("Win U");
86     v->frame("Win V");
87     w->boldframe("Win W");
88     x->frame("Win X");
89     y->boldframe("Win Y");
90     z->frame("Win Z");
91     if (NCursesApplication::getApplication()->useColors()) {
92       u->bkgd(' '|COLOR_PAIR(1));
93       w->bkgd(' '|COLOR_PAIR(1));
94       y->bkgd(' '|COLOR_PAIR(1));
95       v->bkgd(' '|COLOR_PAIR(2));
96       x->bkgd(' '|COLOR_PAIR(2));
97       z->bkgd(' '|COLOR_PAIR(2));
98     }
99
100     //  A refresh to any valid panel updates all panels and refreshes
101     //  the screen.  Using mystd is just convenient - We know it's always
102     //  valid until the end of the program.
103
104     mystd->refresh();
105     sleep(sleeptime);
106
107     //  Show what happens when panels are deleted and moved.
108
109     sleep(sleeptime);
110     delete u;
111     mystd->refresh();
112
113     sleep(sleeptime);
114     delete z;
115     mystd->refresh();
116
117     sleep(sleeptime);
118     delete v;
119     mystd->refresh();
120
121     // show how it looks when a panel moves
122     sleep(sleeptime);
123     y->mvwin(5, 30);
124     mystd->refresh();
125
126     sleep(sleeptime);
127     delete y;
128     mystd->refresh();
129
130     // show how it looks when you raise a panel
131     sleep(sleeptime);
132     w->top();
133     mystd->refresh();
134
135     sleep(sleeptime);
136     delete w;
137     mystd->refresh();
138
139     sleep(sleeptime);
140     delete x;
141
142     mystd->clear();
143     mystd->refresh();
144
145     //  Don't forget to clean up the main screen.  Since this is the
146     //  last thing using NCursesWindow, this has the effect of
147     //  shutting down ncurses and restoring the terminal state.
148
149     sleep(sleeptime);
150     delete mystd;
151   }
152 };
153
154 class UserData
155 {
156 private:
157   int u;
158 public:
159   UserData(int x) : u(x) {}
160   int sleeptime() const { return u; }
161 };
162 //
163 // -------------------------------------------------------------------------
164 //
165 template<class T> class MyAction : public NCursesUserItem<T>
166 {
167 public:
168   MyAction (const char* p_name,
169             const T* p_UserData)
170     : NCursesUserItem<T>(p_name, static_cast<const char*>(0), p_UserData)
171   {}
172
173   virtual ~MyAction() {}
174
175   bool action() {
176     SillyDemo a;
177     a.run(NCursesUserItem<T>::UserData()->sleeptime());
178     return FALSE;
179   }
180 };
181
182 template class MyAction<UserData>;
183 template class NCURSES_IMPEXP NCursesUserItem<UserData>;
184
185 class QuitItem : public NCursesMenuItem
186 {
187 public:
188   QuitItem() : NCursesMenuItem("Quit") {
189   }
190
191   bool action() {
192     return TRUE;
193   }
194 };
195 //
196 // -------------------------------------------------------------------------
197 //
198 class Label : public NCursesFormField
199 {
200 public:
201   Label(const char* title,
202         int row, int col)
203     : NCursesFormField(1, static_cast<int>(::strlen(title)), row, col) {
204       set_value(title);
205       options_off(O_EDIT|O_ACTIVE);
206   }
207 };
208 //
209 // -------------------------------------------------------------------------
210 //
211 class MyFieldType : public UserDefinedFieldType
212 {
213 private:
214   int chk;
215 protected:
216   bool field_check(NCursesFormField& f) {
217     return TRUE;
218   }
219   bool char_check(int c) {
220     return (c==chk?TRUE:FALSE);
221   }
222 public:
223   MyFieldType(int x) : chk(x) {
224   }
225 };
226 //
227 // -------------------------------------------------------------------------
228 //
229 class TestForm : public NCursesForm
230 {
231 private:
232   NCursesFormField** F;
233   MyFieldType* mft;
234   Integer_Field *ift;
235   Enumeration_Field *eft;
236
237   static const char *weekdays[];
238
239 public:
240   TestForm()
241     : NCursesForm(13, 51, (lines() - 15)/2, (cols() - 53)/2),
242       F(0),
243       mft(0),
244       ift(0),
245       eft(0)
246   {
247
248     F     = new NCursesFormField*[10];
249     mft   = new MyFieldType('X');
250     ift   = new Integer_Field(0, 1, 10);
251     eft   = new Enumeration_Field(weekdays);
252
253     F[0]  = new Label("Demo Entry Form", 0, 16);
254     F[1]  = new Label("Weekday Enum", 2, 1);
255     F[2]  = new Label("Number(1-10)", 2, 21);
256     F[3]  = new Label("Only 'X'", 2, 35);
257     F[4]  = new Label("Multiline Field (Dynamic and Scrollable)", 5, 1);
258     F[5]  = new NCursesFormField(1, 18, 3, 1);
259     F[6]  = new NCursesFormField(1, 12, 3, 21);
260     F[7]  = new NCursesFormField(1, 12, 3, 35);
261     F[8]  = new NCursesFormField(4, 46, 6, 1, 2);
262     F[9]  = new NCursesFormField();
263
264     InitForm(F, TRUE, TRUE);
265     boldframe();
266
267     F[5]->set_fieldtype(*eft);
268     F[6]->set_fieldtype(*ift);
269
270     F[7]->set_fieldtype(*mft);
271     F[7]->set_maximum_growth(20); // max. 20 characters
272     F[7]->options_off(O_STATIC);  // make field dynamic
273
274     F[8]->set_maximum_growth(10); // max. 10 lines
275     F[8]->options_off(O_STATIC);  // make field dynamic
276   }
277
278   TestForm& operator=(const TestForm& rhs)
279   {
280     if (this != &rhs) {
281       *this = rhs;
282     }
283     return *this;
284   }
285
286   TestForm(const TestForm& rhs)
287     : NCursesForm(rhs), F(0), mft(0), ift(0), eft(0)
288   {
289   }
290
291   ~TestForm() {
292     delete mft;
293     delete ift;
294     delete eft;
295   }
296 };
297
298 const char* TestForm::weekdays[] = {
299     "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
300     "Friday", "Saturday", NULL };
301 //
302 // -------------------------------------------------------------------------
303 //
304 class FormAction : public NCursesMenuItem
305 {
306 public:
307   FormAction(const char *s) : NCursesMenuItem(s) {
308   }
309
310   bool action() {
311     TestForm F;
312     Soft_Label_Key_Set* S = new Soft_Label_Key_Set;
313     for(int i=1; i <= S->labels(); i++) {
314       char buf[8];
315       assert(i < 100);
316       ::sprintf(buf, "Frm%02d", i);
317       (*S)[i] = buf;                                      // Text
318       (*S)[i] = Soft_Label_Key_Set::Soft_Label_Key::Left; // Justification
319     }
320     NCursesApplication::getApplication()->push(*S);
321     F();
322     NCursesApplication::getApplication()->pop();
323     delete S;
324     return FALSE;
325   }
326 };
327 //
328 // -------------------------------------------------------------------------
329 //
330 class PadAction : public NCursesMenuItem
331 {
332 public:
333   PadAction(const char* s) : NCursesMenuItem(s) {
334   }
335
336   bool action() {
337     const int GRIDSIZE = 3;
338     const int PADSIZE  = 200;
339     unsigned gridcount = 0;
340
341     NCursesPanel mystd;
342     NCursesPanel P(mystd.lines()-2, mystd.cols()-2, 1, 1);
343     NCursesFramedPad FP(P, PADSIZE, PADSIZE);
344
345     for (int i=0; i < PADSIZE; i++) {
346       for (int j=0; j < PADSIZE; j++) {
347         if (i % GRIDSIZE == 0 && j % GRIDSIZE == 0) {
348           if (i==0 || j==0)
349             FP.addch('+');
350           else
351             FP.addch(static_cast<chtype>('A' + (gridcount++ % 26)));
352         }
353         else if (i % GRIDSIZE == 0)
354           FP.addch('-');
355         else if (j % GRIDSIZE == 0)
356           FP.addch('|');
357         else
358           FP.addch(' ');
359       }
360     }
361
362     P.label("Pad Demo", NULL);
363     FP();
364     P.clear();
365     return FALSE;
366   }
367 };
368
369 //
370 // -------------------------------------------------------------------------
371 //
372 class PassiveItem : public NCursesMenuItem
373 {
374 public:
375   PassiveItem(const char* text) : NCursesMenuItem(text) {
376     options_off(O_SELECTABLE);
377   }
378 };
379
380 //
381 // -------------------------------------------------------------------------
382 //
383 class ScanAction : public NCursesMenuItem
384 {
385 public:
386   ScanAction(const char* s) : NCursesMenuItem(s) {
387   }
388
389   bool action() {
390     NCursesPanel *mystd = new NCursesPanel();
391
392     NCursesPanel *w = new NCursesPanel(mystd->lines() - 2, mystd->cols() - 2, 1, 1);
393     w->box();
394     w->refresh();
395
396     NCursesPanel *s = new NCursesPanel(w->lines() - 6, w->cols() - 6, 3, 3);
397     s->scrollok(TRUE);
398     ::echo();
399
400     s->printw("Enter decimal integers.  The running total will be shown\n");
401     int nvalue = -1;
402     int result = 0;
403     while (nvalue != 0) {
404       nvalue = 0;
405       s->scanw("%d", &nvalue);
406       if (nvalue != 0) {
407         s->printw("%d: ", result += nvalue);
408       }
409       s->refresh();
410     }
411     s->printw("\nPress any key to continue...");
412     s->getch();
413
414     delete s;
415     delete w;
416     delete mystd;
417     ::noecho();
418     return FALSE;
419   }
420 };
421
422 //
423 // -------------------------------------------------------------------------
424 //
425 class MyMenu : public NCursesMenu
426 {
427 private:
428   NCursesPanel* P;
429   NCursesMenuItem** I;
430   UserData *u;
431   #define n_items 7
432
433 public:
434   MyMenu ()
435     : NCursesMenu (n_items+2, 8, (lines()-10)/2, (cols()-10)/2),
436       P(0), I(0), u(0)
437   {
438     u = new UserData(1);
439     I = new NCursesMenuItem*[1+n_items];
440     I[0] = new PassiveItem("One");
441     I[1] = new PassiveItem("Two");
442     I[2] = new MyAction<UserData> ("Silly", u);
443     I[3] = new FormAction("Form");
444     I[4] = new PadAction("Pad");
445     I[5] = new ScanAction("Scan");
446     I[6] = new QuitItem();
447     I[7] = new NCursesMenuItem(); // Terminating empty item
448
449     InitMenu(I, TRUE, TRUE);
450
451     P = new NCursesPanel(1, n_items, LINES-1, 1);
452     boldframe("Demo", "Silly");
453     P->show();
454   }
455
456   MyMenu& operator=(const MyMenu& rhs)
457   {
458     if (this != &rhs) {
459       *this = rhs;
460     }
461     return *this;
462   }
463
464   MyMenu(const MyMenu& rhs)
465     : NCursesMenu(rhs), P(0), I(0), u(0)
466   {
467   }
468
469   ~MyMenu()
470   {
471     P->hide();
472     delete P;
473     delete u;
474   }
475
476   virtual void On_Menu_Init()
477   {
478     NCursesWindow W(::stdscr);
479     P->move(0, 0);
480     P->clrtoeol();
481     for(int i=1; i<=count(); i++)
482       P->addch('0' + i);
483     P->bkgd(W.getbkgd());
484     refresh();
485   }
486
487   virtual void On_Menu_Termination()
488   {
489     P->move(0, 0);
490     P->clrtoeol();
491     refresh();
492   }
493
494   virtual void On_Item_Init(NCursesMenuItem& item)
495   {
496     P->move(0, item.index());
497     P->attron(A_REVERSE);
498     P->printw("%1d", 1+item.index());
499     P->attroff(A_REVERSE);
500     refresh();
501   }
502
503   virtual void On_Item_Termination(NCursesMenuItem& item)
504   {
505     P->move(0, item.index());
506     P->attroff(A_REVERSE);
507     P->printw("%1d", 1+item.index());
508     refresh();
509   }
510 };
511 //
512 // -------------------------------------------------------------------------
513 //
514 class TestApplication : public NCursesApplication
515 {
516 protected:
517   int titlesize() const { return 1; }
518   void title();
519   Soft_Label_Key_Set::Label_Layout useSLKs() const {
520     return Soft_Label_Key_Set::PC_Style_With_Index;
521   }
522   void init_labels(Soft_Label_Key_Set& S) const;
523
524 public:
525   TestApplication() : NCursesApplication(TRUE) {
526   }
527
528   int run();
529 };
530
531 void TestApplication::init_labels(Soft_Label_Key_Set& S) const
532 {
533   for(int i=1; i <= S.labels(); i++) {
534     char buf[8];
535     assert(i < 100);
536     ::sprintf(buf, "Key%02d", i);
537     S[i] = buf;                                      // Text
538     S[i] = Soft_Label_Key_Set::Soft_Label_Key::Left; // Justification
539   }
540 }
541
542 void TestApplication::title()
543 {
544   const char * const titleText = "Simple C++ Binding Demo";
545   const int len = ::strlen(titleText);
546
547   titleWindow->bkgd(screen_titles());
548   titleWindow->addstr(0, (titleWindow->cols() - len)/2, titleText);
549   titleWindow->noutrefresh();
550 }
551
552
553 int TestApplication::run()
554 {
555   MyMenu M;
556   M();
557   return 0;
558 }
559
560 //
561 // -------------------------------------------------------------------------
562 //
563 static TestApplication *Demo = new TestApplication();