/* * Copyright (c) 1995-1996 Vectaport Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the names of the copyright holders not be used in * advertising or publicity pertaining to distribution of the software * without specific, written prior permission. The copyright holders make * no representations about the suitability of this software for any purpose. * It is provided "as is" without express or implied warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. * IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*****************************************************************************/ GFieldEditor::GFieldEditor(char* init, GFieldEditorAction* act, float minwidth) : InputHandler(nil, Session::instance()->style()) { field_ = new EivTextBuffer(); if (init && strlen(init) > 0) { field_->Insert(0, init, strlen(init)); } point_pos_ = 0; mark_pos_ = 0; action_ = act; minwidth_ = minwidth; cursor_is_on_= false; int thickness; Style *s = Session::instance()->style(); s->find_attribute("frameThickness", _frame_thickness); make_body(); } GFieldEditor::~GFieldEditor() { delete field_; } void GFieldEditor::keystroke(const Event& e) { char buf[3]; int count = e.mapkey(buf, 3); if (count == 1) switch(buf[0]) { case '\001': // Ctrl-A { beginning_of_line(); break; } case '\002': // Ctrl-B { backward_char(); break; } case '\004': // Ctrl-D { if (mark_pos_ == point_pos_) delete_char_forward(); else delete_region(); break; } case '\005': // Ctrl-E { end_of_line(); break; } case '\006': // Ctrl-F { forward_char(); break; } case '\007': // Ctrl-G case '\033': // Escape { if (action_ != nil) action_->cancel(this); clear_buffer(); break; } case '\010': // Ctrl-H case '\177': // DEL { if (mark_pos_ == point_pos_) delete_char_backward(); else delete_region(); break; } case '\013': // Ctrl-K { delete_to_eol(); break; } case '\015': // Ctrl-M { if (action_ != nil) action_->accept(this); break; } default: // the "normal" case, insert a char, too bad it's buried here.. { if (mark_pos_ != point_pos_) delete_region(); insert_char(buf[0]); if (action_ != nil) action_->accept(this); break; } } } InputHandler* GFieldEditor::focus_in() { cursor_on(); update(); return InputHandler::focus_in(); } void GFieldEditor::focus_out() { cursor_off(); update(); if (action_ != nil) action_->accept(this); InputHandler::focus_out(); } void GFieldEditor::cursor_on() { cursor_is_on_= true; } void GFieldEditor::cursor_off() { cursor_is_on_= false; } const char* GFieldEditor::text() { return field_->Text(); } void GFieldEditor::make_body() { LayoutKit& lk = *LayoutKit::instance(); WidgetKit& wk = *WidgetKit::instance(); PolyGlyph* label_; PolyGlyph* cursor_; PolyGlyph* body_; body_ = lk.overlay(); body_->append(lk.vcenter(label_ = lk.hbox())); label_->append(lk.hspace(2)); int bar1 = Math::min(point_pos_, mark_pos_); int bar2 = Math::max(point_pos_, mark_pos_); #if 0 if (!cursor_is_on_) bar1 = bar2; #endif int i = 0; Display* d = Session::instance()->default_display(); for (; i < bar1; i++) { label_->append(new Character(*field_->Text(i), wk.font(), Color::lookup(d, "black"))); } for (; i < bar2; i++) { label_->append(new Character(*field_->Text(i), wk.font(), Color::lookup(d, "white"))); } for (; i Length(); i++) { label_->append(new Character(*field_->Text(i), wk.font(), Color::lookup(d, "black"))); } #if 0 for (; i append(new Character(' ', wk.font(), Color::lookup(d, "black"))); } #endif label_->append(lk.hglue(0, fil, fil)); if (cursor_is_on_) { body_->append(lk.vcenter(cursor_ = lk.hbox())); float curoff = wk.font()->width(field_->Text(), point_pos_); cursor_->append(lk.hspace(curoff)); cursor_->append(new Fig31Line(new Brush(0), wk.foreground(), nil, 0, 0, 0, wk.font()->Height())); cursor_->append(lk.hglue(0, fil, fil)); } if (minwidth_>0.0) body(wk.inset_frame(lk.hnatural(lk.vfixed(new Target(body_, TargetPrimitiveHit),wk.font()->Height()), minwidth_))); else body(wk.inset_frame(lk.vfixed(new Target(body_, TargetPrimitiveHit), wk.font()->Height()))); } void GFieldEditor::update() { make_body(); redraw(); } void GFieldEditor::beginning_of_line() { mark_pos_ = point_pos_ = 0; update(); } void GFieldEditor::end_of_line() { mark_pos_ = point_pos_ = field_->Length(); update(); } void GFieldEditor::forward_char() { if (point_pos_ < field_->Length()) { mark_pos_ = ++point_pos_; update(); } } void GFieldEditor::backward_char() { if (point_pos_ > 0) { mark_pos_ = --point_pos_; update(); } } void GFieldEditor::delete_char_forward() { if (point_pos_ < field_->Length()) { field_->Delete(point_pos_, 1); update(); } } void GFieldEditor::delete_char_backward() { if (point_pos_ > 0) { mark_pos_ = --point_pos_; field_->Delete(point_pos_, 1); update(); } } void GFieldEditor::delete_region() { if (mark_pos_ > point_pos_) { for (int i= point_pos_; iDelete(point_pos_, 1); mark_pos_ = point_pos_; } else { for (int i= mark_pos_; iDelete(mark_pos_, 1); point_pos_ = mark_pos_; } update(); } void GFieldEditor::delete_to_eol() { while (field_->Length() > point_pos_) field_->Delete(point_pos_, 1); update(); } void GFieldEditor::insert_char(char ch) { /* check to see if this character would exceed the allocation */ const Allocation& a = allocation(); WidgetKit& wk = *WidgetKit::instance(); float swidth = wk.font()->width(field_->Text(), field_->Length()); char cbuf[] = { ch, '\0' }; float cwidth = wk.font()->width((char*) cbuf, 1); float fwidth = a.right() - a.left() - _frame_thickness*2; if (swidth + cwidth > fwidth ) { cerr << "\007"; return; } mark_pos_ = ++point_pos_; char s[2]; s[0] = ch; s[1] = '\0'; field_->Insert(point_pos_ - 1, s, 1); update(); } void GFieldEditor::clear_buffer() { field_->Delete(0,field_->characters()); mark_pos_ = point_pos_ = 0; update(); } void GFieldEditor::select_all() { mark_pos_ = 0; point_pos_ = field_->characters(); update(); } GFieldEditorAction::GFieldEditorAction() { } GFieldEditorAction::~GFieldEditorAction() { } void GFieldEditorAction::accept(GFieldEditor*) { } void GFieldEditorAction::cancel(GFieldEditor*) { } void GFieldEditor::press (const Event& event) { point_pos_ = locate(event); if (!event.shift_is_down()) mark_pos_ = point_pos_; } void GFieldEditor::drag (const Event& event) { point_pos_ = locate(event); update(); } int GFieldEditor::locate (const Event& event) { WidgetKit& wk = *WidgetKit::instance(); const Allocation& a = allocation(); float x = event.pointer_x(); int loc = 0; float xoff = a.left() + _frame_thickness; while (locLength()) { xoff += wk.font()->width(field_->Text()+loc, 1); if (xoff < x ) loc++; else break; } return loc; }