ncurses 5.6
[ncurses.git] / c++ / demo.cc
1 // * This makes emacs happy -*-Mode: C++;-*-
2 /****************************************************************************
3  * Copyright (c) 1998-2005,2006 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.34 2006/04/22 22:38: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 *std = 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     std->box();
73     std->move(std->height()/2,1);
74     std->hline(std->width()-2);
75     std->move(1,std->width()/2);
76     std->vline(std->height()-2);
77     std->addch(0,std->width()/2,ACS_TTEE);
78     std->addch(std->height()-1,std->width()/2,ACS_BTEE);
79     std->addch(std->height()/2,0,ACS_LTEE);
80     std->addch(std->height()/2,std->width()-1,ACS_RTEE);
81     std->addch(std->height()/2,std->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 std is just convenient - We know it's always
102     //  valid until the end of the program.
103
104     std->refresh();
105     sleep(sleeptime);
106
107     //  Show what happens when panels are deleted and moved.
108
109     sleep(sleeptime);
110     delete u;
111     std->refresh();
112
113     sleep(sleeptime);
114     delete z;
115     std->refresh();
116
117     sleep(sleeptime);
118     delete v;
119     std->refresh();
120
121     // show how it looks when a panel moves
122     sleep(sleeptime);
123     y->mvwin(5,30);
124     std->refresh();
125
126     sleep(sleeptime);
127     delete y;
128     std->refresh();
129
130     // show how it looks when you raise a panel
131     sleep(sleeptime);
132     w->top();
133     std->refresh();
134
135     sleep(sleeptime);
136     delete w;
137     std->refresh();
138
139     sleep(sleeptime);
140     delete x;
141
142     std->clear();
143     std->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 std;
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       ::sprintf(buf,"Frm%02d",i);
316       (*S)[i] = buf;                                      // Text
317       (*S)[i] = Soft_Label_Key_Set::Soft_Label_Key::Left; // Justification
318     }
319     NCursesApplication::getApplication()->push(*S);
320     F();
321     NCursesApplication::getApplication()->pop();
322     return FALSE;
323   }
324 };
325 //
326 // -------------------------------------------------------------------------
327 //
328 class PadAction : public NCursesMenuItem
329 {
330 public:
331   PadAction(const char* s) : NCursesMenuItem(s) {
332   }
333
334   bool action() {
335     const int GRIDSIZE = 3;
336     const int PADSIZE  = 200;
337     unsigned gridcount = 0;
338
339     NCursesPanel std;
340     NCursesPanel P(std.lines()-2,std.cols()-2,1,1);
341     NCursesFramedPad FP(P,PADSIZE,PADSIZE);
342
343     for (int i=0; i < PADSIZE; i++) {
344       for (int j=0; j < PADSIZE; j++) {
345         if (i % GRIDSIZE == 0 && j % GRIDSIZE == 0) {
346           if (i==0 || j==0)
347             FP.addch('+');
348           else
349             FP.addch(static_cast<chtype>('A' + (gridcount++ % 26)));
350         }
351         else if (i % GRIDSIZE == 0)
352           FP.addch('-');
353         else if (j % GRIDSIZE == 0)
354           FP.addch('|');
355         else
356           FP.addch(' ');
357       }
358     }
359
360     P.label("Pad Demo",NULL);
361     FP();
362     P.clear();
363     return FALSE;
364   }
365 };
366
367 //
368 // -------------------------------------------------------------------------
369 //
370 class PassiveItem : public NCursesMenuItem
371 {
372 public:
373   PassiveItem(const char* text) : NCursesMenuItem(text) {
374     options_off(O_SELECTABLE);
375   }
376 };
377
378 //
379 // -------------------------------------------------------------------------
380 //
381 class ScanAction : public NCursesMenuItem
382 {
383 public:
384   ScanAction(const char* s) : NCursesMenuItem(s) {
385   }
386
387   bool action() {
388     NCursesPanel *std = new NCursesPanel();
389
390     NCursesPanel *w = new NCursesPanel(std->lines() - 2, std->cols() - 2, 1, 1);
391     w->box();
392     w->refresh();
393
394     NCursesPanel *s = new NCursesPanel(w->lines() - 6, w->cols() - 6, 3, 3);
395     s->scrollok(TRUE);
396     ::echo();
397
398     s->printw("Enter decimal integers.  The running total will be shown\n");
399     int nvalue = -1;
400     int result = 0;
401     while (nvalue != 0) {
402       nvalue = 0;
403       s->scanw("%d", &nvalue);
404       if (nvalue != 0) {
405         s->printw("%d: ", result += nvalue);
406       }
407       s->refresh();
408     }
409     s->printw("\nPress any key to continue...");
410     s->getch();
411
412     delete s;
413     delete w;
414     delete std;
415     ::noecho();
416     return FALSE;
417   }
418 };
419
420 //
421 // -------------------------------------------------------------------------
422 //
423 class MyMenu : public NCursesMenu
424 {
425 private:
426   NCursesPanel* P;
427   NCursesMenuItem** I;
428   UserData *u;
429   #define n_items 7
430
431 public:
432   MyMenu ()
433     : NCursesMenu (n_items+2, 8, (lines()-10)/2, (cols()-10)/2),
434       P(0), I(0), u(0)
435   {
436     u = new UserData(1);
437     I = new NCursesMenuItem*[1+n_items];
438     I[0] = new PassiveItem("One");
439     I[1] = new PassiveItem("Two");
440     I[2] = new MyAction<UserData> ("Silly", u);
441     I[3] = new FormAction("Form");
442     I[4] = new PadAction("Pad");
443     I[5] = new ScanAction("Scan");
444     I[6] = new QuitItem();
445     I[7] = new NCursesMenuItem(); // Terminating empty item
446
447     InitMenu(I,TRUE,TRUE);
448
449     P = new NCursesPanel(1,n_items,LINES-1,1);
450     boldframe("Demo","Silly");
451     P->show();
452   }
453
454   MyMenu& operator=(const MyMenu& rhs)
455   {
456     if (this != &rhs) {
457       *this = rhs;
458     }
459     return *this;
460   }
461
462   MyMenu(const MyMenu& rhs)
463     : NCursesMenu(rhs), P(0), I(0), u(0)
464   {
465   }
466
467   ~MyMenu()
468   {
469     P->hide();
470     delete P;
471     delete u;
472   }
473
474   virtual void On_Menu_Init()
475   {
476     NCursesWindow W(::stdscr);
477     P->move(0,0);
478     P->clrtoeol();
479     for(int i=1; i<=count(); i++)
480       P->addch('0' + i);
481     P->bkgd(W.getbkgd());
482     refresh();
483   }
484
485   virtual void On_Menu_Termination()
486   {
487     P->move(0,0);
488     P->clrtoeol();
489     refresh();
490   }
491
492   virtual void On_Item_Init(NCursesMenuItem& item)
493   {
494     P->move(0,item.index());
495     P->attron(A_REVERSE);
496     P->printw("%1d",1+item.index());
497     P->attroff(A_REVERSE);
498     refresh();
499   }
500
501   virtual void On_Item_Termination(NCursesMenuItem& item)
502   {
503     P->move(0,item.index());
504     P->attroff(A_REVERSE);
505     P->printw("%1d",1+item.index());
506     refresh();
507   }
508 };
509 //
510 // -------------------------------------------------------------------------
511 //
512 class TestApplication : public NCursesApplication
513 {
514 protected:
515   int titlesize() const { return 1; }
516   void title();
517   Soft_Label_Key_Set::Label_Layout useSLKs() const {
518     return Soft_Label_Key_Set::PC_Style_With_Index;
519   }
520   void init_labels(Soft_Label_Key_Set& S) const;
521
522 public:
523   TestApplication() : NCursesApplication(TRUE) {
524   }
525
526   int run();
527 };
528
529 void TestApplication::init_labels(Soft_Label_Key_Set& S) const
530 {
531   for(int i=1; i <= S.labels(); i++) {
532     char buf[8];
533     ::sprintf(buf,"Key%02d",i);
534     S[i] = buf;                                      // Text
535     S[i] = Soft_Label_Key_Set::Soft_Label_Key::Left; // Justification
536   }
537 }
538
539 void TestApplication::title()
540 {
541   const char * const titleText = "Simple C++ Binding Demo";
542   const int len = ::strlen(titleText);
543
544   titleWindow->bkgd(screen_titles());
545   titleWindow->addstr(0,(titleWindow->cols() - len)/2, titleText);
546   titleWindow->noutrefresh();
547 }
548
549
550 int TestApplication::run()
551 {
552   MyMenu M;
553   M();
554   return 0;
555 }
556
557 //
558 // -------------------------------------------------------------------------
559 //
560 static TestApplication Demo;