/* TUIpeer works in conjunction with an implementation of java.awt.Toolkit to provide a Text User Interface for programs using the Java AWT. TUI components to display and edit text Copyright (C) 1997-2000 Stuart D. Gathman This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: textcomp.cc,v $ * Revision 1.2 2000/12/18 01:58:57 stuart * Removed dependencies on libg++. * Changed all references to String to string. * Changed libg++ String idioms to string idioms. * Copied Obstack from libg++ and hacked it to throw an exception on error. * Hacked Set.cc to throw an exception on error. * Added Str.cc to relace the split function from libg++. * * Revision 1.1.1.1 2000/12/16 20:45:08 stuart * Released TUIPeer sources * * Revision 1.1 2000/12/14 21:03:53 stuart * Initial revision * */ #pragma implementation #include #include "textcomp.h" #include "wincomp.h" #include "textdraw.h" #include #include LabelComponent::LabelComponent() { alignment = LEFT; bgColor = 1; fgColor = 0; textAttr = getAttr(); enabled = false; } void LabelComponent::getfocus() { nextFocus(); } void LabelComponent::remoteMethod(int cmd) { switch (cmd) { case SETALIGNMENT: setAlign(readShort()); return; case SETTEXT: setText(readUTF()); return; case DISABLE: if (enabled) { bgColor = 1; textAttr = getAttr(); invalidate(); } break; case ENABLE: if (!enabled) { bgColor = 2; textAttr = getAttr(); invalidate(); } break; } Component::remoteMethod(cmd); } void LabelComponent::setText(const string &s) { txt = s; invalidate(); } void LabelComponent::setAlign(int a) { if (alignment != a) { alignment = a; invalidate(); } } void LabelComponent::paint(DrawingContext *dc) { int len = txt.length(); //fprintf(stderr,"Label::paint(`%s',%04X)\n",txt.chars(),textAttr); dc->fillRect(dc->clipRect(),' '|textAttr); switch (alignment) { case LEFT: dc->writeStr(0,0,txt,textAttr); break; case CENTER: dc->writeStr(width/2,0,txt,textAttr); break; case RIGHT: dc->writeStr(width - len,0,txt,textAttr); break; } } CheckBox::CheckBox() { checked = false; } void CheckBox::remoteMethod(int cmd) { switch (cmd) { case SETSTATE: setState(readShort() != 0); return; } LabelComponent::remoteMethod(cmd); } void CheckBox::setState(bool state) { if (checked != state) { checked = state; invalidate(); } } void CheckBox::paint(DrawingContext *dc) { string txt(checked ? "[X] " : "[ ] "); txt += getText(); //fprintf(stderr,"Checkbox::paint(`%s')\n",txt.chars()); dc->fillRect(dc->clipRect(),' '|textAttr); dc->writeStr(0,0,txt,textAttr); } void CheckBox::getfocus() { Component::getfocus(); setCursor(1,0); } Button::Button() { bgColor = 2; textAttr = getAttr(); enabled = true; } void Button::getfocus() { Component::getfocus(); setCursor(0,0); } void Button::key(int ky) { switch (ky) { case KEY_ENTER: case ' ': case '\r': toolkit->callMethod(compID,MENUPICK); return; } Component::key(ky); } TextComponent::TextComponent() { readonly = true; columns = 0; select(0,0); } TextComponent::~TextComponent() { } void TextComponent::getfocus() { Component::getfocus(); TextEdit::getfocus(); } void TextComponent::remoteMethod(int cmd) { switch (cmd) { case GETSELECTEND: toolkit->callMethod(0,RETSHORT,getEnd()); return; case GETSELECTBEG: toolkit->callMethod(0,RETSHORT,getStart()); return; case GETTEXT: toolkit->callMethod(0,RETSTRING,getText()); return; case SELECT: { int beg = readShort(); int end = readShort(); select(beg,end); return; } case SETCOLUMNS: columns = readShort(); wrapmargin = columns - 1; return; case SETEDITABLE: setEditable(readShort() != 0); return; case SETTEXT: setText(readUTF().c_str()); return; } Component::remoteMethod(cmd); } const string TextArea::getText() const { int n = txt.size(); if (n == 0) return ""; string res(txt[0]); for (int i = 1; i < n; ++i) { res += '\n'; res += txt[i]; } modified = false; return res; } void TextComponent::setEditable(bool b) { readonly = !b; } void TextArea::setText(string s) { txt.clear(); for (int pos = 0; pos < s.length(); ++pos) { int n = s.find('\n',pos); if (n < 0) { txt.add(string(s,pos)); break; } txt.add(string(s,pos,n - pos)); pos = n; } invalidate(); modified = false; } void TextField::setText(string s) { txt.clear(); txt.add(s); invalidate(); modified = false; } const string TextField::getText() const { modified = false; return txt[0]; } void TextField::move(int, int c) { if (wrapmargin > 0 && c > wrapmargin) c = wrapmargin; TextEdit::move(c < 0,c); // restrict to 1st line } void TextField::reform(bool) { } // no reformatting void TextField::insch(char c) { if (isGap() && wrapmargin > 0) { if (txt[0].length() > wrapmargin) { Window::beep(); return; } } TextComponent::insch(c); } void TextComponent::key(int ky) { //fprintf(stderr,"TextComponent::key(%d) CMD=%d\n",ky,commandMode()); // TextArea action only available from command mode if (parent && (readonly || commandMode())) switch (ky) { case KEY_ENTER: case '\r': toolkit->callMethod(compID,MENUPICK); return; } // Keep TAB for moving between components and SELECT for moving between // windows for TextArea. This removes the ability to insert tabs // or use line-drawing mode. We can probably enable inserting TAB // via a "literal" key. if (parent) switch (ky) { case KEY_TAB: case KEY_BTAB: // Java FocusManager will not tab from a TextArea, so we // do it locally. nextFocus(); return; case KEY_SELECT: Component::key(ky); return; } bool wasmodified = modified; TextEdit::key(ky); // FIXME: should have setModified() virtual method if (modified && !wasmodified) toolkit->callMethod(compID,SETMODIFIED); } void TextField::key(int ky) { if (ky < 0) return; //fprintf(stderr,"TextField::key(%d)\n",ky); if (parent) switch (ky) { case KEY_ENTER: case '\r': toolkit->callMethod(compID,MENUPICK); return; case KEY_UP: case KEY_DOWN: case KEY_PPAGE: case KEY_NPAGE: case KEY_SELECT: case KEY_TAB: case KEY_BTAB: Component::key(ky); return; default: if (KEY_F(1) <= ky && ky <= KEY_F(20)) { Component::key(ky); return; } } TextComponent::key(ky); } #if 0 // an experimental hack to mark textfields with [ ] void TextField::paint(DrawingContext *dc) { dc->writeStr(0,0,"[",A_NORMAL); dc->writeStr(width-1,0,"]",A_NORMAL); Rect r(dc->clipRect()); ++r.c1; --r.c2; dc->clipRect(r); dc->translate(1,0); TextComponent::paint(dc); } Dimension TextField::size() const { Dimension sz(TextComponent::size()); return Dimension(sz.width - 2,sz.height); } void TextField::setCursor(int x,int y) { Component::setCursor(x+1,y); } #endif void TextField::remoteMethod(int cmd) { switch (cmd) { case SETECHOCHAR: setEchoChar((char)readShort()); return; } TextComponent::remoteMethod(cmd); } void TextArea::remoteMethod(int cmd) { switch (cmd) { case REPLACETEXT: { string s(readUTF()); int start = readShort(); int end = readShort(); replaceText(s,start,end); return; } } TextComponent::remoteMethod(cmd); } void TextArea::append(const string &s) { move(-1,-1); replaceText(s); }