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