ncurses 5.7 - patch 20100220
[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.39 2008/12/07 02:07:34 juergen Exp $
39  */
40
41 #include "internal.h"
42 #include "cursesapp.h"
43 #include "cursesm.h"
44 #include "cursesf.h"
45
46 #ifdef __MINGW32__
47 #undef KEY_EVENT
48 #endif
49
50 #ifndef __MINGW32__
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     return TRUE;
224   }
225   bool char_check(int c) {
226     return (c==chk?TRUE:FALSE);
227   }
228 public:
229   MyFieldType(int x) : chk(x) {
230   }
231 };
232 //
233 // -------------------------------------------------------------------------
234 //
235 class TestForm : public NCursesForm
236 {
237 private:
238   NCursesFormField** F;
239   MyFieldType* mft;
240   Integer_Field *ift;
241   Enumeration_Field *eft;
242
243   static const char *weekdays[];
244
245 public:
246   TestForm()
247     : NCursesForm(13, 51, (lines() - 15)/2, (cols() - 53)/2),
248       F(0),
249       mft(0),
250       ift(0),
251       eft(0)
252   {
253
254     F     = new NCursesFormField*[10];
255     mft   = new MyFieldType('X');
256     ift   = new Integer_Field(0, 1, 10);
257     eft   = new Enumeration_Field(weekdays);
258
259     F[0]  = new Label("Demo Entry Form", 0, 16);
260     F[1]  = new Label("Weekday Enum", 2, 1);
261     F[2]  = new Label("Number(1-10)", 2, 21);
262     F[3]  = new Label("Only 'X'", 2, 35);
263     F[4]  = new Label("Multiline Field (Dynamic and Scrollable)", 5, 1);
264     F[5]  = new NCursesFormField(1, 18, 3, 1);
265     F[6]  = new NCursesFormField(1, 12, 3, 21);
266     F[7]  = new NCursesFormField(1, 12, 3, 35);
267     F[8]  = new NCursesFormField(4, 46, 6, 1, 2);
268     F[9]  = new NCursesFormField();
269
270     InitForm(F, TRUE, TRUE);
271     boldframe();
272
273     F[5]->set_fieldtype(*eft);
274     F[6]->set_fieldtype(*ift);
275
276     F[7]->set_fieldtype(*mft);
277     F[7]->set_maximum_growth(20); // max. 20 characters
278     F[7]->options_off(O_STATIC);  // make field dynamic
279
280     F[8]->set_maximum_growth(10); // max. 10 lines
281     F[8]->options_off(O_STATIC);  // make field dynamic
282   }
283
284   TestForm& operator=(const TestForm& rhs)
285   {
286     if (this != &rhs) {
287       *this = rhs;
288     }
289     return *this;
290   }
291
292   TestForm(const TestForm& rhs)
293     : NCursesForm(rhs), F(0), mft(0), ift(0), eft(0)
294   {
295   }
296
297   ~TestForm() {
298     delete mft;
299     delete ift;
300     delete eft;
301   }
302 };
303
304 const char* TestForm::weekdays[] = {
305     "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
306     "Friday", "Saturday", NULL };
307 //
308 // -------------------------------------------------------------------------
309 //
310 class FormAction : public NCursesMenuItem
311 {
312 public:
313   FormAction(const char *s) : NCursesMenuItem(s) {
314   }
315
316   bool action() {
317     TestForm F;
318     Soft_Label_Key_Set* S = new Soft_Label_Key_Set;
319     for(int i=1; i <= S->labels(); i++) {
320       char buf[8];
321       assert(i < 100);
322       ::sprintf(buf, "Frm%02d", i);
323       (*S)[i] = buf;                                      // Text
324       (*S)[i] = Soft_Label_Key_Set::Soft_Label_Key::Left; // Justification
325     }
326     NCursesApplication::getApplication()->push(*S);
327     F();
328     NCursesApplication::getApplication()->pop();
329     delete S;
330     return FALSE;
331   }
332 };
333 //
334 // -------------------------------------------------------------------------
335 //
336 class PadAction : public NCursesMenuItem
337 {
338 public:
339   PadAction(const char* s) : NCursesMenuItem(s) {
340   }
341
342   bool action() {
343     const int GRIDSIZE = 3;
344     const int PADSIZE  = 200;
345     unsigned gridcount = 0;
346
347     NCursesPanel mystd;
348     NCursesPanel P(mystd.lines()-2, mystd.cols()-2, 1, 1);
349     NCursesFramedPad FP(P, PADSIZE, PADSIZE);
350
351     for (int i=0; i < PADSIZE; i++) {
352       for (int j=0; j < PADSIZE; j++) {
353         if (i % GRIDSIZE == 0 && j % GRIDSIZE == 0) {
354           if (i==0 || j==0)
355             FP.addch('+');
356           else
357             FP.addch(static_cast<chtype>('A' + (gridcount++ % 26)));
358         }
359         else if (i % GRIDSIZE == 0)
360           FP.addch('-');
361         else if (j % GRIDSIZE == 0)
362           FP.addch('|');
363         else
364           FP.addch(' ');
365       }
366     }
367
368     P.label("Pad Demo", NULL);
369     FP();
370     P.clear();
371     return FALSE;
372   }
373 };
374
375 //
376 // -------------------------------------------------------------------------
377 //
378 class PassiveItem : public NCursesMenuItem
379 {
380 public:
381   PassiveItem(const char* text) : NCursesMenuItem(text) {
382     options_off(O_SELECTABLE);
383   }
384 };
385
386 //
387 // -------------------------------------------------------------------------
388 //
389 class ScanAction : public NCursesMenuItem
390 {
391 public:
392   ScanAction(const char* s) : NCursesMenuItem(s) {
393   }
394
395   bool action() {
396     NCursesPanel *mystd = new NCursesPanel();
397
398     NCursesPanel *w = new NCursesPanel(mystd->lines() - 2, mystd->cols() - 2, 1, 1);
399     w->box();
400     w->refresh();
401
402     NCursesPanel *s = new NCursesPanel(w->lines() - 6, w->cols() - 6, 3, 3);
403     s->scrollok(TRUE);
404     ::echo();
405
406     s->printw("Enter decimal integers.  The running total will be shown\n");
407     int nvalue = -1;
408     int result = 0;
409     while (nvalue != 0) {
410       nvalue = 0;
411       s->scanw("%d", &nvalue);
412       if (nvalue != 0) {
413         s->printw("%d: ", result += nvalue);
414       }
415       s->refresh();
416     }
417     s->printw("\nPress any key to continue...");
418     s->getch();
419
420     delete s;
421     delete w;
422     delete mystd;
423     ::noecho();
424     return FALSE;
425   }
426 };
427
428 //
429 // -------------------------------------------------------------------------
430 //
431 class MyMenu : public NCursesMenu
432 {
433 private:
434   NCursesPanel* P;
435   NCursesMenuItem** I;
436   UserData *u;
437   #define n_items 7
438
439 public:
440   MyMenu ()
441     : NCursesMenu (n_items+2, 8, (lines()-10)/2, (cols()-10)/2),
442       P(0), I(0), u(0)
443   {
444     u = new UserData(1);
445     I = new NCursesMenuItem*[1+n_items];
446     I[0] = new PassiveItem("One");
447     I[1] = new PassiveItem("Two");
448     I[2] = new MyAction<UserData> ("Silly", u);
449     I[3] = new FormAction("Form");
450     I[4] = new PadAction("Pad");
451     I[5] = new ScanAction("Scan");
452     I[6] = new QuitItem();
453     I[7] = new NCursesMenuItem(); // Terminating empty item
454
455     InitMenu(I, TRUE, TRUE);
456
457     P = new NCursesPanel(1, n_items, LINES-1, 1);
458     boldframe("Demo", "Silly");
459     P->show();
460   }
461
462   MyMenu& operator=(const MyMenu& rhs)
463   {
464     if (this != &rhs) {
465       *this = rhs;
466     }
467     return *this;
468   }
469
470   MyMenu(const MyMenu& rhs)
471     : NCursesMenu(rhs), P(0), I(0), u(0)
472   {
473   }
474
475   ~MyMenu()
476   {
477     P->hide();
478     delete P;
479     delete u;
480   }
481
482   virtual void On_Menu_Init()
483   {
484     NCursesWindow W(::stdscr);
485     P->move(0, 0);
486     P->clrtoeol();
487     for(int i=1; i<=count(); i++)
488       P->addch('0' + i);
489     P->bkgd(W.getbkgd());
490     refresh();
491   }
492
493   virtual void On_Menu_Termination()
494   {
495     P->move(0, 0);
496     P->clrtoeol();
497     refresh();
498   }
499
500   virtual void On_Item_Init(NCursesMenuItem& item)
501   {
502     P->move(0, item.index());
503     P->attron(A_REVERSE);
504     P->printw("%1d", 1+item.index());
505     P->attroff(A_REVERSE);
506     refresh();
507   }
508
509   virtual void On_Item_Termination(NCursesMenuItem& item)
510   {
511     P->move(0, item.index());
512     P->attroff(A_REVERSE);
513     P->printw("%1d", 1+item.index());
514     refresh();
515   }
516 };
517 //
518 // -------------------------------------------------------------------------
519 //
520 class TestApplication : public NCursesApplication
521 {
522 protected:
523   int titlesize() const { return 1; }
524   void title();
525   Soft_Label_Key_Set::Label_Layout useSLKs() const {
526     return Soft_Label_Key_Set::PC_Style_With_Index;
527   }
528   void init_labels(Soft_Label_Key_Set& S) const;
529
530 public:
531   TestApplication() : NCursesApplication(TRUE) {
532   }
533
534   int run();
535 };
536
537 void TestApplication::init_labels(Soft_Label_Key_Set& S) const
538 {
539   for(int i=1; i <= S.labels(); i++) {
540     char buf[8];
541     assert(i < 100);
542     ::sprintf(buf, "Key%02d", i);
543     S[i] = buf;                                      // Text
544     S[i] = Soft_Label_Key_Set::Soft_Label_Key::Left; // Justification
545   }
546 }
547
548 void TestApplication::title()
549 {
550   const char * const titleText = "Simple C++ Binding Demo";
551   const int len = ::strlen(titleText);
552
553   titleWindow->bkgd(screen_titles());
554   titleWindow->addstr(0, (titleWindow->cols() - len)/2, titleText);
555   titleWindow->noutrefresh();
556 }
557
558
559 int TestApplication::run()
560 {
561   MyMenu M;
562   M();
563   return 0;
564 }
565
566 //
567 // -------------------------------------------------------------------------
568 //
569 static TestApplication *Demo = new TestApplication();