/** * \file DropDown.C * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * * \author John Levon * * Full author contact details are available in file CREDITS */ #include #ifdef __GNUG__ #pragma implementation #endif #include "DropDown.h" #include "xforms_helpers.h" #include FORMS_H_LOCATION #include #include #ifndef CXX_GLOBAL_CSTD using std::isprint; #endif using std::vector; namespace { extern "C" void C_CompletedCB(FL_OBJECT * ob, long) { DropDown * d = static_cast(ob->u_vdata); d->completed(); } extern "C" int C_PeekCB(FL_FORM * form, void *xev) { DropDown * d = static_cast(form->u_vdata); return d->peek(static_cast(xev)); } } // namespace anon DropDown::DropDown(FL_OBJECT * ob) { form_ = fl_bgn_form(FL_NO_BOX, ob->w, 100); fl_add_box(FL_UP_BOX, 0, 0, ob->w, 100, ""); browser_ = fl_add_browser(FL_SELECT_BROWSER, 0, 0, ob->w, 100, ""); form_->u_vdata = this; browser_->u_vdata = this; fl_set_object_callback(browser_, C_CompletedCB, 0); fl_register_raw_callback(form_, KeyPressMask|ButtonPressMask, C_PeekCB); fl_end_form(); } DropDown::~DropDown() { if (form_->visible) fl_hide_form(form_); fl_free_form(form_); } void DropDown::select(vector const & choices, int x, int y, int w) { if (choices.empty()) return; fl_set_form_geometry(form_, x, y - 100, w, 100); fl_clear_browser(browser_); vector::const_iterator cit = choices.begin(); vector::const_iterator end = choices.end(); for (; cit != end; ++cit) { fl_add_browser_line(browser_, cit->c_str()); } fl_select_browser_line(browser_, 1); fl_show_form(form_, FL_PLACE_POSITION, FL_NOBORDER, ""); XGrabPointer(fl_get_display(), form_->window, false, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, 0, 0, 0); XFlush(fl_get_display()); } void DropDown::line_up() { if (fl_get_browser(browser_) > 1) fl_select_browser_line(browser_, fl_get_browser(browser_) - 1); if (fl_get_browser(browser_) >= fl_get_browser_topline(browser_) + fl_get_browser_screenlines(browser_)) fl_set_browser_topline(browser_, fl_get_browser(browser_) - fl_get_browser_screenlines(browser_) + 1); if (fl_get_browser(browser_) < fl_get_browser_topline(browser_)) fl_set_browser_topline(browser_, fl_get_browser(browser_)); } void DropDown::line_down() { if (fl_get_browser(browser_) < fl_get_browser_maxline(browser_)) fl_select_browser_line(browser_, fl_get_browser(browser_) + 1); if (fl_get_browser(browser_) >= fl_get_browser_topline(browser_) + fl_get_browser_screenlines(browser_)) fl_set_browser_topline(browser_, fl_get_browser(browser_) - fl_get_browser_screenlines(browser_) + 1); if (fl_get_browser(browser_) < fl_get_browser_topline(browser_)) fl_set_browser_topline(browser_, fl_get_browser(browser_)); } int DropDown::peek(XEvent * xev) { int x,y; unsigned int keymask; fl_get_mouse(&x, &y, &keymask); if (xev->type == ButtonPress) { if (!(x >= form_->x && x <= (form_->x + form_->w) && y >= form_->y && y << (form_->y + form_->h))) { fl_hide_form(form_); return 1; } XUngrabPointer(fl_get_display(), CurrentTime); } else if (xev->type == KeyPress) { char s_r[10]; s_r[9] = '\0'; KeySym keysym_return; XLookupString(&xev->xkey, s_r, 10, &keysym_return, 0); switch (keysym_return) { case XK_Down: #ifdef XK_KP_Down case XK_KP_Down: #endif line_down(); return 1; case XK_Up: #ifdef XK_KP_Up case XK_KP_Up: #endif line_up(); return 1; case XK_Return: #ifdef XK_KP_Enter case XK_KP_Enter: #endif completed(); return 1; case XK_Escape: fl_deselect_browser(browser_); completed(); return 1; default: // FIXME: if someone has a got a way to // convince the event to fall back to the // minibuffer, I'm glad to hear it. // fl_XPutBackEvent() doesn't work. // This is a bit less elegant perhaps, but works // well enough. Angus 11 Jan 2002 if (s_r[0] && isprint(s_r[0])) { key_pressed(s_r[0]); return 1; } } } return 0; } void DropDown::completed() { XUngrabPointer(fl_get_display(), CurrentTime); fl_hide_form(form_); result(getString(browser_)); } void DropDown::key_pressed(char c) { XUngrabPointer(fl_get_display(), CurrentTime); fl_hide_form(form_); keypress(c); }