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.38 2008/08/04 17:16:57 tom Exp $
39 */
40
41#include "internal.h"
42#include "cursesapp.h"
43#include "cursesm.h"
44#include "cursesf.h"
45
46extern "C" unsigned int sleep(unsigned int);
47
48#undef index // needed for NeXT
49
50//
51// -------------------------------------------------------------------------
52//
53class SillyDemo
54{
55  public:
56  void run(int sleeptime) {
57
58    NCursesPanel *mystd = 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    mystd->box();
73    mystd->move(mystd->height()/2, 1);
74    mystd->hline(mystd->width()-2);
75    mystd->move(1, mystd->width()/2);
76    mystd->vline(mystd->height()-2);
77    mystd->addch(0, mystd->width()/2, ACS_TTEE);
78    mystd->addch(mystd->height()-1, mystd->width()/2, ACS_BTEE);
79    mystd->addch(mystd->height()/2, 0, ACS_LTEE);
80    mystd->addch(mystd->height()/2, mystd->width()-1, ACS_RTEE);
81    mystd->addch(mystd->height()/2, mystd->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 mystd is just convenient - We know it's always
102    //  valid until the end of the program.
103
104    mystd->refresh();
105    sleep(sleeptime);
106
107    //  Show what happens when panels are deleted and moved.
108
109    sleep(sleeptime);
110    delete u;
111    mystd->refresh();
112
113    sleep(sleeptime);
114    delete z;
115    mystd->refresh();
116
117    sleep(sleeptime);
118    delete v;
119    mystd->refresh();
120
121    // show how it looks when a panel moves
122    sleep(sleeptime);
123    y->mvwin(5, 30);
124    mystd->refresh();
125
126    sleep(sleeptime);
127    delete y;
128    mystd->refresh();
129
130    // show how it looks when you raise a panel
131    sleep(sleeptime);
132    w->top();
133    mystd->refresh();
134
135    sleep(sleeptime);
136    delete w;
137    mystd->refresh();
138
139    sleep(sleeptime);
140    delete x;
141
142    mystd->clear();
143    mystd->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 mystd;
151  }
152};
153
154class UserData
155{
156private:
157  int u;
158public:
159  UserData(int x) : u(x) {}
160  int sleeptime() const { return u; }
161};
162//
163// -------------------------------------------------------------------------
164//
165template<class T> class MyAction : public NCursesUserItem<T>
166{
167public:
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
182template class MyAction<UserData>;
183template class NCURSES_IMPEXP NCursesUserItem<UserData>;
184
185class QuitItem : public NCursesMenuItem
186{
187public:
188  QuitItem() : NCursesMenuItem("Quit") {
189  }
190
191  bool action() {
192    return TRUE;
193  }
194};
195//
196// -------------------------------------------------------------------------
197//
198class Label : public NCursesFormField
199{
200public:
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//
211class MyFieldType : public UserDefinedFieldType
212{
213private:
214  int chk;
215protected:
216  bool field_check(NCursesFormField& f) {
217    return TRUE;
218  }
219  bool char_check(int c) {
220    return (c==chk?TRUE:FALSE);
221  }
222public:
223  MyFieldType(int x) : chk(x) {
224  }
225};
226//
227// -------------------------------------------------------------------------
228//
229class TestForm : public NCursesForm
230{
231private:
232  NCursesFormField** F;
233  MyFieldType* mft;
234  Integer_Field *ift;
235  Enumeration_Field *eft;
236
237  static const char *weekdays[];
238
239public:
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
298const char* TestForm::weekdays[] = {
299    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
300    "Friday", "Saturday", NULL };
301//
302// -------------------------------------------------------------------------
303//
304class FormAction : public NCursesMenuItem
305{
306public:
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      assert(i < 100);
316      ::sprintf(buf, "Frm%02d", i);
317      (*S)[i] = buf;                                      // Text
318      (*S)[i] = Soft_Label_Key_Set::Soft_Label_Key::Left; // Justification
319    }
320    NCursesApplication::getApplication()->push(*S);
321    F();
322    NCursesApplication::getApplication()->pop();
323    delete S;
324    return FALSE;
325  }
326};
327//
328// -------------------------------------------------------------------------
329//
330class PadAction : public NCursesMenuItem
331{
332public:
333  PadAction(const char* s) : NCursesMenuItem(s) {
334  }
335
336  bool action() {
337    const int GRIDSIZE = 3;
338    const int PADSIZE  = 200;
339    unsigned gridcount = 0;
340
341    NCursesPanel mystd;
342    NCursesPanel P(mystd.lines()-2, mystd.cols()-2, 1, 1);
343    NCursesFramedPad FP(P, PADSIZE, PADSIZE);
344
345    for (int i=0; i < PADSIZE; i++) {
346      for (int j=0; j < PADSIZE; j++) {
347        if (i % GRIDSIZE == 0 && j % GRIDSIZE == 0) {
348          if (i==0 || j==0)
349            FP.addch('+');
350          else
351            FP.addch(static_cast<chtype>('A' + (gridcount++ % 26)));
352        }
353        else if (i % GRIDSIZE == 0)
354          FP.addch('-');
355        else if (j % GRIDSIZE == 0)
356          FP.addch('|');
357        else
358          FP.addch(' ');
359      }
360    }
361
362    P.label("Pad Demo", NULL);
363    FP();
364    P.clear();
365    return FALSE;
366  }
367};
368
369//
370// -------------------------------------------------------------------------
371//
372class PassiveItem : public NCursesMenuItem
373{
374public:
375  PassiveItem(const char* text) : NCursesMenuItem(text) {
376    options_off(O_SELECTABLE);
377  }
378};
379
380//
381// -------------------------------------------------------------------------
382//
383class ScanAction : public NCursesMenuItem
384{
385public:
386  ScanAction(const char* s) : NCursesMenuItem(s) {
387  }
388
389  bool action() {
390    NCursesPanel *mystd = new NCursesPanel();
391
392    NCursesPanel *w = new NCursesPanel(mystd->lines() - 2, mystd->cols() - 2, 1, 1);
393    w->box();
394    w->refresh();
395
396    NCursesPanel *s = new NCursesPanel(w->lines() - 6, w->cols() - 6, 3, 3);
397    s->scrollok(TRUE);
398    ::echo();
399
400    s->printw("Enter decimal integers.  The running total will be shown\n");
401    int nvalue = -1;
402    int result = 0;
403    while (nvalue != 0) {
404      nvalue = 0;
405      s->scanw("%d", &nvalue);
406      if (nvalue != 0) {
407        s->printw("%d: ", result += nvalue);
408      }
409      s->refresh();
410    }
411    s->printw("\nPress any key to continue...");
412    s->getch();
413
414    delete s;
415    delete w;
416    delete mystd;
417    ::noecho();
418    return FALSE;
419  }
420};
421
422//
423// -------------------------------------------------------------------------
424//
425class MyMenu : public NCursesMenu
426{
427private:
428  NCursesPanel* P;
429  NCursesMenuItem** I;
430  UserData *u;
431  #define n_items 7
432
433public:
434  MyMenu ()
435    : NCursesMenu (n_items+2, 8, (lines()-10)/2, (cols()-10)/2),
436      P(0), I(0), u(0)
437  {
438    u = new UserData(1);
439    I = new NCursesMenuItem*[1+n_items];
440    I[0] = new PassiveItem("One");
441    I[1] = new PassiveItem("Two");
442    I[2] = new MyAction<UserData> ("Silly", u);
443    I[3] = new FormAction("Form");
444    I[4] = new PadAction("Pad");
445    I[5] = new ScanAction("Scan");
446    I[6] = new QuitItem();
447    I[7] = new NCursesMenuItem(); // Terminating empty item
448
449    InitMenu(I, TRUE, TRUE);
450
451    P = new NCursesPanel(1, n_items, LINES-1, 1);
452    boldframe("Demo", "Silly");
453    P->show();
454  }
455
456  MyMenu& operator=(const MyMenu& rhs)
457  {
458    if (this != &rhs) {
459      *this = rhs;
460    }
461    return *this;
462  }
463
464  MyMenu(const MyMenu& rhs)
465    : NCursesMenu(rhs), P(0), I(0), u(0)
466  {
467  }
468
469  ~MyMenu()
470  {
471    P->hide();
472    delete P;
473    delete u;
474  }
475
476  virtual void On_Menu_Init()
477  {
478    NCursesWindow W(::stdscr);
479    P->move(0, 0);
480    P->clrtoeol();
481    for(int i=1; i<=count(); i++)
482      P->addch('0' + i);
483    P->bkgd(W.getbkgd());
484    refresh();
485  }
486
487  virtual void On_Menu_Termination()
488  {
489    P->move(0, 0);
490    P->clrtoeol();
491    refresh();
492  }
493
494  virtual void On_Item_Init(NCursesMenuItem& item)
495  {
496    P->move(0, item.index());
497    P->attron(A_REVERSE);
498    P->printw("%1d", 1+item.index());
499    P->attroff(A_REVERSE);
500    refresh();
501  }
502
503  virtual void On_Item_Termination(NCursesMenuItem& item)
504  {
505    P->move(0, item.index());
506    P->attroff(A_REVERSE);
507    P->printw("%1d", 1+item.index());
508    refresh();
509  }
510};
511//
512// -------------------------------------------------------------------------
513//
514class TestApplication : public NCursesApplication
515{
516protected:
517  int titlesize() const { return 1; }
518  void title();
519  Soft_Label_Key_Set::Label_Layout useSLKs() const {
520    return Soft_Label_Key_Set::PC_Style_With_Index;
521  }
522  void init_labels(Soft_Label_Key_Set& S) const;
523
524public:
525  TestApplication() : NCursesApplication(TRUE) {
526  }
527
528  int run();
529};
530
531void TestApplication::init_labels(Soft_Label_Key_Set& S) const
532{
533  for(int i=1; i <= S.labels(); i++) {
534    char buf[8];
535    assert(i < 100);
536    ::sprintf(buf, "Key%02d", i);
537    S[i] = buf;                                      // Text
538    S[i] = Soft_Label_Key_Set::Soft_Label_Key::Left; // Justification
539  }
540}
541
542void TestApplication::title()
543{
544  const char * const titleText = "Simple C++ Binding Demo";
545  const int len = ::strlen(titleText);
546
547  titleWindow->bkgd(screen_titles());
548  titleWindow->addstr(0, (titleWindow->cols() - len)/2, titleText);
549  titleWindow->noutrefresh();
550}
551
552
553int TestApplication::run()
554{
555  MyMenu M;
556  M();
557  return 0;
558}
559
560//
561// -------------------------------------------------------------------------
562//
563static TestApplication *Demo = new TestApplication();
564