_C PROGRAMMING COLUMN_ by Al Stevens Listing One // -------- editbox.h #ifndef EDITBOX_H #define EDITBOX_H #include "textbox.h" class EditBox : public TextBox { void OpenWindow(); protected: int column; // Current column Bool changed; // True if text has changed Bool insertmode; // True if in insert mode virtual void Home(); virtual void End(); virtual void NextWord(); virtual void PrevWord(); virtual void Forward(); virtual void Backward(); virtual void DeleteCharacter(); virtual void InsertCharacter(int key); public: EditBox(const char *ttl, int lf, int tp, int ht, int wd, DFWindow *par=0) : TextBox(ttl, lf, tp, ht, wd, par) { OpenWindow(); } EditBox(const char *ttl, int ht, int wd, DFWindow *par=0) : TextBox(ttl, ht, wd, par) { OpenWindow(); } EditBox(int lf, int tp, int ht, int wd, DFWindow *par=0) : TextBox(lf, tp, ht, wd, par) { OpenWindow(); } EditBox(int ht, int wd, DFWindow *par=0) : TextBox(ht, wd, par) { OpenWindow(); } EditBox(const char *ttl) : TextBox(ttl) { OpenWindow(); } // -------- API messages virtual Bool SetFocus(); virtual void ResetFocus(); virtual void SetCursor(int x, int y); virtual void ResetCursor(); virtual void SetCursorSize(); virtual unsigned char CurrentChar() { return (*text)[column]; } virtual unsigned CurrentCharPosition() { return column; } virtual Bool AtBufferStart() { return (Bool) (column == 0); } virtual void Keyboard(int key); virtual void Move(int x, int y); virtual void Paint(); virtual void PaintCurrentLine() { Paint(); } virtual void ClearText(); virtual void LeftButton(int mx, int my); Bool Changed() { return changed; } void ClearChanged() { changed = False; } Bool InsertMode() { return insertmode; } void SetInsertMode(Bool imode) { insertmode = imode; ResetCursor(); } }; inline Bool isWhite(int ch) { return (Bool) (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r'); } #endif Listing Two // ------------- editbox.cpp #include #include "desktop.h" #include "editbox.h" // ----------- common constructor code void EditBox::OpenWindow() { windowtype = EditboxWindow; column = 0; changed = False; text = new String(1); BuildTextPointers(); } Bool EditBox::SetFocus() { Bool rtn = TextBox::SetFocus(); if (rtn) { ResetCursor(); desktop.cursor().Show(); } return rtn; } void EditBox::ResetFocus() { desktop.cursor().Hide(); TextBox::ResetFocus(); } // -------- process keystrokes void EditBox::Keyboard(int key) { int shift = desktop.keyboard().GetShift(); if ((shift & ALTKEY) == 0) { switch (key) { case HOME: Home(); return; case END: End(); return; case CTRL_FWD: NextWord(); return; case CTRL_BS: PrevWord(); return; case FWD: Forward(); return; case BS: Backward(); return; case RUBOUT: if (CurrentCharPosition() == 0) break; Backward(); // --- fall through case DEL: DeleteCharacter(); BuildTextPointers(); PaintCurrentLine(); return; default: if (!isprint(key)) break; // --- printable keys processed by editbox InsertCharacter(key); BuildTextPointers(); PaintCurrentLine(); return; } } TextBox::Keyboard(key); } // -------- paint the editbox void EditBox::Paint() { TextBox::Paint(); ResetCursor(); } // -------- move the editbox void EditBox::Move(int x, int y) { TextBox::Move(x, y); ResetCursor(); } // --------- clear the text from the editbox void EditBox::ClearText() { TextBox::ClearText(); OpenWindow(); ResetCursor(); } // ----- move cursor to left margin void EditBox::Home() { column = 0; if (wleft) { wleft = 0; Paint(); } ResetCursor(); } // ----- move the cursor to end of line void EditBox::End() { int ch; while ((ch = CurrentChar()) != '\0' && ch != '\n') column++; if (column - wleft >= ClientWidth()) { wleft = column - ClientWidth() + 1; Paint(); } ResetCursor(); } // ---- move the cursor to the next word void EditBox::NextWord() { while (!isWhite(CurrentChar()) && CurrentChar()) Forward(); while (isWhite(CurrentChar())) Forward(); } // ---- move the cursor to the previous word void EditBox::PrevWord() { Backward(); while (isWhite(CurrentChar()) && !AtBufferStart()) Backward(); while (!isWhite(CurrentChar()) && !AtBufferStart()) Backward(); if (isWhite(CurrentChar())) Forward(); } // ---- move the cursor one character to the right void EditBox::Forward() { if (CurrentChar()) { column++; if (column-wleft == ClientWidth()) ScrollLeft(); ResetCursor(); } } // ---- move the cursor one character to the left void EditBox::Backward() { if (column) { if (column == wleft) ScrollRight(); --column; ResetCursor(); } } // ---- insert a character into the edit buffer void EditBox::InsertCharacter(int key) { unsigned col = CurrentCharPosition(); if (insertmode || CurrentChar() == '\0') { // ---- shift the text to make room for new character String ls, rs; if (col) ls = text->left(col); int rt = text->Strlen()-col; if (rt > 0) rs = text->right(rt); *text = ls + " " + rs; } (*text)[col] = (char) key; if (key == '\n') BuildTextPointers(); Forward(); changed = True; } // ---- delete a character from the edit buffer void EditBox::DeleteCharacter() { if (CurrentChar()) { String ls, rs; unsigned col = CurrentCharPosition(); if (col) ls = text->left(col); int rt = text->Strlen()-col-1; if (rt > 0) rs = text->right(rt); *text = ls + rs; changed = True; } } // ---- position the cursor void EditBox::SetCursor(int x, int y) { desktop.cursor().SetPosition( x+ClientLeft()-wleft, y+ClientTop()-wtop); } // ---- left mouse button was pressed void EditBox::LeftButton(int mx, int my) { if (ClientRect().Inside(mx, my)) { column = max(0, min(text->Strlen()-1, mx-ClientLeft()+wleft)); ResetCursor(); } else TextBox::LeftButton(mx, my); } // ---- set the size of the cursor void EditBox::SetCursorSize() { if (insertmode) desktop.cursor().BoxCursor(); else desktop.cursor().NormalCursor(); } // ---- reset the cursor void EditBox::ResetCursor() { SetCursorSize(); if (visible) SetCursor(column, 0); } Example 1: The compile problem in (a) dodged by the using the member pointer with the qualification in (b). (a) template class Foo { Foo *nextfoo; // ... }; (b) Foo *nextfoo; Example 2: The template function template void Foo(T *tp) { *tp = 321; } template void Bar(T& tr) { Foo(&tr); } main() { int x = 123; Bar(x); } Example 3: The compiler declares a fatal compile error if a non- void function fails to return something in (a) although this contradicts the ARM rule in (b). (a) #include main() { cout << "Hello, Timna"; } (b) extern f(); main() { }