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