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