Difference between revisions of "Console UI Core Classes - OOP344 20113"

From CDOT Wiki
Jump to: navigation, search
(R0.2)
(Undo revision 81497 by Fardad (Talk))
Line 59: Line 59:
  
 
===Due Date===
 
===Due Date===
Friday Feb 24th. 23:59
+
Tuesday Oct <del>26</del> 30th. 23:59
 
===Tester===
 
===Tester===
 
*[svn://zenit.senecac.on.ca/oop344/trunk/cioTesters/Test2DialogAndLabel.cpp Test2DialogAndLabel.cpp ]
 
*[svn://zenit.senecac.on.ca/oop344/trunk/cioTesters/Test2DialogAndLabel.cpp Test2DialogAndLabel.cpp ]
 
+
*on matrix, with putty (Terminal/keyboard: Xterm R6)
 
*: on OSX, you can emulate XTerm keyboard settings using [http://iterm.sourceforge.net/ iTerm]/[http://www.iterm2.com/#/section/home ITerm 2]
 
*: on OSX, you can emulate XTerm keyboard settings using [http://iterm.sourceforge.net/ iTerm]/[http://www.iterm2.com/#/section/home ITerm 2]
*: On Matrix: ~fardad.soleimanloo/t2 runs the demo for the test
+
*: ~fardad.soleimanloo/t2 runs the demo for the test
 
====Makefile for test 2 on matrix====
 
====Makefile for test 2 on matrix====
 
*create a file in the root of cio call it '''"makefile"''' and copy the content below:
 
*create a file in the root of cio call it '''"makefile"''' and copy the content below:

Revision as of 14:57, 15 February 2012


OOP344 | Weekly Schedule | Student List | Teams | Project | Student Resources


Contents

Objective

Your objective at this stage is to create series of core classes designed to interact with the user. These Core Classes then can be used in development of any interactive application.

Please note that the class definitions here are minimum requirement for the Core Classes and you are free to add any enhancements or features you find useful. However make sure that you discuss these enhancements with your professor to make sure they are feasible before implementation.

It is highly recommended to develop the classes in the order they are stated here. You must create your own tester programs for each class (if possible); However, close to due date of each release, a tester program may be provided to help you verify the functionality of your classes. If tester programs are provided, then executables of the test programs will be available on matrix to show you how it is supposed to run.

Start by creating mock-up classes (class declaration and definition with empty methods that only compiles and don't do anything). Each class MUST have its own header file to hold its declaration and "cpp" file to hold its implementation. To make sure you do not do circular includes follow these simple guidelines:

  • Add recompilation safeguards to all your header files.
  • Always use forward declaration if possible instead of including a class header-file.
  • Use includes only in files in which the actual header file code is used.
  • Avoid "just in case" includes.

Student Resources

Releases and Due Dates

R0.1

To Do

  1. checkout your repository using userids and passwords received through your learn.senecac.on.ca email
  2. Create a direcotry in branches under your seneca email id (NOT YOUR WHOLE EMAIL ADDRESS, ONLY THE ID)
    From now on, this directory will be called Your Workspace
  3. In your workspace create a direcotry called console2.0 and add the files you submitted for your console2.0 assignment to it.
  4. add all the newly created directories and their files to svn
  5. commit the repository with the message (comment) "Initial branch creation"
  6. Browse your Console2.0 codes as a group and add choose the best edit() and display() from it and add it to console.cpp in trunk
    • Any of the group members can do this, but it would be nice if you do this when everyone is present
    • If further changes to console.cpp or console.h are needed, you can apply them too
    • Compile and make sure Test1Frame.cpp works properly
    • After fixing possible bugs recompile and make sure everything is ok and runs properly
  7. tag the trunk under R0.1 in tags directory

Due Date

Wednesday Oct 12th, 23:59

Exercise

To prepare and learn how to contribute and also gain mark for your next release do the following exercise.

Tester

Test1Frame.cpp

R0.2

Dialog and Labels

To Do

Complete the coding of CField, CLabel and CDialog and then test the project using Test2DialogAndLabel.cpp.
Workload estimate out of 100:

  • CField 10%
  • CLabel 25%
  • CDialog 65%
  1. First start with creating mockup classes (create the classes with empty methods that do nothing but compiles), you should have 6 files for headers and cpp code, and add them to trunk.
  2. considering the percentage of the workload, assign tasks to each team member.
  3. Each team member branch the trunk to start their work.
  4. communicate with your team members and keep updating your code with their additions, (remember that you have access to their branches)
  5. keep regular IRC meetings ( you can invite me to your meetings too for advice and help)
  6. When all done, merge back the additions to trunk.
  7. Do final test and tag it to R0.2

Due Date

Tuesday Oct 26 30th. 23:59

Tester

  • Test2DialogAndLabel.cpp
  • on matrix, with putty (Terminal/keyboard: Xterm R6)
    on OSX, you can emulate XTerm keyboard settings using iTerm/ITerm 2
    ~fardad.soleimanloo/t2 runs the demo for the test

Makefile for test 2 on matrix

  • create a file in the root of cio call it "makefile" and copy the content below:
    make sure the lines starting with c++ are tabbed once.
    then at command line issue the command "make" to complie; the name of the executable will be prjexe
t2: console.o cframe.o cfield.o cdialog.o clabel.o Test2DialogAndLabel.o
	c++  console.o cframe.o cfield.o cdialog.o clabel.o \
Test2DialogAndLabel.o -lncurses -oprjexe

console.o: console.cpp console.h keys.h
	c++ -c console.cpp

cframe.o: cframe.cpp cframe.h cuigh.h console.h keys.h
	c++ -c cframe.cpp

cfield.o: cfield.cpp cfield.h cuigh.h cframe.h console.h keys.h
	c++ -c cfield.cpp

cdialog.o: cdialog.cpp cdialog.h cfield.h cuigh.h cframe.h console.h keys.h
	c++ -c cdialog.cpp

clabel.o: clabel.cpp clabel.h cfield.h cframe.h cuigh.h console.h keys.h
	c++ -c clabel.cpp

Test2DialogAndLabel.o: Test2DialogAndLabel.cpp clabel.h cdialog.h cframe.h cuigh.h cfield.h console.h keys.h
	c++ -c Test2DialogAndLabel.cpp

R0.3

  1. CLineEdit
  2. CButton
  3. CValEdit
  4. CCheckMark
  5. CMenuItem


To Do

  • Apply the new changes to cuigh.h
  • Modify CLabel:
    1. remove _length attribute and use _width of CFrame instead (use void width(int) and int width() to set and get length
    2. Modify CLabel Copy Constructor to the new definition.
    3. Modify void CLabel::set(const void* str) and remove the condition for memory reallocation.
  • Complete the classes stated above and test them with the corresponding tested values
it is strongly recommended to have separate tags for ClineEdit, CButton, CValEdit, CCheckMark and CMenuItem

Due Date

  • Friday Nov 18th 23:59Sunday Nov 20th 15:00

Testers

  1. Test3DialogAndLineEdit.cpp
  2. Test4Button.cpp
  3. Test5ValEdit.cpp
  4. Test6Check.cpp
  5. Test7MenuItem.cpp
  • to run the demos on matrix, with putty (Terminal/keyboard: Xterm R6)
    On Terminal Window type:
    $ ~fardad.soleimanloo/tX <ENTER> where X is the number of the test

R0.6

  • CText
  • CCheckList
  • CMenu

To Do

  1. Before starting CText:
    Modify Console::edit(char *str....) and add two argument to the argument list; IsTextEditor, ReadOnly:
    int Console::edit(char *str, int row, int col, int fieldLength, int maxStrLength, bool* insertMode, int* strOffset, int* curPosition, bool IsTextEditor = false, bool ReadOnly = false)
    • IsTextEditor: If IsTextEditor is true, then if offset is modified, stop editing and terminate the function returning the last key entered by the user. The easiest way to accomplish this, is as follows:
      1. Save the value of the offset in a local variable at the very beginning of the main processing loop in the edit() function.
      2. At the very end of the processing loop, If IsTextEditor is true, then compare the saved value with the value of offset. If the values are different, then set the termination flag (done) to true.
    • Also if IsTextEditor is true, ESCAPE should no longer undo the changes in the line. (since in this case, it is responsibility of the Text editor (CText) to undo the changes.
  2. Before starting CCheckList:
    Add the following methods to the CCheckMark class
    • bool radio();
    • void radio(bool isRadio);
    • operator bool();
    • operator char*();
    • bool operator=(bool flag);
    (see CCheckMark description)
  3. Divide and assign tasks.
  4. Branch and Create Mock-ups for the classes
  5. Start coding.

Due Dates

  • Tuesday Dec, 6, 2011

Testers

Project makefiles

  • create a file in the root of cio call it "makefile" and copy the makefile of your test from "cio makefiles" into it.
    make sure the lines starting with c++ are tabbed once.
    then at command line issue the command "make" to complie;
    the name of the executable will bt tX, where X is the number of the test.
  • Again: here are the project makefiles for Linux

POST YOUR PROBLEM HERE

  1. Problem with tester: http://ryandang-cpa.blogspot.com/2011/10/problem-with-tester.html (resolved)
  2. Problem with CCheckMark tester: http://hak9.com/2011/11/problem-with-ccheckmark-tester-file-c-oop344-project/ (resolved)

CUI General Header file (cuigh.h)

The general header file holds the common setting and definition between all the Core Classes.

#ifndef ___CUIGH_H__
#define ___CUIGH_H__
namespace cio{ 
  #ifndef _CRT_SECURE_NO_DEPRECATE
  #define _CRT_SECURE_NO_DEPRECATE
  #endif
  #ifndef _CRT_SECURE_NO_WARNINGS
  #define _CRT_SECURE_NO_WARNINGS
  #endif
 
  #define C_MAX_NO_FIELDS 100
  #define C_BUTTON_HIT 1
  #define C_MAX_LINE_CHARS  (1024u)

  #define C_REFRESH -2
  #define C_FULL_FRAME -1
  #define C_NO_FRAME 0

  #define C_BORDER_CHARS  "/-\\|/-\\|"
  enum CDirection {centre, left, right, up, down};


  enum MessageStatus{ClearMessage,SetMessage};


  #ifdef NO_HELPFUNC
  # undef NO_HELPFUNC
  #endif
  #define NO_HELPFUNC ((void(*)(MessageStatus, CDialog&))(0))
  #ifdef NO_VALDFUNC
  # undef NO_VALDFUNC
  #endif
  #define NO_VALDFUNC ((bool(*)(const char*, CDialog&))(0))


  #define C_MAX_LINE_CHARS  (1024u)
  #define C_INITIAL_NUM_OF_LINES (100u)
}
#endif

File Names

Use the following rules to create filenames for your class.

  • Each class MUST have its own header file and cpp file for implementation
  • Use the class name for the name of the file but make sure it is all lowercase.
    For example CFrame class should have cframe.h and cframe.cpp files for its implementation.

Hierarchy

CFrame
 |
 |---CDialog
 |
 |
 |---CField
       |
       |-------- CLabel
       |
       |
       |-------- CButton
       |
       |
       |-------- CLineEdit
       |         |
       |         |-------CValEdit
       |
       |-------- CText
       |
       |
       |-------- CCheckMark
       |
       |
       |-------- CCheckList 
       |
       |
       |-------- CMenuItem  
       |
       |
       |-------- CMenu 

CUI Basic Classes

CFrame

The code for this class is provided. You must understand and use it to develop your core classes.

CFrame class is responsible to create a frame or structure in which all user interface classes contain themselves in. It can draw a border around it self or be border-less. CFrame also, before displaying itself on the screen, will save the area it is about to cover, so it can redisplay them to hide itself.

CFrame is base of all objects in our user interface system.

#pragma once
#include "cuigh.h"

class CFrame{
  int _row;      // relative row of left top corner to the container frame or the screen if _frame is null
  int _col;      // relative col of left top corner to the container frame or the screen if _frame is null
  int _height;   
  int _width;
  char _border[9];  // border characters
  bool _visible;    // is bordered or not
  CFrame* _frame;   // pointer to the container of the frame (the frame, surrounding this frame)
  char* _covered;   // pointer to the characters of the screen which are covered by this frame, when displayed
  void capture();   // captures and saves the characters in the area covered by this frame when displayed and sets 
                    // _covered to point to it
protected:
  int absRow()const;    
  int absCol()const;    
public:
  CFrame(int Row=-1, int Col=-1, int Width=-1,int Height=-1,
    bool Visible = false,
    const char* Border=C_BORDER_CHARS,
    CFrame* Frame = (CFrame*)0);
  
  virtual void draw(int fn=C_FULL_FRAME);
  virtual void move(CDirection dir);
  virtual void move();
  virtual void hide();

  virtual ~CFrame();
  
  /* setters and getters: */

  bool fullscreen()const;

  void visible(bool val);
  bool visible()const;

  void frame(CFrame* theContainer);
  CFrame* frame();
  
  void row(int val);
  int row()const;

  void col(int val);
  int col()const;

  void height(int val);
  int height()const;

  void width(int val);
  int width()const;

  void refresh();
};

Properties

int _row, holds the relative coordinate of top row of this border with respect to its container.
int _col, same as _row, but for _col.
int _height, height of the entity.
int _width, width of the entity.
char _border[9], characters used to draw the border:

_border[0], left top
_border[1], top side
_border[2], right top
_border[3], right side
_border[4], right bottom
_border[5], bottom side
_border[6], bottom left
_border[7], left side

bool _visible; Indicates if the border surrounding the entity is to be drawn or not.
CFrame* _frame; holds the container (another CFrame) which has opened this one (owner or container of the current CFrame). _frame will be NULL if this CFrame does not have a container, in which case, it will be full screen and no matter what the values of row, col, width and height are, CFrame will be Full Screen (no border will be drawn)
char* _covered; is a pointer to a character array that hold what was under this frame before being drawn. When the CFrame wants to hide itself, it simple copies the content of this array back on the screen on its own coordinates.

Methods and Constructors

Private Methods

void capture();
if _covered pointer is not pointing to any allocated memory, it will call the iol_capture function to capture the area that is going to be covered by this frame and keeps its address in _covered.

Protected Methods

  • int absRow()const; calculates the absolute row (relative to the left top corner of the screen) and returns it.
    it returns the sum of row() of this border plus all the row()s of the _frames
  • int absCol()const; calculates the absolute column(relative to the left top corner of the screen) and returns it.
    it returns the sum of col() of this border plus all the col()s of the _frames

Public Methods

  CFrame(int Row=-1, int Col=-1, int Width=-1,int Height=-1,
    bool Visible = false,
    const char* Border=C_BORDER_CHARS,
    CFrame* Frame = (CFrame*)0);
Sets the corresponding attributes to the incoming values in the argument list and set _covered to null
  virtual void draw(int fn=C_FULL_FRAME);
  • First it will capture() the coordinates it is supposed to cover
  • If frame is fullscreen() then it just clears the screen and exits.

Otherwise:

  • If the _visible flag is true, it will draw a box at _row and _col, with size of _width and _height using the _border characters and fills it with spaces. Otherwise it will just draw a box using spaces at the same location and same size.


  virtual void move(CDirection dir);

First it will hide the Frame, then adjust the row and col to more to the "dir" direction and then draws the Frame back on screen.

  virtual void hide();

using iol_restore()it restores the characters behind the Frame back on screen. It will also free the memory pointed by _covered;

  virtual ~CFrame();

It will make sure allocated memories are freed.

  bool fullscreen()const;
  void visible(bool val);
  bool visible()const;
  void frame(CFrame* theContainer);
  CFrame* frame();
  void row(int val);
  int row()const;
  void col(int val);
  int col()const;
  void height(int val);
  int height()const;
  void width(int val);
  int width()const;

These functions set and get the attributes of the CFrame.

CField

CField is an abstract base class that encapsulates the commonalities of all Input Outputs Console Fields which are placeable on a CDialog. All Fields could be Framed, therefore a CField is inherited from CFrame.

#include "cframe.h"
class CDialog;
class CField : public CFrame{
protected:
  void* _data;
public:
  CField(int Row = 0, int Col = 0,
         int Width = 0, int Height =0,
         void* Data = (void*) 0,
         bool Bordered = false,
         const char* Border=C_BORDER_CHARS);
  ~CField();
  virtual int edit() = 0;
  virtual bool editable() const = 0;
 
 
  virtual void set(const void* data) = 0;
  virtual void* data();
 
  void container(CDialog* theContainer);
  CDialog* container();
};

Attributes

  void* _data;

Will hold the address of any type of data a CField can hold.

Constructors and Methods

  CField(int Row = 0, int Col = 0,
         int Width = 0, int Height =0,
         void* Data = (void*) 0,
         bool Bordered = false,
         const char* Border=C_BORDER_CHARS);

Passes the corresponding attributes to it's parents constructor and then sets the _data attribute to the incoming Data argument.

  ~CField();

Empty Destructor

  virtual int edit() = 0;
  virtual bool editable() const = 0;
  virtual void set(const void* data) = 0;

Enforce the children to implement;

  • an edit() method
  • an editable() method that returns true if the class is to edit data and false if the class is to only display data.
  • a set() method to set the _data attribute to the data the class is to work with.
  virtual void* data();

Returns _data.

  void container(CDialog* theContainer);
  CDialog* container();

Sets and Gets the _frame attribute of CFrame by calling CFrame::frame() method. Make sure to cast The CDialog to CFrame when setting and cast CFrame to CDialog when getting!

CLabel

A readonly Field that encapsulates console.display() function. (i.e it is responsible to display a short character string on the display) CLable although, by inheritance is Frame, but it is never bordered.

#include "cfield.h"
class CLabel :  public CField{
   // int _length;     Use void CFrame::width(int) to store length, and int CFrame::width() to retrieve the length

 public:
   CLabel(const CLabel& L);
   CLabel(const char *Str, int Row, int Col,
     int Len = 0);
   CLabel(int Row, int Col, int Len);
   ~CLabel();
   void draw(int fn=C_NO_FRAME) ;
   int edit();
   bool editable()const;
   void set(const void* str);
};

Attributes

No attributes, (use Cframe attributes)

  //  int _length;  removed! use void CFrame::width(int) to store and int CFrame::width() to retrieve length

Holds the Length of the label, this will be stored to be passed to console.display function.

Constructors / Destructor

   CLabel(const char *Str, int Row, int Col,
     int Len = 0);

passes the Row and Col to the CField constructor and then; if len is zero, it will allocate enough memory to store the string pointed by Str and then copies the Str into it. if len > 0, then it will allocate enough memory to store len chars in a string. In any way, the allocated memory is pointed by _data

   CLabel(int Row, int Col, int Len);

Works exactly like the previous constructor, but len in this case can not be zero. (no validation required) and the string pointed by _data will be set to an empty string.

   CLabel(const CLabel& L);

A private and empty copy Constructor. This prevents copying CLabel.
Copies a CLabel safely to guaranty there is no memory leak.

   ~CLabel();

makes sure that memory pointed by _data is deallocated before the object is destroyed.

Methods

   void draw(int fn=C_NO_FRAME) ;

makes a direct call to console.display(), passing _data for the string to be printed and absRow() and absCol() for row and col and _length for len. this function ignores the argument fn.

   int edit();

calls draw, returning 0.

   bool editable()const;

always return false.

   void set(const void* str);

if _length is greater than zero, it will copy the string pointed by str into the string pointed by _data upto _length characters. if _length is zero,
It will delete the memory pointed by _data and reallocates enough memory for str and copies the string pointed by str into the newly allocated memory pointed by _data.

CDialog

Organizes CField objects on the screen, displays them and then lets the user edit them one by one.

#include "cuigh.h"
#include "cframe.h"
namespace cio{
  class CField;
  class CDialog: public CFrame{
    private:
    int _fnum;
    int _curidx;
    CField* _fld[C_MAX_NO_FIELDS];
    bool _dyn[C_MAX_NO_FIELDS];
    bool _editable;
    public:
    CDialog(CFrame *Container = (CFrame*)0,
             int Row = -1, int Col = -1, 
             int Width = -1, int Height = -1, 
             bool Borderd = false,
             const char* Border=C_BORDER_CHARS);
    virtual ~CDialog();
    void draw(int fn = C_FULL_FRAME);
    int edit(int fn = C_FULL_FRAME);

    int add(CField* field, bool dynamic = true);
    int add(CField& field, bool dynamic = false);
    CDialog& operator<<(CField* field);
    CDialog& operator<<(CField& field);

    bool editable();
    int fieldNum()const;
    int curIndex()const;

    CField& operator[](unsigned int index);
    CField& curField();
  };
}

Attributes

  int _fnum;

Holds the number of Fields added to the Dialog

  bool _editable;

will be set to true if any of the Fields added are editable. This is optional because it depends on how you are going to implement the collection of CFields:

  int _curidx;

Holds the index of the Field that is currently being edited.

  CField* _fld[C_MAX_NO_FIELDS];

Array of CField pointers to hold the address of the CField objects added to the screen. The maximum number of CFields that can be added to this CDialog is C_MAX_NO_FIELDS. Remove this restriction for additional mark.

  bool _dyn[C_MAX_NO_FIELDS];

Holds series of boolean to the exact number of fields, and each boolean here will hold false if the corresponding field pointed by _fld is allocated dynamically or not. This array will later on be used by destructor to decide which object is dynamic and to be deleted.

Constructors/Destructors

  CDialog(CFrame *Container = (CFrame*)0,
           int Row = -1, int Col = -1, 
           int Width = -1, int Height = -1, 
           bool Borderd = false,
           const char* Border=C_BORDER_CHARS);

The constructor, passes all the incoming arguments to the corresponding arguments of the apparent constructor CFrame.
Then it will set called a attributes to their default values and then sets all the field pointers (_fld) to NULL. It also sets all the dynamic (_dyn) flags to false.

  virtual ~CDialog();

The destructor, will loop through all the field pointers and if the corresponding dynamic flag is true then it will delete the field pointed to by the field pointer.

Methods

  void draw(int fn = C_FULL_FRAME);

If fn is C_FULL_FRAME, it will call its parent draw. Then It will draw all the Fields in the Dialog.
If fn is not C_FULL_FRAME, then it will just draw all the Fields in the Dialog.
If fn is a non-zero positive value, then it will only draw Field number fn in the dialog. (First added Field is field number one.)

  int edit(int fn = C_FULL_FRAME);

If CDialog is not editable (all fields are non-editable), it will just display the Dialog and then waits for the user to enter a key and then terminates the function returning the key.
If fn is 0 or less, then before editing, the draw method is called with fn as its argument and then editing begins from the first editable Field.

If fn is greater than 0 then editing begins from the first editable key on or after Field number fn.

Note that fn is the sequence number of field and not the index. (First field number is one)

Start editing from field number fn;

Call the edit of each field and depending on the value returned, do the following:

  1. For ENTER_KEY, TAB_KEY and DOWN_KEY, go to next editable Field , if this is the last editable Field then restart from Field number one.
  2. For UP_KEY go to the previous editable Field, if there is no previous editable Field, go to the last editable Field in the Dialog.
  3. For any other key, terminate the edit function returning the character which caused the termination.
  int add(CField* field, bool dynamic = true);

Adds the CField' pointed by field to the Fields of the Dialog; by appending the value of the field pointer after the last added field in the _fld array , setting the corresponding _dyn element to the value of dynamic argument and then increasing _fnum by one and returning it the index of added Field in the CDialog object.
important note:
Make sure that add() sets the container of the added CField to this CDialog object, using the container() method of CField

  int add(CField& field, bool dynamic = false);

Makes a direct call to the first add method.

  CDialog& operator<<(CField* field);

Makes a direct call to the first add method, ignoring the second argument and then returns the owner (current CDialog).

  CDialog& operator<<(CField& field);

Makes a direct call to the second add method, ignoring the second argument and then returns the owner (current CDialog).

  bool editable();

Returns _editable;

  int fieldNum()const;

returns _fnum.

  int curIndex()const;

returns _curidx;

  CField& operator[](unsigned int index);

Returns the reference of the Field with incoming index. (Note that here, the first field index is 0)

  CField& curField();

Returns the reference of the Field that was just being edited.

CLineEdit

ClineEdit encapsulates the console.edit() function of Console class.

#include "cfield.h"
namespace cio{
  class CLineEdit: public CField{
    bool _dyn;
    int _maxdatalen;
    bool* _insertmode;
    int _curpos;
    int _offset;
  public:
    CLineEdit(char* Str, int Row, int Col, int Width,
      int Maxdatalen, bool* Insertmode, 
      bool Bordered = false,
            const char* Border=C_BORDER_CHARS);
    CLineEdit(int Row, int Col, int Width,
      int Maxdatalen, bool* Insertmode, 
      bool Bordered = false,
            const char* Border=C_BORDER_CHARS);
    ~CLineEdit();
    void draw(int Refresh = C_FULL_FRAME);
 
    int edit();
    bool editable()const;

    void  set(const void* Str);
  };
}

Attributes

  bool _dyn;

_dyn is set to true if the object dynamically allocated memory and is responsible to free it at destruction time.

  int _maxdatalen;

no comment!

  bool* _insertmode;

points to the location of input method (insert or overstrike)

  int _curpos;

current position of cursor

  int _offset;
current offset

Constructors / Destructor

  CLineEdit(char* Str, int Row, int Col, int Width,
    int Maxdatalen, int* Insertmode, 
    bool Bordered = false,
          const char* Border=C_BORDER_CHARS);

LineEdit, sets the Field's _data to the value of str. If LineEdit is instantiated with this constructor then it will edit an external string provided by the caller function of LineEdit. LineEdit in this case is not creating any dynamic memory, therefore _dyn is set to false (therefore the destructor will not attempt to deallocate the memory pointed by _data).
The location (row and col) and Bordered are directly passed to the parent (FWField) and str is passed as data to the parent constructor. Unlike Label, LineEdit could have border or not so depending on this (Bordered being true or false) the Height is set to 3 or 1 respectfully.
(hint: use ? : operator to pass the proper Height value to FWField's constructor)

  CLineEdit(int Row, int Col, int Width,
    int Maxdatalen, int* Insertmode, 
    bool Bordered = false,
          const char* Border=C_BORDER_CHARS);

Works exactly like the previous constructor with one difference; since no external data is passed to be edited here, this constructor must allocate enough dynamic memory to accommodate editing of Maxdatalen characters. Then make it an empty string and set Fields's _data to point to it. Make sure _dyn is set to true in this case, so the destructor knows that it has to deallocate the memory at the end.

  ~CLineEdit();

If _dyn is true, it will deallocate the character array pointed by Fields's _data

Methods

  void draw(int Refresh = C_FULL_FRAME);

It will first call Frame's draw passing Refresh as an argument to it.
Then it will make a direct call to console.display() to show the data kept in Field's _data.
The values used for the arguments of console.display() are:

  • str: address of string pointed by _data + the value of _offset
  • row: absRow() (add one if border is visible)
  • col: absCol() (add one if border is visible)
  • len: width() (reduce by two if border is visible')
  int edit();

Makes a direct call to, and returns console.edit(). For the coordinates and width arguments follow the same rules as the draw function. For the rest of the arguments of console.edit(), use the attributes of CLineEdit.

  bool editable()const;

Always return true;

  void  set(const void* Str);

Copies the characters pointed by Str into the memory pointed by Field's _data up to _maxdatalen characters.

CButton

Button is a child of CField. It displays a small piece of text (usually one word or two) and accepts one key hit entry. When in edit mode, to indicate the editing mode, it will surround the text with squared brackets.

#pragma once
#include "cfield.h"
namespace cio{
   class  CButton: public CField{

   public:
     CButton(const char *Str, int Row, int Col, 
              bool Bordered = true,
              const char* Border=C_BORDER_CHARS);
     virtual ~CButton();
     void draw(int rn=C_FULL_FRAME);
     int edit();
     bool editable()const;
     void set(const void* str);
   };
}

Attributes

This class does not have any attributes of its own!

Constructor / Destructor

   CButton(const char *Str, int Row, int Col, 
            bool Bordered = true,
            const char* Border=C_BORDER_CHARS);

When creating a Button, allocate enough memory to hold the contents of the Str and set Field's _data to point to it. Then copy the content of Str into the newly allocated memory.
Pass all the arguments directly to Field's constructor.
For Field size (width and hight) do the following:
For width: Set width to the length of Str + 2 (adding 2 for surrounding brackets) or if the Button is bordered set width to the length of Str + 4 (adding 2 for surrounding brackets and 2 for the borders). For height: Set the height to 1 or if the Button is bordered, set the height to 3.

   virtual ~CButton();

Deallocates the allocated memory pointed by Field's _data.

Methods

   void draw(int fn=C_FULL_FRAME);

Draws the Button with border around it if it is Bordered. Note that there should be a space before and after of the text that will be used to surround the text with "[" and "]"
hint:

  • First calls Frame's draw(fn) (passing the fn argument to the parents draw)
Use console.display() to display the Button's text (pointed by Field's _data)
  • If not bordered
    display the text at absRow() and absCol()
  • If bordered
    display the text at absRow()+1 and absCol()+2
   int edit();

First draw() the Button, then surround it by squared brackets, place the cursor under the first character of Button's text and wait for user entry.
When user hits a key, if the key is ENTER_KEY or SPACE, return C_BUTTON_HIT (defined in cuigh.h) otherwise return the entered key.

   void set(const void* str);

First deallocated what is pointed by Field's _data. Then allocate new memory to the size of content of str and copy the content into it and make Field's _data point to it.

   bool editable()const;

Always returns true

CValEdit

#include "clineedit.h"

namespace cio{
  class CValEdit: public CLineEdit{
    void (*_help)(MessageStatus, CDialog&);
    bool (*_validate)(const char*, CDialog&);
  public:
    CValEdit(char* Str, int Row, int Col, int Width,
          int Maxdatalen, bool* Insertmode,
          bool (*Validate)(const char* , CDialog&) = NO_VALDFUNC, 
          void (*Help)(MessageStatus, CDialog&) = NO_HELPFUNC,
          bool Bordered = false,
          const char* Border=C_BORDER_CHARS);
    CValEdit(int Row, int Col, int Width,
          int Maxdatalen, bool* Insertmode,
          bool (*Validate)(const char* , CDialog&) = NO_VALDFUNC, 
          void (*Help)(MessageStatus, CDialog&) = NO_HELPFUNC,
          bool Bordered = false,
          const char* Border=C_BORDER_CHARS);
    int edit();
  };
}

Attributes

    void (*_help)(MessageStatus, CDialog&);
    bool (*_validate)(const char*, CDialog&);
  • _help, holds the address of the help logic (function) or NULL if there is no help function is assigned
  • _validate, holds the address of the validation logic (function) or NULL if there is no validation function is assgned

Constructors

    CValEdit(char* Str, int Row, int Col, int Width,
          int Maxdatalen, bool* Insertmode,
          bool (*Validate)(const char* , CDialog&) = NO_VALDFUNC, 
          void (*Help)(MessageStatus, CDialog&) = NO_HELPFUNC,
          bool Bordered = false,
          const char* Border=C_BORDER_CHARS);
    CValEdit(int Row, int Col, int Width,
          int Maxdatalen, bool* Insertmode,
          bool (*Validate)(const char* , CDialog&) = NO_VALDFUNC, 
          void (*Help)(MessageStatus, CDialog&) = NO_HELPFUNC,
          bool Bordered = false,
          const char* Border=C_BORDER_CHARS);

These constructors pass all their arguments to corresponding arguments of CLineEdit constructor and then set _help and _validate attributes to the corresponding incoming arguments

Method

  int edit();

If the container() is NULL then this function works exactly like LineEdit::edit().
If the container() is not NULL:

  1. If _help function exist, it calls the function passing MessageStatus::SetMessage and container()'s reference as arguments.
  2. Calls CLineEdit's edit()
  3. If validation function exists, and the terminating key of CLineEdit's edit() is a navigation key(see below)
    It will call the validation function on the Field's _data, if the data is valid, it goes to next step, otherwise it will repeat calling CLineEdit's edit().
  4. After validation is done, if _help function exists, it will recall the help function using MessageStatus::ClearMessage and contianer()'s reference as arguments.
  5. It will return the terminating key

Navigation keys are Up key, Down key, Tab key or Enter key.
MessageStatus is enumerated in cuigh.h

CCheckMark

#include "cfield.h"
#include "clabel.h"
namespace cio{
  class CCheckMark : public CField{
    bool _flag;
    bool _radio;
    char _format[4];
    CLabel _Label;
  public:
    CCheckMark(bool Checked,const char* Format, const char* Text, int Row, int Col, int Width, bool IsRadio = false);
    CCheckMark(const CCheckMark& C);
    void draw(int fn = C_NO_FRAME) ;
    int edit();
    bool editable()const;
    void set(const void* flag);
    bool checked()const;
    void checked(bool val);
    bool radio(); // addition for R0.6
    void radio(bool isRadio); // addition for R0.6
    operator bool(); // addtion for R0.6
    operator char*(); // addition for R0.6
    bool operator=(bool flag);
  };
}

Attributes

  int _flag;
  bool _radio;
  char _format[4];
  CLabel _Label;
  • _flag holds the status of the Checkbox (0: unchecked or 1: checked ) and is pointed by _data pointer .
  • _radio dictates the behavior of the Checkbox as a radio-button, or a check-mark.
  • _format holds the characters, the Checkbox is drawn with (i.e. "[X]", "(O)", "<*>", etc...).
  • _Label holds the Label attached to the this Checkbox

Constructor / Destructor

  CCheckMark(bool Checked,const char* Format, const char* Text, int Row, int Col, int Width, bool IsRadio = false);
  • Passes the Row, Col, Width and "1" to row, col, width and height arguments of CField and directly initializes _Label with Text, 0, 4, and (Width-4) for Str, Row, Col and Len, arguments of CLabel's Constructor.
  • Sets the frame of _Label to its owner (Checkmark i.e. 'this');
  • Sets _flag to Checked
  • Sets _radio to IsRadio
  • Copies Format to _format
  • Sets _data to the address of _flag
  CCheckMark(const CCheckMark& C);
  • Passes incoming CCheckMark reference ("C") to CField's copy constructor, and directly initializes the _Label with the _Label of C
  • Sets all the attributes of this object to the attributes of incoming CCheckMark reference ("C")
  • Sets _data to the address of _flag

Methods

  void draw(int fn = C_NO_FRAME) ;

Using Console methods:

  1. displays the _format string at absRow() and absCol()
  2. if _flag is false, it will overwrite the second character printed above, with a space (removes the check mark on console)
  3. draw()s the _Label
  4. sets the position of the cursor at the checkmark (second character of printed _format)
  int edit();
  1. draw()s the checkmark
  2. gets a key
    the key must be either SPACE or any non-printable character (all printable character are ignored)
  3. if the entered key is space
    1. if _radio is true, it will set the _flag to true
    2. if _radio is false, it will flip the value of _flag.
    3. draw()s the checkmark again
  bool editable()const;
  • Always return true;
  void set(const void* flag);
  • Casts the incoming flag pointer to an (bool*) and sets the content of _flag to where flag is pointing to.
  bool checked()const;
  void checked(bool val);
  • These methods set and get _flag.
    bool radio(); // addition for R0.6
    void radio(bool isRadio); // addition for R0.6
  • These to methods, get and set the _radio attribute.
    operator bool(); // addtion for R0.6
  • Overload the bool cast to return the value of _flag
     operator char*(); // addtion for R0.6
  • Overload the char* cast to return the value of _Label.data()
     bool operator=(bool flag);; // addtion for R0.6
  • Overload the operator= and set the _flag to flag

CMenuItem

CMenuItem provides a Label that is can be marked as selected by pressing the space bar.

#include "clabel.h"
#include "cfield.h"
namespace cio{
  class CMenuItem:public CField{
    bool  _selected;
    char _format[3];
    CLabel Label;
  public:
    CMenuItem(bool Selected,const char* Format, const char* Text, int Row, int Col, int Width);
    CMenuItem(const CMenuItem &CM);
    void draw(int fn = C_NO_FRAME) ;
    int edit();
    bool editable()const;
    void set(const void* Selected);
    bool selected()const;
    void selected(bool val);
    const char* Text();
  };
}

Attributes

    bool  _selected;

Holds the status of the MenuItem, being selected or not;

    char _format[3];

Holds the surrounding characters with which a selected MenuItem is shown:
If _format holds "[]", then a selected MenuItem will be like [MenuText]

    CLabel Label;

Hold the Text of the MenuItem.

Constructors / Destructor

    CMenuItem(bool Selected,const char* Format, const char* Text, int Row, int Col, int Width);
  1. Initializes the CField with Row, Col, Width and 1 for Height
  2. Initializes the Label with (Text, 0, 1 and Width-2) for (Str, Row, Col, and Len)
  3. Sets the attributes to corresponding arguments
  4. Sets CFeilds::_data to the address of _formated
  5. Sets the Label's frame to this object.
    CMenuItem(const CMenuItem &CM);
  1. Passes CM to CFiled and Initializes the Label with CM
  2. Sets the _selected to _selected of CM
  3. Sets CFeilds::_data to the address of _format
  4. Sets the Label's frame to this object.

Methods

    void draw(int fn = C_NO_FRAME) ;
  1. Draws the Label with fn
  2. If _selected is true, it surrounds the Label Text the _format[0] and _format[1]
  3. If _selected if false, it surrounds the Label with SPACEs (overwrites _format[0] and _format[1])
  4. Positions the cursor at the first character of the Label
    int edit();
  1. draw()s the MenuItem
  2. gets a key
    the key must be either SPACE or any non-printable character (all printable character are ignored)
  3. if the entered key is space
    1. it will set the _selected to true
    2. draw()s the MenuItem again
  4. returns the key
    bool editable()const;

Returns true.

    void set(const void* Selected);

Sets _selected to where Selected is pointing to

    bool selected()const;

Returns Selected

    void selected(bool val);

Sets _selected to val

    const char* Text();

Returns the text of Label

CText

CText is a CField to edit a multiline text.
To do this, it will use the Text class to convert a character string containing a text into a (simulated) two dimensional array.

#pragma once
#include "cfield.h"
#include "text.h"

using namespace cio;


class CText:public CField{
  Text _T;
  bool _displayOnly;
  int _curpos;
  bool* _insertmode;
  int _offset;
  int _lcurpos;
  int _loffset;
public:
  CText(int Row, int Col, int Width, int Height, bool* Insertmode, 
    bool displayOnly = false, const char* Border=C_BORDER_CHARS);
  CText(const char* Str, int Row, int Col, int Width, int Height,
    bool* Insertmode, bool displayOnly = false, 
    const char* Border=C_BORDER_CHARS);
  void draw(int fn = C_FULL_FRAME);

  void set(const void *Str);
  void *data()const;

  int edit();
  bool  editable()const;
  bool displayOnly();
  void displayOnly(bool val);
};

Attributes

  Text _T;

An instance of the Text class

  bool _displayOnly;

If it is set to true, then the Text can only be viewed but not edited; All scrolling, page UP, DOWN, etc... is enabled but any attempt to change the text, is ignored quietly. This attribute is passed to ReadOnly argument of Console::edit(......).

  int _curpos;
  bool* _insertmode;
  int _offset;

Values used by Console::edit(......)

  int _lcurpos;
  int _loffset;

Vertical cursor position in text. Vertical offset of the text relative to the frame of CText. This value indicates, how many line are hidden above the frame when text is scrolled down.

Constructors/Destructor

  CText(int Row, int Col, int Width, int Height, bool* Insertmode, 
    bool displayOnly = false, const char* Border=C_BORDER_CHARS);

Initialized the CField with the corresponding incoming arguments and then sets all the attributes to their corresponding arguments.

  CText(const char* Str, int Row, int Col, int Width, int Height,
    bool* Insertmode, bool displayOnly = false, 
    const char* Border=C_BORDER_CHARS);

Works exactly like the previous constructor but it also set()s the class to Str.

Methods

Under Construction

  void draw(int fn = C_FULL_FRAME);

First it will draw the CField using the fn arguement.
Then it will use console.display to display all the Lines of _T that are positioned inside the frame of the CText. (i.e. from _loffset to _loffset + Height() - 2).
Two Important things to note:

  1. you should note that Lines are console.display()ed from _offset character. (i.e. &_T[theLineNumber][_offset]).
  2. Also you should console.display() the Lines only if the length of the line is more than the _offset(i.e. _T[theLineNumver].strlen() > _offset)
  void set(const void *Str);

Sets the _T attribute to the incoming string.

  void *data()const;

Exports the string out of _T and returns its address after casting it to void*.

  int edit();
  1. Create local variables to hold the following attributes in case ESCAPE is hit to undo:
    1. _T
    2. _curpos
    3. _offset
    4. _lcurpos
    5. _loffset
  2. Create the usual while(!done) structure for interfacing with user
  3. draw() the text
  4. console.edit() the Line at where vertical cursor is after _loffset.
    1. use absRow() and _lcurpos to calculate the row on which the editing should happen
    2. use absCol() to calculate the column on which editing to happen.
    3. use width() to calculate the fieldLen for console.edit()
    4. use the size() of the current Line in _T to determine the maximum data length of the string to console.edit()
    5. the isTextEditor is always true
    6. the ReadOnly depends on the value of _displayOnly
  bool  editable()const;

Always return true;

  bool displayOnly();
  void displayOnly(bool val);

These methods Get and Set the _displayOnly attribute.

The Text Helper Class

Text class

CText Tester Crash

char* data = (char*)TD[0].data();
delete [] data;

This fails because TD[0].data() refers to CField::data() and NOT CText::data() like it should. Here are some possible fixes that I think Fardad meant to use:

char* data = (char*)((CText&)(TD[0])).data();
OR
char* data = (char*)txt.data();

Note, this does NOT crash on Matrix, only Windows and Visual Studio.

CCheckList

#pragma once
#include "cfield.h"
#include "ccheckmark.h"
namespace cio{

  class CCheckList : public CField{
    CCheckMark* _checkmarks[32];
    bool _radio;
    char _format[4];
    unsigned int _cnt;
    unsigned int _flags;
    unsigned int _cur;
  public:
    CCheckList(const char* Format, int Row, int Col, int Width,bool radio, bool Bordered = true,const char* Border=C_BORDER_CHARS);
    ~CCheckList(void);
    CCheckList& add(const char* Text, bool selected = false);
    CCheckList& operator<<(const char* Text);
    void draw(int fn = C_FULL_FRAME);
    int edit();
    void* data();
    void set(const void* data);
    CCheckMark& operator[](unsigned int index);
    bool editable()const;
    bool radio()const;
    void radio(bool val);
    unsigned int flags()const;
    void flags(unsigned int theFlags);
    int selectedIndex()const;
    void selectedIndex(int index);
    unsigned int length();
  };
}

Attributes

    CCheckMark* _checkmarks[32];

An array of 32 CCheckmark pointers that will piont to _cnt dynamically allocated CCheckMarks.

    bool _radio;

Holds the behaviour of the CCheckList to be like a Radio Button List or Check Mark List

    char _format[4];

Holds the format with which a check mark is displayed (i.e. "[X]" or "(o)" etc...)

    unsigned int _cnt;

Holds the number of CCheckMarks currently in CCheckList

    unsigned int _flags;

Always holds the bit pattern corresponding to the status of the CCheckMarks in the List. Note that bit 0 (right most) will correspond to the first CCheckMark.

    unsigned int _cur;

Holds the index of the CCheckMark in the "_checkmarks" array which is currently being edited. (focused)

Constructors/Destructor

    CCheckList(const char* Format, int Row, int Col, int Width,bool radio, bool Bordered = true,const char* Border=C_BORDER_CHARS);

Passes corresponding values to the Base class (CField) then

  1. sets the _data attribute to the address of _flags
  2. copies Format and radio into _format and _radio respectively
  3. sets _cnt, _cur and _flags to zero
    ~CCheckList(void);

Goes through _checkmarks up to _cnt and if deletes them one by one.

Methods

    CCheckList& add(const char* Text, bool selected = false);
  • Only adds a new CCheckMark if _cnt does not exceed the maximum amount of _checkmarks (32)
  • Creates a new CCheckMark with the row being _cnt+1, the height being 1 and the length being the length of Text+4
  • Sets the newly created CCheckMarks' frame to this
  • Automatically expands the width of the CCheckList if the width of the newly created CCheckMark is bigger than the current width of the CCheckList
  • Sets the height of the CCheckList to _cnt+3
  • Updates the bit pattern of _flags
  • Increments _cnt
    CCheckList& operator<<(const char* Text);

returns add(Text).

    void draw(int fn = C_FULL_FRAME);

Draws the frame and then draws all the _checkmarks, making sure the cursor is standing under the first checked checkmark.

    int edit();
  • Draws the CCheckList then starts the editing the _checkmarks form _cur and according to the return key of CCheckMark::edit():
    • If Down or Right key is hit it goes to the next _checkmark, if _cur is the last one, then it exits the edit, returning the last key entered.
    • UP and Left key works in opposite direction of Down and Right, if _cur is already zero, then it exits the edit, returning the last key entered.
    • If Space is hit, then if _radio is true, it will uncheck all the _checkmarks other than the _current one.
    void* data();

returns the bit pattern held in _flags.
make sure _flags are updated to the status of the _checkmarks

    void set(const void* data);

sets the _flags and updates the _checkmarks to the bitpattern of _flags

    CCheckMark& operator[](unsigned int index);

returns the CCheckMark corresponding the index value.

    bool editable()const;

always returns true;

    bool radio()const;

returns _radio

    void radio(bool val);

sets the _radio and updates all _checkMarks radio value.

    unsigned int flags()const;

returns the _flags attribute

    void flags(unsigned int theFlags);

sets the _flags attribute

    int selectedIndex()const;

returns the index of the first CCheckMark that is selected, and -1 if nothing is selected.

    void selectedIndex(int index);

sets the selectedindex. (only un-selects the rest if object is in radio mode)
if index is less than zero, then it will un-selects all

    unsigned int length();

returns _cnt

CMenu and MNode

CMenu is a linked list of MNodes. Providing menu selection for the user in two formats; Drop Down List, or a simple menu.

#ifndef __CIO__CMENU_H__
#define __CIO__CMENU_H__
#include "cuigh.h"
#include "cfield.h"
#include "cmenuitem.h"
#include "cbutton.h"
namespace cio{
  class Cmenu;

  class MNode{
    CMenuItem* _item;
    MNode* _next;
    MNode* _prev;
    unsigned int _index;
    MNode(CMenuItem* item,unsigned int index, MNode* prev, MNode* next = ((MNode*)0));
    ~MNode(void);
    friend class CMenu;
  };

  class CMenu : public CField{
    MNode* _first;
    MNode* _head;
    MNode* _tail;
    MNode* _cur;
    char _format[3];
    unsigned int _cnt;
    int _selectedIndex;
    bool _dropdown;
    bool _dropped;
    bool goNext();
    bool goPrev();
    CButton _Title;
  public:
    static const bool Select;
    CMenu(const char* Title, const char* Format, int Row, int Col, 
              int Width, int Height,bool dropdown,  
              const char* Border=C_BORDER_CHARS);
    CMenu& add(const char* Text, bool selected = false);
    CMenu& operator<<(const char* Text);
    CMenu& operator<<(bool select);
    void draw(int fn = C_FULL_FRAME);
    int edit();
    void set(const void* data);
    int selectedIndex() const;
    int selectedIndex(int index);
    const char* selectedText();
    bool editable()const;
    ~CMenu(void);
  };
  extern const bool Select;
}

#endif

MNode

MNode holds to main about an Item in the menut:

  1. The CMenuItem object
  2. The index of this Item

MNode is a fully private class and is only accessible by CMenu.

Attributes

    CMenuItem* _item;

Holds the address of a dynamically allocated CMenuItem

    unsigned int _index;

Holds the index (sequence -1) number of the CMenuItem in the CMenu.

    MNode* _next;
    MNode* _prev;

Standard next and previous pointer for a linked list node.

Constructor/Destructor

 MNode(CMenuItem* item,unsigned int index, MNode* prev, MNode* next = ((MNode*)0));

Sets the corresponding attributes to the values of the arguments.

~MNode(void);

deletes the _item

CMenu

CMenu is a linked list of MNodes and also contains a CButton for a Title (only used on if in _dropdown mode).
Assuming that a CMenu is created with a title as "FILE" and menu-items as "Save, Load, Print, Quit":

  • When in _dropdown mode:

When drawing, Only the _Title(CButton) is drawn (and not the menu itself)

 FILE

When edited (in _dropdown mode) the CButton gets activated and if it is hit, then the Menu will be dropped down (drawn) under the CButton and user can browse through the options and select one of them. selecting the option in this case will close the menu and CButton gets activated again:
when active, CMenu looks like this:

[FILE]

User hits enter: (since nothing is selected all menu items are unselected)

 FILE
/-------\
| Save  |
| Load  |
| Print |
| Quit  |
\-------/

Now the cursor is standing under Save. User hits down arrow twice to select Print and then hits Space:

[FILE]

The Print is selected and The menu is closed and FILE is active again. If the user hits Enter again:

 FILE
/-------\
| Save  |
| Load  |
|[Print]|
| Quit  |
\-------/

We will see the Print is selected and the cursor in under P. If user hits Enter instead of space, the selection wont change and whatever was selected before will remain the same:

[FILE]

User hits navigation keys and moves out of the CMenu Field. Note that if left or right navigation keys are hit when the title is active, then they are translated to up or down respectively.

  • When NOT in _dropdown mode:
    The CButton will not be displayed at all, and when user starts to edit, he enters the menu browsing the items and if he gets to the end of the menu, the control goes to the next field in the dialog. If user goes up and passes the first them, then the control will go to the previous field in the dalog.
/-------\
| Save  |
| Load  |
|[Print]|
| Quit  |
\-------/

Note that if the number of menu items are more than the space provided by the CField's frame, then the menu items should scroll up and down to accommodate the selection

Attributes

    MNode* _first;

points to the first CMenuItem visible on the menu.

    MNode* _head;
    MNode* _tail;
    MNode* _cur;

standard Link list pointers

    char _format[3];

The two characters used to surround the selected menu item

    unsigned int _cnt;

The number of CMenuItems in CMenu

    int _selectedIndex;

The index of the selected CMenuItem (saved in MNode::index), if there is no selected menu, then this value is -1.

    bool _dropdown;

True if the Menu is a Drop Down Menu.

    bool _dropped;

Flag used to hold the status of a Drop Down Menu, (_dropped or not)

    bool goNext();
    bool goPrev();

standard gonext() and goprev() in linked lists

    CButton _Title;

CButton holding the Title of this menu

Constructor/Destructor

    CMenu(const char* Title, const char* Format, int Row, int Col, 
              int Width, int Height,bool dropdown,  
              const char* Border=C_BORDER_CHARS);
  1. Initializes CField as follows:
    • Row: Passes Row, if this menu is not a dropdown, otherwise it will pass Row+1.
    • Col, Width, Height are passed directly
    • Data: a void null pointer is passed for data
    • Bordered: since CMenu is always bordered, true is passed here
    • Border is directly passed.
  2. Initializes _Title (the CButton) as follows:
    • Str, Title is passed here
    • Row, -1
    • Col, 1
    • Bordered, since the title of the dorpdown is alway NOT bordered, then false is passed here.
  3. Constructor Settings:
    • Link list attributes are set as standard linked list contructor
    • Format is copied into _format
    • _cnt is set to zero
    • _selectedIndex is set to -1
    • _data is set to address of _selectedIndex
    • _dropdown is set to dropdown
    • _dropped is set to false
    • _Title's frame is set to the CMenu object (this)
~CMenu();

Standard Linked list destructor

Methods

    CMenu& add(const char* Text, bool selected = false);

Standard append for a linked list:

  1. creates an MNode with
    • a new CMenutItem with
      selected, _format, Text for first three arguments
      1, 1, and (width of the menu) -2, for Row col and width
    • the rest are what is needed for a standard append procedure for a linked list
  2. appends the new MNode to the end of the list
  3. if the new added CMenuItem is selected, it will update the selected index

Note that if the added CMenuItem is the first CMenuItem in the list, then the _first pointer should be pointing to it

    CMenu& operator<<(const char* Text);

returns add(Text)

    CMenu& operator<<(bool select);

if select is true, it will select the last CMenuItem added to the CMenu

    void draw(int fn = C_FULL_FRAME);
  1. if this is a _dropdown, then it will draw the _Title
    and then if _dropped is true, it will draw the CField and then draw the CMenuItems starting form what _first is pointing to, up to (CField's hieght -2) times.
  2. if this not a _dropdown then the _Title will never be drawn and the CMenuItems should be drawn as above.
    int edit();

Edits the menu the way it is explains in CMenu description.
If it is too confusing, this pseudo code may help.

    void set(const void* data);

Sets the selected index to the integer pointed by data;

    int selectedIndex() const;

returns the selected index or -1 if nothing is selected

    int selectedIndex(int index);

sets the selected index.

    const char* selectedText();

returns the text of the selected menu, if nothing is selected, and empty string is returned.

    bool editable()const;

returns true if _cnt is greater than zero