+// * This makes emacs happy -*-Mode: C++;-*-
+/****************************************************************************
+ * Copyright 2018-2019,2020 Thomas E. Dickey *
+ * Copyright 1998-2012,2017 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
/*
* Silly demo program for the NCursesPanel class.
*
* written by Anatoly Ivasyuk (anatoly@nick.csh.rit.edu)
*
- * $Id: demo.cc,v 1.7 1997/05/05 20:53:41 tom Exp $
+ * Demo code for NCursesMenu and NCursesForm written by
+ * Juergen Pfeifer
+ *
+ * $Id: demo.cc,v 1.47 2020/07/18 19:57:11 anonymous.maarten Exp $
*/
-#include <stdlib.h>
-
+#include "internal.h"
+#include "cursesapp.h"
#include "cursesm.h"
+#include "cursesf.h"
-#if HAVE_LIBC_H
-# include <libc.h>
+#ifdef _WIN32
+#undef KEY_EVENT
#endif
-class SillyDemo
+#ifndef _WIN32
+extern "C" unsigned int sleep(unsigned int);
+#endif
+
+#undef index // needed for NeXT
+
+//
+// -------------------------------------------------------------------------
+//
+class SillyDemo
{
public:
void run(int sleeptime) {
- // We need to define a full screen panel for the main screen so
- // that when redraws happen, the main screen actually gets redrawn.
- // I think there may be a bug in the panels code which won't redraw
- // the main screen otherwise. Maybe someone out there can find it...
- NCursesPanel *std = new NCursesPanel();
+ NCursesPanel *mystd = new NCursesPanel();
// Make a few small demo panels
- NCursesPanel *u = new NCursesPanel(10,20,12,4);
- NCursesPanel *v = new NCursesPanel(10,20,10,6);
- NCursesPanel *w = new NCursesPanel(10,20,8,8);
- NCursesPanel *x = new NCursesPanel(10,20,6,10);
- NCursesPanel *y = new NCursesPanel(10,20,4,12);
- NCursesPanel *z = new NCursesPanel(10,30,2,14);
+ NCursesPanel *u = new NCursesPanel(8, 20, 12, 4);
+ NCursesPanel *v = new NCursesPanel(8, 20, 10, 6);
+ NCursesPanel *w = new NCursesPanel(8, 20, 8, 8);
+ NCursesPanel *x = new NCursesPanel(8, 20, 6, 10);
+ NCursesPanel *y = new NCursesPanel(8, 20, 4, 12);
+ NCursesPanel *z = new NCursesPanel(8, 30, 2, 14);
// Draw something on the main screen, so we can see what happens
// when panels get moved or deleted.
- std->box();
- std->move(10,0);
- std->hline('a',79);
- std->move(0,40);
- std->vline(20);
+ mystd->box();
+ mystd->move(mystd->height()/2, 1);
+ mystd->hline(mystd->width()-2);
+ mystd->move(1, mystd->width()/2);
+ mystd->vline(mystd->height()-2);
+ mystd->addch(0, mystd->width()/2, ACS_TTEE);
+ mystd->addch(mystd->height()-1, mystd->width()/2, ACS_BTEE);
+ mystd->addch(mystd->height()/2, 0, ACS_LTEE);
+ mystd->addch(mystd->height()/2, mystd->width()-1, ACS_RTEE);
+ mystd->addch(mystd->height()/2, mystd->width()/2, ACS_PLUS);
// Draw frames with titles around panels so that we can see where
// the panels are located.
-
u->boldframe("Win U");
v->frame("Win V");
w->boldframe("Win W");
x->frame("Win X");
y->boldframe("Win Y");
z->frame("Win Z");
+ if (NCursesApplication::getApplication()->useColors()) {
+ u->bkgd(' '|COLOR_PAIR(1));
+ w->bkgd(' '|COLOR_PAIR(1));
+ y->bkgd(' '|COLOR_PAIR(1));
+ v->bkgd(' '|COLOR_PAIR(2));
+ x->bkgd(' '|COLOR_PAIR(2));
+ z->bkgd(' '|COLOR_PAIR(2));
+ }
// A refresh to any valid panel updates all panels and refreshes
- // the screen. Using std is just convenient - We know it's always
+ // the screen. Using mystd is just convenient - We know it's always
// valid until the end of the program.
- std->refresh();
-
- // Show that things actually come back correctly when the screen
- // is cleared and the global NCursesPanel::redraw() is called.
-
- sleep(sleeptime);
- ::clear(); // call ncurses clear() directly
- ::wrefresh(stdscr); // call ncurses refresh directly
+ mystd->refresh();
sleep(sleeptime);
- NCursesPanel::redraw();
// Show what happens when panels are deleted and moved.
sleep(sleeptime);
delete u;
- std->refresh();
+ mystd->refresh();
sleep(sleeptime);
delete z;
- std->refresh();
+ mystd->refresh();
sleep(sleeptime);
delete v;
- std->refresh();
+ mystd->refresh();
// show how it looks when a panel moves
sleep(sleeptime);
- y->mvpan(5,30);
- std->refresh();
+ y->mvwin(5, 30);
+ mystd->refresh();
sleep(sleeptime);
delete y;
- std->refresh();
+ mystd->refresh();
// show how it looks when you raise a panel
sleep(sleeptime);
w->top();
- std->refresh();
+ mystd->refresh();
sleep(sleeptime);
delete w;
- std->refresh();
+ mystd->refresh();
sleep(sleeptime);
delete x;
- std->refresh();
+
+ mystd->clear();
+ mystd->refresh();
// Don't forget to clean up the main screen. Since this is the
// last thing using NCursesWindow, this has the effect of
// shutting down ncurses and restoring the terminal state.
sleep(sleeptime);
- delete std;
+ delete mystd;
}
};
-
class UserData
{
private:
int u;
public:
- UserData(int x) : u(x) {}
+ UserData(int x) : u(x) {}
int sleeptime() const { return u; }
-
};
-
+//
+// -------------------------------------------------------------------------
+//
template<class T> class MyAction : public NCursesUserItem<T>
{
public:
- MyAction (const T* p_UserData,
- const char* p_name)
- : NCursesUserItem<T>(p_UserData, p_name)
- {};
+ MyAction (const char* p_name,
+ const T* p_UserData)
+ : NCursesUserItem<T>(p_name, static_cast<const char*>(0), p_UserData)
+ {}
- ~MyAction() {}
+ virtual ~MyAction() THROWS(NCursesException) {}
bool action() {
SillyDemo a;
- a.run(UserData()->sleeptime());
+ a.run(NCursesUserItem<T>::UserData()->sleeptime());
return FALSE;
}
};
+template class MyAction<UserData>;
+template class NCURSES_CXX_IMPEXP NCursesUserItem<UserData>;
+
class QuitItem : public NCursesMenuItem
{
public:
}
bool action() {
- endwin();
return TRUE;
}
};
+//
+// -------------------------------------------------------------------------
+//
+class Label : public NCursesFormField
+{
+public:
+ Label(const char* title,
+ int row, int col)
+ : NCursesFormField(1, static_cast<int>(::strlen(title)), row, col) {
+ set_value(title);
+ options_off(O_EDIT|O_ACTIVE);
+ }
+};
+//
+// -------------------------------------------------------------------------
+//
+class MyFieldType : public UserDefinedFieldType
+{
+private:
+ int chk;
+protected:
+ bool field_check(NCursesFormField& f) {
+ (void) f;
+ return TRUE;
+ }
+ bool char_check(int c) {
+ return (c==chk?TRUE:FALSE);
+ }
+public:
+ MyFieldType(int x) : chk(x) {
+ }
+};
+//
+// -------------------------------------------------------------------------
+//
+class TestForm : public NCursesForm
+{
+private:
+ NCursesFormField** F;
+ MyFieldType* mft;
+ Integer_Field *ift;
+ Enumeration_Field *eft;
+
+ static const char *weekdays[];
+
+public:
+ TestForm()
+ : NCursesForm(13, 51, (lines() - 15)/2, (cols() - 53)/2),
+ F(0),
+ mft(0),
+ ift(0),
+ eft(0)
+ {
+
+ F = new NCursesFormField*[10];
+ mft = new MyFieldType('X');
+ ift = new Integer_Field(0, 1, 10);
+ eft = new Enumeration_Field(weekdays);
+
+ F[0] = new Label("Demo Entry Form", 0, 16);
+ F[1] = new Label("Weekday Enum", 2, 1);
+ F[2] = new Label("Number(1-10)", 2, 21);
+ F[3] = new Label("Only 'X'", 2, 35);
+ F[4] = new Label("Multiline Field (Dynamic and Scrollable)", 5, 1);
+ F[5] = new NCursesFormField(1, 18, 3, 1);
+ F[6] = new NCursesFormField(1, 12, 3, 21);
+ F[7] = new NCursesFormField(1, 12, 3, 35);
+ F[8] = new NCursesFormField(4, 46, 6, 1, 2);
+ F[9] = new NCursesFormField();
+
+ InitForm(F, TRUE, TRUE);
+ boldframe();
+
+ F[5]->set_fieldtype(*eft);
+ F[6]->set_fieldtype(*ift);
+
+ F[7]->set_fieldtype(*mft);
+ F[7]->set_maximum_growth(20); // max. 20 characters
+ F[7]->options_off(O_STATIC); // make field dynamic
+
+ F[8]->set_maximum_growth(10); // max. 10 lines
+ F[8]->options_off(O_STATIC); // make field dynamic
+ }
+ TestForm& operator=(const TestForm& rhs)
+ {
+ if (this != &rhs) {
+ *this = rhs;
+ }
+ return *this;
+ }
+
+ TestForm(const TestForm& rhs)
+ : NCursesForm(rhs), F(0), mft(0), ift(0), eft(0)
+ {
+ }
+
+ ~TestForm() THROWS(NCursesException) {
+ delete mft;
+ delete ift;
+ delete eft;
+ }
+};
+
+const char* TestForm::weekdays[] = {
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
+ "Friday", "Saturday", NULL };
+//
+// -------------------------------------------------------------------------
+//
+class FormAction : public NCursesMenuItem
+{
+public:
+ FormAction(const char *s) : NCursesMenuItem(s) {
+ }
+
+ bool action() {
+ TestForm F;
+ Soft_Label_Key_Set* S = new Soft_Label_Key_Set;
+ for(int i=1; i <= S->labels(); i++) {
+ char buf[8];
+ assert(i < 100);
+ ::_nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) "Frm%02d", i % 100);
+ (*S)[i] = buf; // Text
+ (*S)[i] = Soft_Label_Key_Set::Soft_Label_Key::Left; // Justification
+ }
+ NCursesApplication::getApplication()->push(*S);
+ F();
+ NCursesApplication::getApplication()->pop();
+ delete S;
+ return FALSE;
+ }
+};
+//
+// -------------------------------------------------------------------------
+//
+class PadAction : public NCursesMenuItem
+{
+public:
+ PadAction(const char* s) : NCursesMenuItem(s) {
+ }
+
+ bool action() {
+ const int GRIDSIZE = 3;
+ const int PADSIZE = 200;
+ unsigned gridcount = 0;
+
+ NCursesPanel mystd;
+ NCursesPanel P(mystd.lines()-2, mystd.cols()-2, 1, 1);
+ NCursesFramedPad FP(P, PADSIZE, PADSIZE);
+
+ for (int i=0; i < PADSIZE; i++) {
+ for (int j=0; j < PADSIZE; j++) {
+ if (i % GRIDSIZE == 0 && j % GRIDSIZE == 0) {
+ if (i==0 || j==0)
+ FP.addch('+');
+ else
+ FP.addch(static_cast<chtype>('A' + (gridcount++ % 26)));
+ }
+ else if (i % GRIDSIZE == 0)
+ FP.addch('-');
+ else if (j % GRIDSIZE == 0)
+ FP.addch('|');
+ else
+ FP.addch(' ');
+ }
+ }
+
+ P.label("Pad Demo", NULL);
+ FP();
+ P.clear();
+ return FALSE;
+ }
+};
+
+//
+// -------------------------------------------------------------------------
+//
+class PassiveItem : public NCursesMenuItem
+{
+public:
+ PassiveItem(const char* text) : NCursesMenuItem(text) {
+ options_off(O_SELECTABLE);
+ }
+};
+
+//
+// -------------------------------------------------------------------------
+//
+class ScanAction : public NCursesMenuItem
+{
+public:
+ ScanAction(const char* s) : NCursesMenuItem(s) {
+ }
+
+ bool action() {
+ NCursesPanel *mystd = new NCursesPanel();
+
+ NCursesPanel *w = new NCursesPanel(mystd->lines() - 2, mystd->cols() - 2, 1, 1);
+ w->box();
+ w->refresh();
+
+ NCursesPanel *s = new NCursesPanel(w->lines() - 6, w->cols() - 6, 3, 3);
+ s->scrollok(TRUE);
+ ::echo();
+
+ s->printw("Enter decimal integers. The running total will be shown\n");
+ int nvalue = -1;
+ int result = 0;
+ while (nvalue != 0) {
+ nvalue = 0;
+ s->scanw("%d", &nvalue);
+ if (nvalue != 0) {
+ s->printw("%d: ", result += nvalue);
+ }
+ s->refresh();
+ }
+ s->printw("\nPress any key to continue...");
+ s->getch();
+
+ delete s;
+ delete w;
+ delete mystd;
+ ::noecho();
+ return FALSE;
+ }
+};
+
+//
+// -------------------------------------------------------------------------
+//
class MyMenu : public NCursesMenu
{
private:
NCursesPanel* P;
+ NCursesMenuItem** I;
+ UserData *u;
+ #define n_items 7
public:
- MyMenu (NCursesMenuItem* menu[])
- : NCursesMenu (menu, 7, 8, 2, 2, TRUE)
+ MyMenu ()
+ : NCursesMenu (n_items+2, 8, (lines()-10)/2, (cols()-10)/2),
+ P(0), I(0), u(0)
{
- if (NCursesWindow::NumberOfColors() > 2) {
- setcolor(1);
- setpalette(COLOR_YELLOW, COLOR_BLUE);
+ u = new UserData(1);
+ I = new NCursesMenuItem*[1+n_items];
+ I[0] = new PassiveItem("One");
+ I[1] = new PassiveItem("Two");
+ I[2] = new MyAction<UserData> ("Silly", u);
+ I[3] = new FormAction("Form");
+ I[4] = new PadAction("Pad");
+ I[5] = new ScanAction("Scan");
+ I[6] = new QuitItem();
+ I[7] = new NCursesMenuItem(); // Terminating empty item
+
+ InitMenu(I, TRUE, TRUE);
+
+ P = new NCursesPanel(1, n_items, LINES-1, 1);
+ boldframe("Demo", "Silly");
+ P->show();
+ }
+
+ MyMenu& operator=(const MyMenu& rhs)
+ {
+ if (this != &rhs) {
+ *this = rhs;
}
+ return *this;
+ }
- P = new NCursesPanel(1,COLS,LINES-1,0);
- boldframe("Demo","Silly");
- P->show();
+ MyMenu(const MyMenu& rhs)
+ : NCursesMenu(rhs), P(0), I(0), u(0)
+ {
}
- ~MyMenu()
+ ~MyMenu() THROWS(NCursesException)
{
P->hide();
delete P;
+ delete u;
}
virtual void On_Menu_Init()
{
- P->move(0,0);
+ NCursesWindow W(::stdscr);
+ P->move(0, 0);
P->clrtoeol();
- P->addstr("12345");
- NCursesPanel::refresh();
+ for(int i=1; i<=count(); i++)
+ P->addch('0' + i);
+ P->bkgd(W.getbkgd());
+ refresh();
}
virtual void On_Menu_Termination()
{
- P->move(0,0);
+ P->move(0, 0);
P->clrtoeol();
- P->addstr("Menu Exit");
- NCursesPanel::refresh();
+ refresh();
}
virtual void On_Item_Init(NCursesMenuItem& item)
{
- P->move(0,item.index());
+ P->move(0, item.index());
P->attron(A_REVERSE);
- P->printw("%1d",1+item.index());
+ P->printw("%1d", 1+item.index());
P->attroff(A_REVERSE);
- NCursesPanel::refresh();
+ refresh();
}
virtual void On_Item_Termination(NCursesMenuItem& item)
{
- P->move(0,item.index());
+ P->move(0, item.index());
P->attroff(A_REVERSE);
- P->printw("%1d",1+item.index());
- NCursesPanel::refresh();
+ P->printw("%1d", 1+item.index());
+ refresh();
}
};
-
-main()
+//
+// -------------------------------------------------------------------------
+//
+class TestApplication : public NCursesApplication
{
- UserData* u = new UserData(1);
-
- NCursesWindow::useColors();
+protected:
+ int titlesize() const { return 1; }
+ void title();
+ Soft_Label_Key_Set::Label_Layout useSLKs() const {
+ return Soft_Label_Key_Set::PC_Style_With_Index;
+ }
+ void init_labels(Soft_Label_Key_Set& S) const;
- NCursesMenuItem** I = new NCursesMenuItem*[6];
- I[0] = new NCursesMenuItem("One");
- I[1] = new NCursesMenuItem("Two");
- I[2] = new MyAction<UserData> (u, "Silly");
- I[3] = new NCursesMenuItem("Four");
- I[4] = new QuitItem();
- I[5] = new NCursesMenuItem();
-
- MyMenu m(I);
+public:
+ TestApplication() : NCursesApplication(TRUE) {
+ }
- m();
+ int run();
+};
- for(int i=0; i < 6; i++) {
- delete I[i];
+void TestApplication::init_labels(Soft_Label_Key_Set& S) const
+{
+ for(int i=1; i <= S.labels(); i++) {
+ char buf[8];
+ assert(i < 100);
+ ::_nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) "Key%02d", i % 100);
+ S[i] = buf; // Text
+ S[i] = Soft_Label_Key_Set::Soft_Label_Key::Left; // Justification
}
- delete I;
- delete u;
+}
- exit(0);
+void TestApplication::title()
+{
+ const char * const titleText = "Simple C++ Binding Demo";
+ const int len = ::strlen(titleText);
+
+ getTitleWindow()->bkgd(screen_titles());
+ getTitleWindow()->addstr(0, (getTitleWindow()->cols() - len)/2, titleText);
+ getTitleWindow()->noutrefresh();
}
+
+
+int TestApplication::run()
+{
+ MyMenu M;
+ M();
+ return 0;
+}
+
+//
+// -------------------------------------------------------------------------
+//
+static TestApplication *Demo = new TestApplication();
+
+#ifdef _WIN32
+// This is actually only needed when ncurses is a dll
+NCURSES_CXX_MAIN
+#endif