home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / lyx-0.13.2.tar.gz / lyx-0.13.2.tar / lyx-0.13.2 / src / BufferView.C < prev    next >
C/C++ Source or Header  |  1998-04-23  |  36KB  |  1,419 lines

  1. // -*- C++ -*-
  2. /* This file is part of
  3. * ======================================================
  4. *           LyX, The Document Processor
  5. *        
  6. *           Copyright (C) 1995 Matthias Ettrich
  7. *           Copyright (C) 1995-1998 The LyX Team.
  8. *
  9. *======================================================*/
  10.  
  11. #include <config.h>
  12.  
  13. #include <stdlib.h>
  14.  
  15. #ifdef __GNUG__
  16. #pragma implementation
  17. #endif
  18.  
  19. #include "commandtags.h"
  20. #include "BufferView.h"
  21. #include "bufferlist.h"
  22. #include "LyXView.h"
  23. #include "lyxfunc.h"
  24. #include "minibuffer.h"
  25. #include "lyxscreen.h"
  26. #include "up.xpm"
  27. #include "down.xpm"
  28. #include "error.h"
  29. #include "lyxdraw.h"
  30. #include "lyx_gui_misc.h"
  31. #include "BackStack.h"
  32. #include "lyxtext.h"
  33. #include "lyx_cb.h"
  34. #include "gettext.h"
  35.  
  36. //     $Id: BufferView.C,v 1.1.1.1 1998/04/23 16:02:46 larsbj Exp $    
  37.  
  38. #if !defined(lint) && !defined(WITH_WARNINGS)
  39. static char vcid[] = "$Id: BufferView.C,v 1.1.1.1 1998/04/23 16:02:46 larsbj Exp $";
  40. #endif /* lint */
  41.  
  42. extern BufferList bufferlist;
  43.  
  44. extern void SetXtermCursor(Window win);
  45. extern bool input_prohibited;
  46. extern bool selection_possible;
  47. extern void BeforeChange();
  48. extern char ascii_type;
  49. extern int UnlockInset(UpdatableInset* inset);
  50. extern void ToggleFloat();
  51. extern void MenuPasteSelection(char at);
  52. extern InsetUpdateStruct *InsetUpdateList;
  53. extern void UpdateInsetUpdateList();
  54.  
  55. // This is _very_ temporary
  56. FL_OBJECT *figinset_canvas;
  57.  
  58. BufferView::BufferView(LyXView *o, int xpos, int ypos,
  59.                int width, int height)
  60.     : _owner(o)
  61. {
  62.     _buffer = 0;
  63.     
  64.     screen = 0;
  65.     work_area = 0;
  66.     figinset_canvas = 0;
  67.     scrollbar = 0;
  68.     button_down = 0;
  69.     button_up = 0;
  70.     timer_cursor = 0;
  71.     current_scrollbar_value = 0;
  72.     create_view(xpos, ypos, width, height);
  73.     // Activate the timer for the cursor 
  74.     fl_set_timer(timer_cursor, 0.4);
  75.     fl_set_focus_object(_owner->getForm(), work_area);
  76.     work_area_focus = true;
  77.     lyx_focus = false;
  78.         backstack = new BackStack(16);
  79. }
  80.  
  81.  
  82. BufferView::~BufferView()
  83. {
  84.     delete backstack;
  85. }   
  86.  
  87.  
  88. void BufferView::setBuffer(Buffer *b)
  89. {
  90.     lyxerr.debug("Setting buffer in BufferView");
  91.     if (_buffer)
  92.         _buffer->delUser(this);
  93.  
  94.     // Set current buffer
  95.     _buffer = b;
  96.  
  97.     if (bufferlist.getState() == BufferList::CLOSING) return;
  98.     
  99.     // Nuke old image
  100.     if (screen)
  101.         delete screen;
  102.     screen = 0;
  103.  
  104.     // If we are closing the buffer, use the first buffer as current
  105.     if (!_buffer) {
  106.         _buffer = bufferlist.first();
  107.     }
  108.  
  109.     if (_buffer) {
  110.         lyxerr.debug(LString("  Buffer addr: ") + PTR_AS_INT(_buffer));
  111.         _buffer->addUser(this);
  112.         _owner->getMenus()->showMenus();
  113.         // If we don't have a text object for this, we make one
  114.         if (_buffer->text == 0)
  115.             resizeCurrentBuffer();
  116.         else {
  117.             updateScreen();
  118.             updateScrollbar();
  119.         }
  120.         _owner->updateLayoutChoice();
  121.         screen->first = screen->TopCursorVisible();
  122.         redraw();
  123.         updateAllVisibleBufferRelatedPopups();
  124.     } else {
  125.         lyxerr.debug("  No Buffer!");
  126.         _owner->getMenus()->hideMenus();
  127.         //workAreaExpose();
  128.         updateScrollbar();
  129.         fl_redraw_object(work_area);
  130.     }
  131.     _owner->getMiniBuffer()->Init();
  132.     _owner->updateWindowTitle();
  133. }
  134.  
  135.  
  136. void BufferView::updateScreen()
  137. {
  138.     // Regenerated the screen.
  139.     if (screen)
  140.         delete screen;
  141.     screen = new LyXScreen(FL_ObjWin(work_area),
  142.                    work_area->w,
  143.                    work_area->h,
  144.                    work_area->x,
  145.                    work_area->y,
  146.                    _buffer->text);
  147. }
  148.  
  149.  
  150. void BufferView::resize()
  151. {
  152.     // This will resize the buffer. (Asger)
  153.     if (_buffer)
  154.         resizeCurrentBuffer();
  155. }
  156.  
  157.  
  158. void BufferView::redraw()
  159. {
  160.     lyxerr.debug("BufferView::redraw()");
  161.     fl_redraw_object(work_area);
  162.     fl_redraw_object(scrollbar);
  163.     fl_redraw_object(button_down);
  164.     fl_redraw_object(button_up);
  165. }
  166.  
  167.  
  168. void BufferView::fitCursor()
  169. {
  170.     if (screen) screen->FitCursor();
  171. }
  172.  
  173.  
  174. void BufferView::update()
  175. {
  176.     if (screen) screen->Update();
  177. }
  178.  
  179.  
  180. void BufferView::updateScrollbar()
  181. {
  182.     /* If the text is smaller than the working area, the scrollbar
  183.      * maximum must be the working area height. No scrolling will 
  184.      * be possible */
  185.  
  186.     if (!_buffer) {
  187.         fl_set_slider_value(scrollbar, 0);
  188.         fl_set_slider_size(scrollbar, scrollbar->h);
  189.         return;
  190.     }
  191.     
  192.     static long max2 = 0;
  193.     static long height2 = 0;
  194.  
  195.     long cbth = 0;
  196.     long cbsf = 0;
  197.  
  198.     if (_buffer->text)
  199.         cbth = _buffer->text->height;
  200.     if (screen)
  201.         cbsf = screen->first;
  202.  
  203.     // check if anything has changed.
  204.     if (max2 == cbth &&
  205.         height2 == work_area->h &&
  206.         current_scrollbar_value == cbsf)
  207.         return;          // no
  208.     
  209.     max2 = cbth;
  210.     height2 = work_area->h;
  211.     current_scrollbar_value = cbsf;
  212.  
  213.     if (cbth <= height2) { // text is smaller than screen
  214.         fl_set_slider_size(scrollbar, scrollbar->h);
  215.         return;
  216.     }
  217.     
  218.     long maximum_height = work_area->h * 3/4 + cbth;
  219.     long value = cbsf;
  220.  
  221.     /* set the scrollbar */
  222.     double hfloat = work_area->h;
  223.     double maxfloat = maximum_height;
  224.    
  225.     fl_set_slider_value(scrollbar, value);
  226.     fl_set_slider_bounds(scrollbar, 0,
  227.                  maximum_height - work_area->h);
  228.     double lineh = _buffer->text->DefaultHeight();
  229.     fl_set_slider_increment(scrollbar,work_area->h-lineh,lineh);
  230.     if (maxfloat>0){
  231.         if ((hfloat/maxfloat) * (float) height2 < 3)
  232.             fl_set_slider_size(scrollbar,
  233.                        3/(float)height2);
  234.         else
  235.             fl_set_slider_size(scrollbar,
  236.                        hfloat/maxfloat);
  237.     } else
  238.         fl_set_slider_size(scrollbar, hfloat);
  239.     fl_set_slider_precision(scrollbar, 0);
  240. }
  241.  
  242.  
  243. void BufferView::redoCurrentBuffer()
  244. {
  245.     lyxerr.debug("BufferView::redoCurrentBuffer");
  246.     if (_buffer && _buffer->text) {
  247.         resize();
  248.         _owner->updateLayoutChoice();
  249.     }
  250. }
  251.  
  252.  
  253. int BufferView::resizeCurrentBuffer()
  254. {
  255.     lyxerr.debug("resizeCurrentBuffer");
  256.     
  257.     LyXParagraph *par = 0;
  258.     LyXParagraph *selstartpar = 0;
  259.     LyXParagraph *selendpar = 0;
  260.     int pos = 0;
  261.     int selstartpos = 0;
  262.     int selendpos = 0;
  263.     int selection = 0;
  264.     int mark_set = 0;
  265.  
  266.     ProhibitInput();
  267.  
  268.     _owner->getMiniBuffer()->Set(_("Formatting document..."));   
  269.  
  270.     if (_buffer->text) {
  271.         par = _buffer->text->cursor.par;
  272.         pos = _buffer->text->cursor.pos;
  273.         selstartpar = _buffer->text->sel_start_cursor.par;
  274.         selstartpos = _buffer->text->sel_start_cursor.pos;
  275.         selendpar = _buffer->text->sel_end_cursor.par;
  276.         selendpos = _buffer->text->sel_end_cursor.pos;
  277.         selection = _buffer->text->selection;
  278.         mark_set = _buffer->text->mark_set;
  279.         delete _buffer->text;
  280.     }
  281.     _buffer->text = new LyXText(work_area->w, _buffer);
  282.  
  283.     updateScreen();
  284.    
  285.     if (par) {
  286.         _buffer->text->selection = true;
  287.         /* at this point just
  288.          * to avoid the Delete-
  289.          * Empty-Paragraph
  290.          * Mechanism when
  291.          * setting the cursor */
  292.         _buffer->text->mark_set = mark_set;
  293.         if (selection) {
  294.             _buffer->text->SetCursor(selstartpar,
  295.                                    selstartpos);
  296.             _buffer->text->sel_cursor = _buffer->text->cursor;
  297.             _buffer->text->SetCursor(selendpar,
  298.                                    selendpos);
  299.             _buffer->text->SetSelection();
  300.             _buffer->text->SetCursor(par, pos);
  301.         } else {
  302.             _buffer->text->SetCursor(par, pos);
  303.             _buffer->text->sel_cursor = _buffer->text->cursor;
  304.             _buffer->text->selection = false;
  305.         }
  306.     }
  307.     screen->first = screen->TopCursorVisible(); /* this will scroll the
  308.                              * screen such that the
  309.                              * cursor becomes
  310.                              * visible */ 
  311.     updateScrollbar();
  312.     redraw();
  313.     _owner->getMiniBuffer()->Init();
  314.     AllowInput();
  315.  
  316.     // Now if the title form still exist kill it
  317.     TimerCB(0,0);
  318.  
  319.     return 0;
  320. }
  321.  
  322.  
  323. void BufferView::gotoError()
  324. {
  325.     if (!screen)
  326.         return;
  327.    
  328.     screen->HideCursor();
  329.     BeforeChange();
  330.     _buffer->update(-2);
  331.     LyXCursor tmp;
  332.    
  333.     if (!_buffer->text->GotoNextError()) {
  334.         if (_buffer->text->cursor.pos 
  335.             || _buffer->text->cursor.par !=
  336.             _buffer->text->FirstParagraph()) {
  337.             tmp = _buffer->text->cursor;
  338.             _buffer->text->cursor.par =
  339.                 _buffer->text->FirstParagraph();
  340.             _buffer->text->cursor.pos = 0;
  341.             if (!_buffer->text->GotoNextError()) {
  342.                 _buffer->text->cursor = tmp;
  343.                 _owner->getMiniBuffer()->Set(_("No more errors"));
  344.                 LyXBell();
  345.             }
  346.         } else {
  347.             _owner->getMiniBuffer()->Set(_("No more errors"));
  348.             LyXBell();
  349.         }
  350.     }
  351.     _buffer->update(0);
  352.     _buffer->text->sel_cursor =
  353.         _buffer->text->cursor;
  354. }
  355.  
  356.  
  357. void BufferView::create_view(int xpos, int ypos, int width, int height)
  358. {
  359.     FL_OBJECT *obj;
  360.     const int bw = abs(fl_get_border_width());
  361.  
  362.     // a hack for the figinsets (Matthias)
  363.     // This one first, then it will probably be invisible. (Lgb)
  364.     ::figinset_canvas = figinset_canvas = obj =
  365.         fl_add_canvas(FL_NORMAL_CANVAS,
  366.                   xpos + 1,
  367.                   ypos + 1,1,1,"");
  368.     fl_set_object_boxtype(obj,FL_NO_BOX);
  369.     fl_set_object_resize(obj, FL_RESIZE_ALL);
  370.     fl_set_object_gravity(obj, NorthWestGravity, NorthWestGravity);
  371.  
  372.     // a box
  373.     obj = fl_add_box(FL_BORDER_BOX, xpos, ypos,
  374.              width - 15,
  375.              height,"");
  376.     fl_set_object_resize(obj, FL_RESIZE_ALL);
  377.     fl_set_object_gravity(obj, NorthWestGravity, SouthEastGravity);
  378.  
  379.     // the free object
  380.     work_area = obj = fl_add_free(FL_INPUT_FREE,
  381.                       xpos +bw, ypos+bw,
  382.                       width-15-2*bw /* scrollbarwidth */,
  383.                       height-2*bw,"",
  384.                       work_area_handler);
  385.     obj->wantkey = FL_KEY_TAB;
  386.     obj->u_vdata = (void*) this; /* This is how we pass the BufferView
  387.                        to the work_area_handler. */
  388.     fl_set_object_boxtype(obj,FL_DOWN_BOX);
  389.     fl_set_object_resize(obj, FL_RESIZE_ALL);
  390.     fl_set_object_gravity(obj, NorthWestGravity, SouthEastGravity);
  391.  
  392.     //
  393.     // THE SCROLLBAR
  394.     //
  395.  
  396.     // up - scrollbar button
  397.     fl_set_border_width(-1);
  398.  
  399.     button_up = obj = fl_add_pixmapbutton(FL_TOUCH_BUTTON,
  400.                           width-15+4*bw,
  401.                           ypos,
  402.                           15,15,"");
  403.     fl_set_object_boxtype(obj,FL_UP_BOX);
  404.     fl_set_object_color(obj,FL_MCOL,FL_BLUE);
  405.     fl_set_object_resize(obj, FL_RESIZE_ALL);
  406.     fl_set_object_gravity(obj,NorthEastGravity, NorthEastGravity);
  407.     fl_set_object_callback(obj,UpCB,(long)this);
  408.     fl_set_pixmapbutton_data(obj, up_xpm);
  409.  
  410.     // Remove the blue feedback rectangle
  411.     fl_set_pixmapbutton_focus_outline(obj,0);
  412.  
  413.     // the scrollbar slider
  414.     fl_set_border_width(-bw);
  415.     scrollbar = obj = fl_add_slider(FL_VERT_SLIDER,
  416.                     width-15+4*bw,
  417.                     ypos + 15,
  418.                     15,height-30,"");
  419.     fl_set_object_color(obj,FL_COL1,FL_MCOL);
  420.     fl_set_object_boxtype(obj, FL_UP_BOX);
  421.     fl_set_object_resize(obj, FL_RESIZE_ALL);
  422.     fl_set_object_gravity(obj, NorthEastGravity, SouthEastGravity);
  423.     fl_set_object_callback(obj,ScrollCB,(long)this);
  424.     
  425.     // down - scrollbar button
  426.     fl_set_border_width(-1);
  427.  
  428.     button_down = obj = fl_add_pixmapbutton(FL_TOUCH_BUTTON,
  429.                               width-15+4*bw,
  430.                               ypos + height-15,
  431.                               15,15,"");
  432.     fl_set_object_boxtype(obj,FL_UP_BOX);
  433.     fl_set_object_color(obj,FL_MCOL,FL_BLUE);
  434.     fl_set_object_resize(obj, FL_RESIZE_ALL);
  435.     fl_set_object_gravity(obj, SouthEastGravity, SouthEastGravity);
  436.     fl_set_object_callback(obj,DownCB,(long)this);
  437.     fl_set_pixmapbutton_data(obj, down_xpm);
  438.     fl_set_border_width(-bw);
  439.  
  440.     // Remove the blue feedback rectangle
  441.     fl_set_pixmapbutton_focus_outline(obj,0);
  442.  
  443.     //
  444.     // TIMERS
  445.     //
  446.     
  447.     // timer_cursor
  448.     timer_cursor = obj = fl_add_timer(FL_HIDDEN_TIMER,
  449.                       0,0,0,0,"Timer");
  450.     fl_set_object_callback(obj,CursorToggleCB,0);
  451.     obj->u_vdata = (void*) this;
  452. }
  453.  
  454.  
  455. // Callback for scrollbar up button
  456. void BufferView::UpCB(FL_OBJECT *ob, long buf)
  457. {
  458.     BufferView *view = (BufferView*) buf;
  459.     
  460.     if (view->_buffer == 0) return;
  461.  
  462.     const XEvent*ev2;
  463.     static long time = 0;
  464.     ev2 = fl_last_event();
  465.     if (ev2->type == ButtonPress || ev2->type == ButtonRelease) 
  466.         time = 0;
  467.     int button = fl_get_button_numb(ob);
  468.     switch (button) {
  469.     case 3:
  470.         view->ScrollUpOnePage(time++); break;
  471.     case 2:
  472.         view->ScrollDownOnePage(time++); break;
  473.     default:
  474.         view->ScrollUp(time++); break;
  475.     }
  476. }
  477.  
  478.  
  479. static
  480. void waitForX()
  481. {
  482.     static Window w = 0;
  483.     static Atom a = 0;
  484.     if (!a)
  485.         a = XInternAtom(fl_display, "WAIT_FOR_X", False);
  486.     if (w == 0) {
  487.         int mask;
  488.         XSetWindowAttributes attr;
  489.         mask = CWOverrideRedirect;
  490.         attr.override_redirect = 1;
  491.         w = XCreateWindow(fl_display, fl_root,
  492.                   0, 0, 1, 1, 0, CopyFromParent,
  493.                   InputOnly, CopyFromParent, mask, &attr);
  494.         XSelectInput(fl_display, w, 
  495.                  PropertyChangeMask);
  496.         XMapWindow(fl_display, w);
  497.     }
  498.     static XEvent ev;
  499.     XChangeProperty(fl_display, w, a, a, 8,
  500.             PropModeAppend, (unsigned char *)"", 0);
  501.     XWindowEvent(fl_display, w, PropertyChangeMask, &ev);
  502. }
  503.  
  504.  
  505. // Callback for scrollbar slider
  506. void BufferView::ScrollCB(FL_OBJECT *ob, long buf)
  507. {
  508.     BufferView *view = (BufferView*) buf;
  509.     extern bool cursor_follows_scrollbar;
  510.     
  511.     if (view->_buffer == 0) return;
  512.  
  513.     view->current_scrollbar_value = (long)fl_get_slider_value(ob);
  514.     if (view->current_scrollbar_value < 0)
  515.         view->current_scrollbar_value = 0;
  516.    
  517.     if (!view->screen)
  518.         return;
  519.  
  520.     view->screen->Draw(view->current_scrollbar_value);
  521.  
  522.     if (cursor_follows_scrollbar) {
  523.         LyXText * vbt = view->_buffer->text;
  524.         int height = vbt->DefaultHeight();
  525.         
  526.         if (vbt->cursor.y < view->screen->first + height) {
  527.             vbt->SetCursorFromCoordinates(0,
  528.                               view->screen->first +
  529.                               height);
  530.         }
  531.         else if (vbt->cursor.y >
  532.              view->screen->first + view->work_area->h - height) {
  533.             vbt->SetCursorFromCoordinates(0,
  534.                               view->screen->first +
  535.                               view->work_area->h  -
  536.                               height);
  537.         }
  538.     }
  539.     waitForX();
  540. }
  541.  
  542.  
  543. // Callback for scrollbar down button
  544. void BufferView::DownCB(FL_OBJECT *ob, long buf)
  545. {
  546.     BufferView *view = (BufferView*) buf;
  547.  
  548.     if (view->_buffer == 0) return;
  549.     
  550.     const XEvent*ev2;
  551.     static long time = 0;
  552.     ev2 = fl_last_event();
  553.     if (ev2->type == ButtonPress || ev2->type == ButtonRelease) 
  554.         time = 0;
  555.     int button = fl_get_button_numb(ob);
  556.     switch (button) {
  557.     case 2:
  558.         view->ScrollUpOnePage(time++); break;
  559.     case 3:
  560.         view->ScrollDownOnePage(time++); break;
  561.     default:
  562.         view->ScrollDown(time++); break;
  563.     }
  564. }
  565.  
  566.  
  567. int BufferView::ScrollUp(long time)
  568. {
  569.     if (_buffer == 0) return 0;
  570.     if (!screen)
  571.         return 0;
  572.    
  573.     double value= fl_get_slider_value(scrollbar);
  574.    
  575.     if (value == 0)
  576.         return 0;
  577.    
  578.     float add_value =  (_buffer->text->DefaultHeight()
  579.                 + (float)(time) * (float)(time) * 0.125);
  580.    
  581.     if (add_value > work_area->h)
  582.         add_value = (float) (work_area->h -
  583.                      _buffer->text->DefaultHeight());
  584.    
  585.     value -= add_value;
  586.  
  587.     if (value < 0)
  588.         value = 0;
  589.    
  590.     fl_set_slider_value(scrollbar, value);
  591.    
  592.     ScrollCB(scrollbar,(long)this); 
  593.     return 0;
  594. }
  595.  
  596.  
  597. int BufferView::ScrollDown(long time)
  598. {
  599.     if (_buffer == 0) return 0;
  600.     if (!screen)
  601.         return 0;
  602.    
  603.     double value= fl_get_slider_value(scrollbar);
  604.     double min, max;
  605.     fl_get_slider_bounds(scrollbar, &min, &max);
  606.  
  607.     if (value == max)
  608.         return 0;
  609.    
  610.     float add_value =  (_buffer->text->DefaultHeight()
  611.                 + (float)(time) * (float)(time) * 0.125);
  612.    
  613.     if (add_value > work_area->h)
  614.         add_value = (float) (work_area->h -
  615.                      _buffer->text->DefaultHeight());
  616.    
  617.     value += add_value;
  618.    
  619.     if (value > max)
  620.         value = max;
  621.    
  622.     fl_set_slider_value(scrollbar, value);
  623.    
  624.     ScrollCB(scrollbar,(long)this); 
  625.     return 0;
  626. }
  627.  
  628.  
  629. void BufferView::ScrollUpOnePage(long /*time*/)
  630. {
  631.     if (_buffer == 0) return;
  632.     if (!screen)
  633.         return;
  634.    
  635.     long y = screen->first;
  636.  
  637.     if (!y) return;
  638.    
  639.     Row* row = _buffer->text->GetRowNearY(y);
  640.     y = y - work_area->h + row->height;
  641.     
  642.     fl_set_slider_value(scrollbar, y);
  643.    
  644.     ScrollCB(scrollbar,(long)this); 
  645. }
  646.  
  647.  
  648. void BufferView::ScrollDownOnePage(long /*time*/)
  649. {
  650.     if (_buffer == 0) return;
  651.     if (!screen)
  652.         return;
  653.    
  654.     double min, max;
  655.     fl_get_slider_bounds(scrollbar, &min, &max);
  656.     long y = screen->first;
  657.    
  658.     if (y > _buffer->text->height - work_area->h)
  659.         return;
  660.    
  661.     y += work_area->h;
  662.     _buffer->text->GetRowNearY(y);
  663.     
  664.     fl_set_slider_value(scrollbar, y);
  665.    
  666.     ScrollCB(scrollbar,(long)this); 
  667. }
  668.  
  669.  
  670. int BufferView::work_area_handler(FL_OBJECT * ob, int event,
  671.                   FL_Coord, FL_Coord ,
  672.                   int /*key*/, void *xev)
  673. {
  674.     static int x_old = -1;
  675.     static int y_old = -1;
  676.     static long scrollbar_value_old = -1;
  677.     
  678.     XEvent* ev = (XEvent*) xev;
  679.     BufferView *view = (BufferView*) ob->u_vdata;
  680.  
  681.     // If we don't have a view yet; return
  682.     if (!view || quitting) return 0;
  683.  
  684.     switch (event){   
  685.     case FL_DRAW:
  686.         view->workAreaExpose(); 
  687.         break;
  688.     case FL_PUSH:
  689.         view->WorkAreaButtonPress(ob, 0,0,0,ev,0);
  690.         break; 
  691.     case FL_RELEASE:
  692.         view->WorkAreaButtonRelease(ob, 0,0,0,ev,0);
  693.         break;
  694.     case FL_MOUSE:
  695.         if (ev->xmotion.x != x_old || 
  696.             ev->xmotion.y != y_old ||
  697.             view->current_scrollbar_value != scrollbar_value_old){
  698.             x_old = ev->xmotion.x;
  699.             y_old = ev->xmotion.y;
  700.             scrollbar_value_old = view->current_scrollbar_value;
  701.             view->WorkAreaMotionNotify(ob, 0,0,0,ev,0);
  702.         }        break;
  703.     // Done by the raw callback:
  704.     //  case FL_KEYBOARD: WorkAreaKeyPress(ob, 0,0,0,ev,0); break;
  705.     case FL_FOCUS:
  706.         if (!view->_owner->getMiniBuffer()->shows_no_match)
  707.             view->_owner->getMiniBuffer()->Init();
  708.         view->_owner->getMiniBuffer()->shows_no_match = false;
  709.         view->work_area_focus = true;
  710.         fl_set_timer(view->timer_cursor, 0.4);
  711.         break;
  712.     case FL_UNFOCUS:
  713.         view->_owner->getMiniBuffer()->ExecCommand();
  714.         view->work_area_focus = false;
  715.         break;
  716.     case FL_ENTER:
  717.         SetXtermCursor(view->_owner->getForm()->window);
  718.         // reset the timer
  719.         view->lyx_focus = true;
  720.         fl_set_timer(view->timer_cursor, 0.4);
  721.         break;
  722.     case FL_LEAVE: 
  723.         if (!input_prohibited)
  724.             XUndefineCursor(fl_display,
  725.                     view->_owner->getForm()->window);
  726.         view->lyx_focus = false; // this is not an ablsolute truth
  727.         // but if it is not true, it will be changed within a blink
  728.         // of an eye. ... Not good enough... use regulare timeperiod
  729.         //fl_set_timer(view->timer_cursor, 0.01); // 0.1 sec blink
  730.         fl_set_timer(view->timer_cursor, 0.4); // 0.4 sec blink
  731.         break;
  732.     case FL_DBLCLICK: 
  733.         // select a word 
  734.         if (view->_buffer &&
  735.             !view->_buffer->the_locking_inset) {
  736.             if (view->screen &&
  737.                 ev->xbutton.button == 1) {
  738.                 view->screen->HideCursor();
  739.                 view->screen->
  740.                     ToggleSelection(); 
  741.                 view->_buffer->text->SelectWord();
  742.                 view->screen->
  743.                     ToggleSelection(false);
  744.                 view->_buffer->update(0); /* this will fit the cursor on the screen
  745.                         * if necessary */ 
  746.             }
  747.         }
  748.         break;
  749.     case FL_TRPLCLICK:
  750.         // select a line
  751.         if (view->_buffer &&
  752.             view->screen && ev->xbutton.button == 1){
  753.             view->screen->HideCursor(); 
  754.             view->screen->ToggleSelection(); 
  755.             view->_buffer->text->CursorHome();
  756.             view->_buffer->text->sel_cursor =
  757.                 view->_buffer->text->cursor;
  758.             view->_buffer->text->CursorEnd();
  759.             view->_buffer->text->SetSelection();
  760.             view->screen->ToggleSelection(false); 
  761.             view->_buffer->update(0); /* this will fit the cursor on the screen
  762.                     * if necessary */ 
  763.         }
  764.         break;
  765.     case FL_OTHER:
  766.         view->WorkAreaSelectionNotify(ob,
  767.                           view->_owner->getForm()->window,
  768.                           0,0,ev,0); 
  769.         break;
  770.     }
  771.   
  772.     return 1;
  773. }
  774.  
  775.  
  776. int BufferView::WorkAreaMotionNotify(FL_OBJECT *ob, Window,
  777.                      int /*w*/, int /*h*/,
  778.                      XEvent *ev, void */*d*/)
  779. {
  780.     if (_buffer == 0) return 0;
  781.     if (!screen)
  782.         return 0;
  783.    
  784.     /* check for inset locking */
  785.     if (_buffer->the_locking_inset){
  786.         LyXCursor cursor = _buffer->text->cursor;
  787.         _buffer->the_locking_inset->
  788.             InsetMotionNotify(ev->xbutton.x - ob->x - cursor.x,
  789.                       ev->xbutton.y - ob->y -
  790.                       (cursor.y),
  791.                       ev->xbutton.state);
  792.         return 0;
  793.     }
  794.    
  795.     /* only use motion with button 1 */
  796.     if (!ev->xmotion.state & Button1MotionMask)
  797.         return 0; 
  798.     
  799.    
  800.     /* the selection possible is needed, that only motion events are 
  801.      * used, where the bottom press event was on the drawing area too */
  802.     if (selection_possible) {
  803.       
  804.         screen->HideCursor();
  805.  
  806.         _buffer->text->
  807.             SetCursorFromCoordinates(ev->xbutton.x - ob->x,
  808.                          ev->xbutton.y - ob->y +
  809.                          screen->first);
  810.       
  811.         if (!_buffer->text->selection)
  812.             _buffer->update(-3);       /* maybe an empty line was deleted  */
  813.       
  814.         _buffer->text->SetSelection();
  815.         screen->ToggleToggle();
  816.         if (screen->FitCursor())
  817.             updateScrollbar(); 
  818.         screen->ShowCursor();
  819.     } 
  820.     return 0;
  821. }
  822.  
  823.  
  824. int BufferView::WorkAreaSelectionNotify(FL_OBJECT *, Window win,
  825.                 int /*w*/, int /*h*/, XEvent *event, void */*d*/)
  826. {
  827.     if (_buffer == 0) return 0;
  828.     if (event->type != SelectionNotify)
  829.         return 0;
  830.  
  831.     Atom tmpatom;
  832.     unsigned long ul1;
  833.     unsigned long ul2;
  834.     unsigned char* uc = 0;
  835.     int tmpint;
  836.     screen->HideCursor();
  837.     BeforeChange();
  838.     if (event->xselection.type == XA_STRING
  839.         && event->xselection.property) {
  840.     
  841.         if (XGetWindowProperty(
  842.             fl_display            /* display */,
  843.             win /* w */,
  844.             event->xselection.property        /* property */,
  845.             0                /* long_offset */,
  846.             0                /* long_length */,
  847.             false                /* delete */,
  848.             XA_STRING                /* req_type */,
  849.             &tmpatom               /* actual_type_return */,
  850.             &tmpint                /* actual_format_return */,
  851.             &ul1      /* nitems_return */,
  852.             &ul2      /* bytes_after_return */,
  853.             &uc     /* prop_return */
  854.             ) != Success) {
  855.             return 0;
  856.         }
  857.         XFlush(fl_display);
  858.  
  859.         if (uc){
  860.             free(uc);
  861.             uc = 0;
  862.         }
  863.  
  864.         if (XGetWindowProperty(
  865.             fl_display           /* display */,
  866.             win              /* w */,
  867.             event->xselection.property           /* property */,
  868.             0                /* long_offset */,
  869.             ul2/4+1                /* long_length */,
  870.             True                /* delete */,
  871.             XA_STRING                /* req_type */,
  872.             &tmpatom               /* actual_type_return */,
  873.             &tmpint                /* actual_format_return */,
  874.             &ul1      /* nitems_return */,
  875.             &ul2      /* bytes_after_return */,
  876.             &uc     /* prop_return */
  877.             ) != Success) {
  878.             return 0;
  879.         }
  880.         XFlush(fl_display);
  881.         
  882.         if (uc){
  883.             if (!ascii_type)
  884.                 _buffer->text->
  885.                     InsertStringA((char*)uc);
  886.             else
  887.                 _buffer->text->
  888.                     InsertStringB((char*)uc);
  889.             free(uc);
  890.             uc = 0;
  891.         }
  892.     
  893.         _buffer->update(1);
  894.     }
  895.     return 0;
  896. }
  897.  
  898.  
  899. extern int bibitemMaxWidth(const class LyXFont &);
  900.  
  901. // Single-click on work area
  902. int BufferView::WorkAreaButtonPress(FL_OBJECT *ob, Window,
  903.             int /*w*/, int /*h*/, XEvent *ev, void */*d*/)
  904. {
  905.     if (_buffer == 0) return 0;
  906.     if (!screen)
  907.         return 0 ;
  908.  
  909.     int x = ev->xbutton.x - ob->x;
  910.     int y = ev->xbutton.y - ob->y;
  911.  
  912.     if (_buffer->the_locking_inset){
  913.         /* we are in inset locking mode. */
  914.  
  915.         /* check whether the inset was hit. If not reset mode,
  916.            otherwise give the event to the inset */
  917.         if (checkInsetHit(x, y)){ 
  918.             _buffer->the_locking_inset->
  919.                 InsetButtonPress(x, y, ev->xbutton.button);
  920.             return 0;
  921.         }
  922.         else {
  923.             UnlockInset(_buffer->the_locking_inset);
  924.         }
  925.     }
  926.    
  927.     selection_possible = true;
  928.     screen->HideCursor();
  929.         
  930.     // Right button mouse click on a table
  931.     if ((ev->xbutton.button == 3) &&
  932.         (_buffer->text->cursor.par->table ||
  933.              _buffer->text->MouseHitInTable(x, y+screen->first))) {
  934.             // set the cursor to the press-position
  935.             _buffer->text->SetCursorFromCoordinates(ev->xbutton.x - ob->x,
  936.                                                     ev->xbutton.y - ob->y +
  937.                                                     screen->first);
  938.         bool doit = true;
  939.         // only show the table popup if the hit is on the table, too
  940.         if (!_buffer->text->
  941.             HitInTable(_buffer->text->cursor.row,
  942.                    ev->xbutton.x - ob->x))
  943.             doit = false; 
  944.      
  945.         // hit above or below the table ?
  946.         if (doit){
  947.             long y_tmp = ev->xbutton.y - ob->y +
  948.                 screen->first;
  949.             Row*  row =  _buffer->text->GetRowNearY(y_tmp);
  950.             if (row->par != _buffer->text->cursor.par)
  951.                 doit = true;
  952.         }
  953.      
  954.         if (doit){
  955.             if (!_buffer->text->selection){
  956.                 screen->ToggleSelection();
  957.                 _buffer->text->ClearSelection();
  958.                 _buffer->text->FullRebreak();
  959.                 screen->Update();
  960.                 updateScrollbar();
  961.             }
  962.             // popup table popup when on a table.
  963.             // this is obviously temporary, since we should be
  964.             // able to 
  965.             // popup various context-sensitive-menus with the
  966.             // the right mouse. So this should be done more
  967.             // general in the future. Matthias.
  968.             selection_possible = false;
  969.                         _owner->getLyXFunc()->Dispatch(LFUN_LAYOUT_TABLE,
  970.                                "true");
  971.             return 0;
  972.         }
  973.     }
  974.  
  975.     int screen_first = screen->first;
  976.  
  977.     // Middle button press pastes if we have a selection
  978.     bool paste_internally = false;
  979.     if (ev->xbutton.button == 2 && !_buffer->the_locking_inset
  980.         && _buffer->text->selection){
  981.         _owner->getLyXFunc()->Dispatch(LFUN_COPY);
  982.         paste_internally = true;
  983.     }
  984.  
  985.     /* clear the selection */ 
  986.     screen->ToggleSelection();
  987.     _buffer->text->ClearSelection();
  988.     _buffer->text->FullRebreak();
  989.     screen->Update();
  990.     updateScrollbar();
  991.  
  992.     // Right click on a footnote flag opens float menu
  993.     if ((ev->xbutton.button == 3) &&
  994.             _buffer->text->cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
  995.         selection_possible = false;
  996.         lyxerr.print("LyX: Sorry not implemented yet.");
  997.         return 0;
  998.     }
  999.  
  1000.     if (ev->xbutton.button == 3){
  1001.         selection_possible = false;
  1002.         return 0;
  1003.     }
  1004.  
  1005.    
  1006.     _buffer->text->SetCursorFromCoordinates(ev->xbutton.x - ob->x,
  1007.                                                 ev->xbutton.y - ob->y +
  1008.                                                 screen_first);
  1009.     _buffer->text->FinishUndo();
  1010.     _buffer->text->sel_cursor = _buffer->text->cursor;
  1011.     _buffer->text->cursor.x_fix = _buffer->text->cursor.x;
  1012.    
  1013.     /* Single left click */
  1014.     if (ev->xbutton.button == 1){
  1015.         int x2 = ev->xbutton.x - ob->x;
  1016.         int y2 = ev->xbutton.y - ob->y;
  1017.         // Did we hit an inset?
  1018.         if (checkInsetHit(x2, y2)){
  1019.             if (_buffer->text->cursor.par->
  1020.                 GetInset(_buffer->text->cursor.pos)->
  1021.                 Editable() == 2) 
  1022.                 {
  1023.                     // Highly editable inset, like math
  1024.                     selection_possible = false;
  1025.                     _owner->updateLayoutChoice();
  1026.                     _owner->getMiniBuffer()->
  1027.                                                 Set(_buffer->text->cursor.par->
  1028.                                                     GetInset(_buffer->text->cursor.pos)->
  1029.                                                     EditMessage());
  1030.                     _buffer->text->cursor.par->
  1031.                         GetInset(_buffer->text->cursor.pos)->
  1032.                         Edit(x2, y2);
  1033.                     return 0;
  1034.                 } else {
  1035.                     // Other inset like error, notes
  1036.                     // and figures
  1037.                     selection_possible = false;
  1038. #ifdef WITH_WARNINGS
  1039. #warning fix this proper in 0.13
  1040. #endif
  1041.                     // Following a ref shouldn't issue
  1042.                     // a push on the undo-stack
  1043.                     // anylonger, now that we have
  1044.                     // keybindings for following
  1045.                     // references and returning from
  1046.                     // references.  IMHO though, it
  1047.                     // should be the inset's own business
  1048.                     // to push or not push on the undo
  1049.                     // stack. They don't *have* to
  1050.                     // alter the document...
  1051.                     // (Joacim)
  1052.                     // ...or maybe the SetCursorParUndo()
  1053.                     // below isn't necessary at all anylonger?
  1054.                     if (!_buffer->text->cursor.par->
  1055.                          GetInset(_buffer->text->cursor.pos)->
  1056.                      LyxCode() == Inset::REF_CODE)
  1057.                         _buffer->text->
  1058.                             SetCursorParUndo();
  1059.  
  1060.                     _owner->getMiniBuffer()->
  1061.                         Set(_buffer->
  1062.                             text->cursor.par->
  1063.                             GetInset(_buffer->
  1064.                                  text->
  1065.                                  cursor.pos)->
  1066.                             EditMessage());
  1067.                     _buffer->
  1068.                         text->cursor.par->
  1069.                         GetInset(_buffer->
  1070.                              text->cursor.pos)->
  1071.                         Edit(x, y);
  1072.                     return 0;
  1073.                 }
  1074.         }
  1075.  
  1076.         // check whether we want to open a float
  1077.         if (_buffer->text && 
  1078.             _buffer->text->cursor.pos <
  1079.             _buffer->text->cursor.par->Last()) {
  1080.             char c = _buffer->text->cursor.par->
  1081.                 GetChar(_buffer->text->cursor.pos);
  1082.             if (c == LYX_META_FOOTNOTE || c == LYX_META_MARGIN
  1083.                 || c == LYX_META_FIG || c == LYX_META_TAB
  1084.                 || c == LYX_META_WIDE_FIG || c == LYX_META_WIDE_TAB
  1085.                             || c == LYX_META_ALGORITHM){
  1086.                 ToggleFloat();
  1087.                 selection_possible = false;
  1088.                 return 0;
  1089.             }
  1090.         }
  1091.  
  1092.         // do we want to close a float (click on the float-label)
  1093.         if (_buffer->text->cursor.row->par->footnoteflag ==
  1094.             LyXParagraph::OPEN_FOOTNOTE
  1095.             && _buffer->text->cursor.pos == 0
  1096.             && _buffer->text->cursor.row->previous &&
  1097.             _buffer->text->cursor.row->previous->par->
  1098.             footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
  1099.             LyXFont font (LyXFont::ALL_SANE);
  1100.             font.setSize(LyXFont::SIZE_SMALL);
  1101.  
  1102.             int box_x = 20; // LYX_PAPER_MARGIN;
  1103.             box_x += font.textWidth("Mwide-figM", 10);
  1104.        
  1105.             if (ev->xbutton.x - ob->x < box_x
  1106.                 && ev->xbutton.y - ob->y +
  1107.                 screen_first
  1108.                 > _buffer->text->cursor.y -
  1109.                 _buffer->text->cursor.row->baseline
  1110.                 && ev->xbutton.y - ob->y +
  1111.                 screen_first
  1112.                 < _buffer->text->cursor.y -
  1113.                 _buffer->text->cursor.row->baseline
  1114.                 + font.maxAscent()*1.2 +
  1115.                 font.maxDescent()*1.2){
  1116.                 ToggleFloat();
  1117.                 selection_possible = false;
  1118.                 return 0;
  1119.             }
  1120.         }
  1121.         
  1122.             // Maybe we want to edit a bibitem ale970302
  1123.             if (_buffer->text->cursor.par->bibkey && 
  1124.             x2 < 20+bibitemMaxWidth(lyxstyle.TextClass(_buffer->
  1125.                         params.textclass)->defaultfont)) {
  1126.             _buffer->text->cursor.par->bibkey->Edit(0, 0);
  1127.         }
  1128.     }
  1129.    
  1130.     _owner->updateLayoutChoice();
  1131.     if (screen->FitCursor()){
  1132.         updateScrollbar();
  1133.         selection_possible = false;
  1134.     }
  1135.  
  1136.     // insert primary selection with middle mouse
  1137.     // if there is a local selection in the current buffer, insert this
  1138.     if (ev->xbutton.button == 2 && !_buffer->the_locking_inset){
  1139.         if (paste_internally)
  1140.             _owner->getLyXFunc()->Dispatch(LFUN_PASTE);
  1141.         else
  1142.             _owner->getLyXFunc()->Dispatch(LFUN_PASTESELECTION,
  1143.                                "paragraph");
  1144.         selection_possible = false;
  1145.     }
  1146.     return 0;
  1147. }
  1148.  
  1149.  
  1150. int BufferView::workAreaExpose()
  1151. {
  1152.     if (!work_area || !work_area->form->visible) 
  1153.         return 1;
  1154.  
  1155.     static int work_area_width = work_area->w;
  1156.     static int work_area_height = work_area->h;
  1157.  
  1158.     bool widthChange = work_area->w != work_area_width;
  1159.     bool heightChange = work_area->h != work_area_height;
  1160.  
  1161.     // update from work area
  1162.     work_area_width = work_area->w;
  1163.     work_area_height = work_area->h;
  1164.     if (_buffer != 0) {
  1165.         if (widthChange) {
  1166.             // All buffers need a resize
  1167.             bufferlist.resize();
  1168.         } else if (heightChange) {
  1169.             // Rebuild image of current screen
  1170.             updateScreen();
  1171.             // fitCursor() ensures we don't jump back
  1172.             // to the start of the document on vertical
  1173.             // resize
  1174.             fitCursor();
  1175.  
  1176.             // The main window size has changed, repaint most stuff
  1177.             redraw();
  1178.             // ...including the minibuffer
  1179.             _owner->getMiniBuffer()->Init();
  1180.  
  1181.         } else if (screen) screen->Redraw();
  1182.     } else {
  1183.         // Grey box when we don't have a buffer
  1184.         fl_winset(FL_ObjWin(work_area));
  1185.         fl_rectangle(1, work_area->x, work_area->y,
  1186.                  work_area->w, work_area->h, FL_GRAY63);
  1187.     }
  1188.  
  1189.     // always make sure that the scrollbar is sane.
  1190.     updateScrollbar();
  1191.     _owner->updateLayoutChoice();
  1192.     return 1;
  1193. }
  1194.  
  1195.  
  1196. // Callback for cursor timer
  1197. void BufferView::CursorToggleCB(FL_OBJECT *ob, long)
  1198. {
  1199.     BufferView *view = (BufferView*) ob->u_vdata;
  1200.     
  1201.     /* quite a nice place for asyncron Inset updating, isn't it? */
  1202.     // actually no! This is run even if no buffer exist... so (Lgb)
  1203.     if (view && !view->_buffer) {
  1204.         goto set_timer_and_return;
  1205.     }
  1206.     
  1207.     if (InsetUpdateList) 
  1208.         UpdateInsetUpdateList();
  1209.  
  1210.     if (view && !view->screen){
  1211.         goto set_timer_and_return;
  1212.     }
  1213.  
  1214.     if (view->lyx_focus && view->work_area_focus) {
  1215.         if (!view->_buffer->the_locking_inset){
  1216.             view->screen->CursorToggle();
  1217.         } else {
  1218.             view->_buffer->the_locking_inset->
  1219.                 ToggleInsetCursor();
  1220.         }
  1221.         goto set_timer_and_return;
  1222.     } else {
  1223.         // Make sure that the cursor is visible.
  1224.         if (!view->_buffer->the_locking_inset){
  1225.             view->screen->ShowCursor();
  1226.         } else {
  1227.             if (!view->_buffer->the_locking_inset->isCursorVisible())
  1228.                 view->_buffer->the_locking_inset->
  1229.                     ToggleInsetCursor();
  1230.         }
  1231.  
  1232.         // This is only run when work_area_focus or lyx_focus is false.
  1233.         Window tmpwin;
  1234.         int tmp;
  1235.         XGetInputFocus(fl_display, &tmpwin, &tmp);
  1236.         lyxerr.debug(LString("tmpwin: ") + int(tmpwin));
  1237.         lyxerr.debug(LString("window: ")
  1238.                  + int(view->_owner->getForm()->window));
  1239.         lyxerr.debug(LString("work_area_focus: ")
  1240.                  + int(view->work_area_focus));
  1241.         lyxerr.debug(LString("lyx_focus      : ")
  1242.                  + int(view->lyx_focus));
  1243.         if (tmpwin != view->_owner->getForm()->window) {
  1244.             view->lyx_focus = false;
  1245.             goto skip_timer;
  1246.         } else {
  1247.             view->lyx_focus = true;
  1248.             if (!view->work_area_focus)
  1249.                 goto skip_timer;
  1250.             else
  1251.                 goto set_timer_and_return;
  1252.         }
  1253.     }
  1254.  
  1255.   set_timer_and_return:
  1256.     fl_set_timer(ob, 0.4);
  1257.   skip_timer:
  1258.     return;
  1259. }
  1260.  
  1261.  
  1262. int BufferView::WorkAreaButtonRelease(FL_OBJECT *ob, Window ,
  1263.               int /*w*/, int /*h*/, XEvent *ev, void */*d*/)
  1264. {
  1265.     if (_buffer == 0) return 0;
  1266.  
  1267.     if (screen && _buffer->the_locking_inset){
  1268.         int x = ev->xbutton.x - ob->x;
  1269.         int y = ev->xbutton.y - ob->y;
  1270.  
  1271.         /* we are in inset locking mode. */
  1272.         /* LyX does a kind of work-area grabbing for insets.
  1273.            only a ButtonPress Event outside the inset will 
  1274.            force a InsetUnlock */
  1275.         checkInsetHit(x, y); /* just to adept the coordinates */
  1276.         _buffer->the_locking_inset->
  1277.             InsetButtonRelease(x, y, ev->xbutton.button);
  1278.         return 0;
  1279.     }
  1280.   
  1281.     selection_possible = false;
  1282.         if (_buffer->text->cursor.par->table) {
  1283.                 int cell = _buffer->text->
  1284.                         NumberOfCell(_buffer->text->cursor.par,
  1285.                                      _buffer->text->cursor.pos);
  1286.                 if (_buffer->text->cursor.par->table->IsContRow(cell) &&
  1287.                     _buffer->text->cursor.par->table->
  1288.                     CellHasContRow(_buffer->text->cursor.par->table->
  1289.                                    GetCellAbove(cell))<0) {
  1290.                         _buffer->text->CursorUp();
  1291.                 }
  1292.         }
  1293.     return 0;
  1294. }
  1295.  
  1296.  
  1297. bool BufferView::checkInsetHit(int &x, int &y)
  1298.     /* returns 1 if inset was hit. Coordinates are set relativly
  1299.        to the inset. Otherwise coordinates doesn't change their
  1300.        values and 0 is returned.
  1301.        */
  1302. {
  1303.     if (!getScreen())
  1304.         return false;
  1305.   
  1306.     int y_tmp = y + getScreen()->first;
  1307.   
  1308.     LyXCursor cursor = _buffer->text->cursor;
  1309.     if (cursor.pos 
  1310.         < cursor.par->Last() 
  1311.         && cursor.par->GetChar(cursor.pos) == LYX_META_INSET
  1312.         && cursor.par->GetInset(cursor.pos)
  1313.         && cursor.par->GetInset(cursor.pos)->Editable()) {
  1314.  
  1315.         /* check wether the inset was really hit */
  1316.         Inset* tmpinset = cursor.par->GetInset(cursor.pos);
  1317.         LyXFont font = _buffer->text->GetFont(cursor.par, cursor.pos);
  1318.         if (x > cursor.x
  1319.             && x < cursor.x + tmpinset->Width(font) 
  1320.             && y_tmp > cursor.y - tmpinset->Ascent(font)
  1321.             && y_tmp < cursor.y + tmpinset->Descent(font)){
  1322.             x = x - cursor.x;
  1323.             y = y_tmp - (cursor.y); // now the origin of an inset
  1324.             // is on the baseline (for mathed) (Matthias)
  1325.             return true;
  1326.         }
  1327.     }
  1328.     return false;
  1329. }
  1330.  
  1331.  
  1332. void BufferView::cursorPrevious()
  1333. {
  1334.     if (!currentBuffer()->text->cursor.row->previous) return;
  1335.     
  1336.     long y = getScreen()->first;
  1337.     Row* cursorrow = currentBuffer()->text->cursor.row;
  1338.     currentBuffer()->text->
  1339.       SetCursorFromCoordinates(currentBuffer()->text->
  1340.                    cursor.x_fix,
  1341.                    y);
  1342.     currentBuffer()->text->FinishUndo();
  1343.     /* this is to allow jumping over large insets */
  1344.     if ((cursorrow == currentBuffer()->text->cursor.row))
  1345.       currentBuffer()->text->CursorUp();
  1346.     
  1347.       if (currentBuffer()->text->cursor.row->height < work_area->h)
  1348.       getScreen()->Draw(currentBuffer()->text->cursor.y
  1349.                   - currentBuffer()->text->cursor.row->baseline
  1350.                   + currentBuffer()->text->cursor.row->height
  1351.                   - work_area->h +1 );
  1352. }
  1353.  
  1354.  
  1355. void BufferView::cursorNext()
  1356. {
  1357.     if (!currentBuffer()->text->cursor.row->next) return;
  1358.     
  1359.     long y = getScreen()->first;
  1360.     currentBuffer()->text->GetRowNearY(y);
  1361.     Row* cursorrow = currentBuffer()->text->cursor.row;
  1362.     currentBuffer()->text->
  1363.         SetCursorFromCoordinates(currentBuffer()->text->
  1364.                      cursor.x_fix, 
  1365.                      y + work_area->h);
  1366.     currentBuffer()->text->FinishUndo();
  1367.     /* this is to allow jumping over large insets */
  1368.     if ((cursorrow == currentBuffer()->text->cursor.row))
  1369.       currentBuffer()->text->CursorDown();
  1370.     
  1371.      if (currentBuffer()->text->cursor.row->height < work_area->h)
  1372.        getScreen()->Draw(currentBuffer()->text->cursor.y
  1373.                  - currentBuffer()->text->cursor.row->baseline);
  1374. }
  1375.  
  1376.  
  1377. bool BufferView::available() const
  1378. {
  1379.     if (_buffer && _buffer->text) return true;
  1380.     return false;
  1381. }
  1382.  
  1383.  
  1384. void BufferView::savePosition()
  1385. {
  1386.     backstack->push(currentBuffer()->getFileName(),
  1387.             currentBuffer()->text->cursor.x,
  1388.             currentBuffer()->text->cursor.y);
  1389. }
  1390.  
  1391.  
  1392. void BufferView::restorePosition()
  1393. {
  1394.     int  x, y;
  1395.     LString fname = backstack->pop(&x, &y);
  1396.     
  1397.     BeforeChange();
  1398.     Buffer *b = (bufferlist.exists(fname)) ? bufferlist.getBuffer(fname):
  1399.         bufferlist.loadLyXFile(fname); // don't ask, just load it
  1400.     setBuffer(b);
  1401.     currentBuffer()->text->SetCursorFromCoordinates(x, y);
  1402.     currentBuffer()->update(0);
  1403.  
  1404.  
  1405. void BufferView::switchBuffer(Buffer *buff)
  1406. {
  1407.     if (_buffer) {    
  1408.         _buffer->InsetSleep();
  1409.     }
  1410.  
  1411.     if (!buff) return;
  1412.     
  1413.         setBuffer(buff);
  1414.         buff->InsetWakeup();
  1415. }  
  1416.  
  1417.