X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fxforms%2FXMiniBuffer.C;h=a6b228aa998282939e94cb690ed968520edf594f;hb=37e82a546392d43f787826b85481a11f2a27af15;hp=790a16234e64bd534053ad9910b6ea7e1e0f6235;hpb=72a19def2905c725299b569f0dd41b793f43178a;p=lyx.git diff --git a/src/frontends/xforms/XMiniBuffer.C b/src/frontends/xforms/XMiniBuffer.C index 790a16234e..a6b228aa99 100644 --- a/src/frontends/xforms/XMiniBuffer.C +++ b/src/frontends/xforms/XMiniBuffer.C @@ -1,196 +1,212 @@ -// -*- C++ -*- /** * \file XMiniBuffer.C - * Copyright 1995-2002 the LyX Team - * Read the file COPYING + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. * * \author Lars - * \author Asger and Juergen + * \author Asger and Jürgen + * + * Full author contact details are available in file CREDITS. */ #include -#ifdef __GNUG__ -#pragma implementation -#endif +#include "XMiniBuffer.h" +#include "XFormsView.h" + +#include "freebrowser.h" +#include "xforms_helpers.h" + +#include "controllers/ControlCommandBuffer.h" -#include "frontends/xforms/DropDown.h" -#include "frontends/xforms/XFormsView.h" #include "frontends/Timeout.h" -#include "XMiniBuffer.h" -#include "BufferView.h" -#include "LyXAction.h" #include "gettext.h" -#include "support/lyxalgo.h" -#include "support/lstrings.h" #include -#include -#include - -#ifndef CXX_GLOBAL_CSTD -using std::isprint; -#endif +using boost::shared_ptr; using std::vector; +using std::string; +namespace lyx { +namespace frontend { namespace { -struct prefix { - string p; - prefix(string const & s) - : p(s) {} - bool operator()(string const & s) const { - return prefixIs(s, p); - } -}; +/// This creates the input widget for the minibuffer +FL_OBJECT * create_input_box(void * parent, int type); -} // end of anon namespace +FL_FREEBROWSER * create_freebrowser(void * parent); +} // namespace anon -XMiniBuffer::XMiniBuffer(LyXView * o, FL_Coord x, FL_Coord y, - FL_Coord h, FL_Coord w) - : MiniBuffer(o) + +XMiniBuffer::XMiniBuffer(XFormsView & owner, + ControlCommandBuffer & control) + : controller_(control), + info_shown_(false) { - create_input_box(FL_NORMAL_INPUT, x, y, h, w); + input_ = create_input_box(this, FL_NORMAL_INPUT); + freebrowser_.reset(create_freebrowser(this), fl_free_freebrowser); + + // The minibuffer is 25 pixels high and is embedded inside a + // 2 pixel deep frame. + int const air = 2; + + BoxList & boxlist = owner.getBox(XFormsView::Bottom)->children(); + minibuffer_ = boxlist.push_back(Box(0,0)); + shared_ptr center = embed(input_, minibuffer_->children(), widgets_, air); + center->set(Box::Expand); + center->setMinimumDimensions(0, 25); + + owner.metricsUpdated.connect(boost::bind(&WidgetMap::updateMetrics, + &widgets_)); + + info_timer_.reset(new Timeout(1500)); + idle_timer_.reset(new Timeout(6000)); + info_con = info_timer_->timeout.connect(boost::bind(&XMiniBuffer::info_timeout, this)); + idle_con = idle_timer_->timeout.connect(boost::bind(&XMiniBuffer::idle_timeout, this)); + idle_timer_->start(); messageMode(); } -// thanks for nothing, xforms (recursive creation not allowed) -void XMiniBuffer::dd_init() -{ - dropdown_ = new DropDown(owner_, the_buffer); - dropdown_->result.connect(boost::bind(&XMiniBuffer::set_complete_input, this, _1)); - dropdown_->keypress.connect(boost::bind(&XMiniBuffer::append_char, this, _1)); -} +// This is here so that scoped ptr will not require a complete type. +XMiniBuffer::~XMiniBuffer() +{} -XMiniBuffer::~XMiniBuffer() +void XMiniBuffer::freebrowserCB(int action) { - delete dropdown_; + if (action < 0 || action > 1) + // unrecognized action + return; + + if (action == 0) + // The freebrowser has been hidden + return; + + if (freebrowser_->last_printable) { + // Append this char to the current input contents + string input = getString(input_); + input += freebrowser_->last_printable; + fl_set_input(input_, input.c_str()); + + } else { + // Fill the input widget with the selected + // browser entry. + FL_OBJECT * browser = freebrowser_->browser; + string const str = getString(browser); + + if (!str.empty()) { + // add a space so the user can type + // an argument immediately + set_input(str + ' '); + } + } } int XMiniBuffer::peek_event(FL_OBJECT * ob, int event, int key, XEvent * /*xev*/) { -#if 0 - if (dropdown_->isVisible()) { - return dropdown_->peek(xev); - } -#endif - switch (event) { + case FL_FOCUS: + messageMode(false); + break; case FL_UNFOCUS: messageMode(); break; case FL_KEYBOARD: { string input; - if (information_displayed_) { - information_timer_->stop(); - input = stored_input; - restore_input(); - } else { - char const * tmp = fl_get_input(ob); - input = tmp ? tmp : ""; + if (info_shown_) { + info_timer_->stop(); + info_timeout(); } + char const * tmp = fl_get_input(ob); + input = tmp ? tmp : ""; switch (key) { case XK_Down: #ifdef XK_KP_Down case XK_KP_Down: #endif - if (hist_iter != history_->end()) { - ++hist_iter; - } - if (hist_iter == history_->end()) { - // no further history - show_information(_("[End of history]"), input); + { + string const h(controller_.historyDown()); + if (h.empty()) { + show_info(_("[End of history]"), input, false); } else { - set_input((*hist_iter)); + set_input(h); } return 1; + } + case XK_Up: #ifdef XK_KP_Up case XK_KP_Up: #endif - if (hist_iter == history_->begin()) { - // no further history - show_information(_("[Beginning of history]"), - input); + { + string const h(controller_.historyUp()); + if (h.empty()) { + show_info(_("[Beginning of history]"), input, false); } else { - --hist_iter; - set_input((*hist_iter)); + set_input(h); } return 1; + } + case 9: case XK_Tab: { - // Completion handling. + string new_input; + vector comp = controller_.completions(input, new_input); - vector comp; - lyx::copy_if(completion_.begin(), - completion_.end(), - back_inserter(comp), prefix(input)); + if (comp.empty() && new_input == input) { + show_info(_("[no match]"), input); + break; + } if (comp.empty()) { - // No matches - string const tmp = input + _(" [no match]"); - show_information(tmp, input); - } else if (comp.size() == 1) { - // Perfect match - string const tmp = - comp[0] + _(" [sole completion]"); - show_information(tmp, comp[0] + " "); - } else { - // More that one match - // Find maximal avaliable prefix - string const tmp = comp[0]; - string test(input); - if (tmp.length() > test.length()) - test += tmp[test.length()]; - while (test.length() < tmp.length()) { - vector vtmp; - lyx::copy_if(comp.begin(), - comp.end(), - back_inserter(vtmp), - prefix(test)); - if (vtmp.size() != comp.size()) { - test.erase(test.length() - 1); - break; - } - test += tmp[test.length()]; - } - set_input(test); - - int x,y,w,h; - fl_get_wingeometry(fl_get_real_object_window(the_buffer), - &x, &y, &w, &h); - - // asynchronous completion - int const air = the_buffer->x; - x += air; - y += h - (the_buffer->h + air); - w = the_buffer->w; - dropdown_->select(comp, x, y, w); + set_input(new_input); + show_info(_("[only completion]"), new_input + ' '); + break; + } + + set_input(new_input); + + // Fill freebrowser_'s browser with the list of + // available completions + FL_OBJECT * browser = freebrowser_->browser; + fl_clear_browser(browser); + vector::const_iterator cit = comp.begin(); + vector::const_iterator end = comp.end(); + for (; cit != end; ++cit) { + fl_add_browser_line(browser, cit->c_str()); } + fl_select_browser_line(browser, 1); + + // Set the position of the freebrowser and display it. + int x,y,w,h; + fl_get_wingeometry(fl_get_real_object_window(input_), + &x, &y, &w, &h); + + // asynchronous completion + int const air = input_->x; + x += air; + y += h - (input_->h + air); + w = input_->w; + h = 100; + + fl_show_freebrowser(freebrowser_.get(), x, y-h, w, h); return 1; } case 27: case XK_Escape: - // Abort -#if 0 - owner_->view()->focus(true); -#endif - message_timeout(); messageMode(); - //escape.emit(); return 1; case 13: case XK_Return: @@ -198,33 +214,9 @@ int XMiniBuffer::peek_event(FL_OBJECT * ob, int event, case XK_KP_Enter: #endif { -#if 0 - // This will go in again in a little while - // we need to be able to declare what types - // of argumetns LFUN's should have first. (Lgb) - // First check for match - vector::const_iterator cit = - find(completion_.begin(), - completion_.end(), - input); - if (cit == completion_.end()) { - // no such func/item - string const tmp = input + _(" [no match]"); - show_information(tmp, input); - } else { -#endif - // Return the inputted string - messageMode(); -#if 0 - owner_->view()->focus(true); -#endif - if (!input.empty()) { - history_->push_back(input); - } - inputReady(input); -# if 0 - } -#endif + messageMode(); + redraw(); + controller_.dispatch(input); return 1; } default: @@ -232,7 +224,6 @@ int XMiniBuffer::peek_event(FL_OBJECT * ob, int event, } } default: - //lyxerr << "Unhandled minibuffer event!" << endl; break; } @@ -240,88 +231,133 @@ int XMiniBuffer::peek_event(FL_OBJECT * ob, int event, } -extern "C" { +void XMiniBuffer::freeze() +{ + // we must prevent peek_event, or we get an unfocus() when the + // containing form gets destroyed + fl_set_object_prehandler(input_, 0); +} - static - int C_XMiniBuffer_peek_event(FL_OBJECT * ob, int event, - FL_Coord, FL_Coord, - int key, void * xev) - { - XMiniBuffer * mini = static_cast(ob->u_vdata); - return mini->peek_event(ob, event, key, - static_cast(xev)); - } +void XMiniBuffer::show_info(string const & info, string const & input, bool append) +{ + stored_input_ = input; + info_shown_ = true; + if (append) + set_input(input + ' ' + info); + else + set_input(info); + info_timer_->start(); } -FL_OBJECT * XMiniBuffer::create_input_box(int type, FL_Coord x, FL_Coord y, - FL_Coord w, FL_Coord h) +void XMiniBuffer::idle_timeout() { - FL_OBJECT * obj; + set_input(controller_.getCurrentState()); +} - the_buffer = obj = fl_add_input(type, x, y, w, h, text.c_str()); - fl_set_object_boxtype(obj, FL_DOWN_BOX); - fl_set_object_resize(obj, FL_RESIZE_ALL); - fl_set_object_gravity(obj, SouthWestGravity, SouthEastGravity); - fl_set_object_color(obj, FL_MCOL, FL_MCOL); - fl_set_object_lsize(obj, FL_NORMAL_SIZE); - // To intercept Up, Down, Table for history - fl_set_object_prehandler(obj, C_XMiniBuffer_peek_event); - obj->u_vdata = this; - obj->wantkey = FL_KEY_TAB; +void XMiniBuffer::info_timeout() +{ + info_shown_ = false; + set_input(stored_input_); +} - set_input(text); - return obj; +bool XMiniBuffer::isEditingMode() const +{ + return input_->focus; } -bool XMiniBuffer::isEditingMode() const +void XMiniBuffer::messageMode(bool on) { - return the_buffer->focus; + set_input(""); + if (!on) { + fl_activate_object(input_); + fl_set_focus_object(input_->form, input_); + redraw(); + idle_timer_->stop(); + } else { + if (isEditingMode()) { + // focus back to the workarea + fl_set_focus_object(input_->form, 0); + idle_timer_->start(); + } + } } -void XMiniBuffer::editingMode() +void XMiniBuffer::redraw() { - fl_activate_object(the_buffer); - fl_set_focus_object(static_cast(owner_)->getForm(), - the_buffer); - redraw(); + fl_redraw_object(input_); + XFlush(fl_display); } -void XMiniBuffer::messageMode() +void XMiniBuffer::message(string const & str) { - fl_deactivate_object(the_buffer); - redraw(); + if (!isEditingMode()) + set_input(str); } -void XMiniBuffer::redraw() +void XMiniBuffer::set_input(string const & str) { - fl_redraw_object(the_buffer); - XFlush(fl_display); + fl_set_input(input_, str.c_str()); +} + + +namespace { + +extern "C" +int C_XMiniBuffer_peek_event(FL_OBJECT * ob, int event, + FL_Coord, FL_Coord, + int key, void * xev) +{ + XMiniBuffer * mini = static_cast(ob->u_vdata); + return mini->peek_event(ob, event, key, static_cast(xev)); } -void XMiniBuffer::append_char(char c) +extern "C" +void C_freebrowserCB(FL_FREEBROWSER * fb, int action) { - if (!c || !isprint(c)) + if (!fb || !fb->parent) return; - char const * tmp = fl_get_input(the_buffer); - string str = tmp ? tmp : ""; + XMiniBuffer * ptr = static_cast(fb->parent); + ptr->freebrowserCB(action); +} - str += c; - fl_set_input(the_buffer, str.c_str()); +FL_OBJECT * create_input_box(void * parent, int type) +{ + FL_OBJECT * obj = fl_add_input(type, 0, 0, 0, 0, ""); + fl_set_object_boxtype(obj, FL_DOWN_BOX); + fl_set_object_resize(obj, FL_RESIZE_ALL); + fl_set_object_gravity(obj, SouthWestGravity, SouthEastGravity); + fl_set_object_color(obj, FL_MCOL, FL_MCOL); + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + + // To intercept Up, Down, Table for history + fl_set_object_prehandler(obj, C_XMiniBuffer_peek_event); + obj->u_vdata = parent; + obj->wantkey = FL_KEY_TAB; + + return obj; } -void XMiniBuffer::set_input(string const & str) +FL_FREEBROWSER * create_freebrowser(void * parent) { - fl_set_input(the_buffer, str.c_str()); + FL_FREEBROWSER * fb = fl_create_freebrowser(parent); + fb->want_printable = 1; + fb->callback = C_freebrowserCB; + return fb; } + +} // namespace anon + +} // namespace frontend +} // namespace lyx