X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FCursor.h;h=f5490479851b8322f7b095d0bf4ae6ce0c3d152b;hb=e11c7cb71da01989da9370c10e30af0c6a21a1f4;hp=3464a54a233885f0b991e8e4ae862ecdfe4f3d01;hpb=0e14f379f367e4d3f5f8263185e0903424a746e7;p=lyx.git diff --git a/src/Cursor.h b/src/Cursor.h index 3464a54a23..f549047985 100644 --- a/src/Cursor.h +++ b/src/Cursor.h @@ -9,6 +9,47 @@ * Full author contact details are available in file CREDITS. */ +/* +First some explanation about what a Cursor really is, from local to +global. + +* a CursorSlice indicates the position of the cursor at local level. + It contains in particular: + * idx(): the cell that contains the cursor (for Tabular or math + arrays). Always 0 for 'plain' insets + * pit(): the index of the current paragraph (only for text) + * pos(): the position in the current paragraph (or in the math + equation in mathed). + * inset(): the inset in which the cursor is. For a InsetTabular, + this is the tabular itself, not the cell inset (which is an + InsetTableCell). + +* a DocIterator indicated the position of the cursor in the document. + It knows about the current buffer (buffer() method) and contains a + vector of CursorSlices that describes the nesting of insets up to the + point of interest. Note that operator<< has been implemented, so that + one can send a DocIterator to a stream to see its value. Try it, it is + very helpful to understand the cursor layout. + * when using idx/pit/pos on a DocIterator, one gets the information + from the inner slice (this slice can be accessed as top()) + * inMathed() returns true when the cursor is in a math formula + * inTexted() returns true when the cursor is in text + * innerTextSlice() returns the deepest slice that is text (useful + when one is in a math equation and looks for the enclosing text) + +* A CursorData is a descendant of Dociterator that contains + * a second DocIterator object, the anchor, that is useful when + selecting. + * some other data that describes current selection, cursor font, etc. + + This class is mostly used only for undo and contains the Cursor + elements that are not GUI-related. In LyX 2.0, Cursor was directly + deriving from DocIterator + +* A Cursor is a descendant of CursorData that contains interesting + display-related information, in particular the BufferView that owns it. +*/ + #ifndef LCURSOR_H #define LCURSOR_H @@ -19,8 +60,6 @@ #include "mathed/MathParser_flags.h" -#include - namespace lyx { @@ -32,59 +71,54 @@ class Row; // these should go class InsetMathUnknown; -class Encoding; - -/// The cursor class describes the position of a cursor within a document. -class Cursor : public DocIterator +/** + * This class describes the position of a cursor within a document, + * but does not contain any detail about the view. It is currently + * only used to save cursor position in Undo, but culd be extended to + * handle the methods that only need this data. + **/ +class CursorData : public DocIterator { public: - /// create the cursor of a BufferView - explicit Cursor(BufferView & bv); + /// + CursorData(); + /// + explicit CursorData(Buffer * buffer); + /// + explicit CursorData(DocIterator const & dit); + /// output + friend std::ostream & operator<<(std::ostream & os, CursorData const & cur); + friend LyXErr & operator<<(LyXErr & os, CursorData const & cur); - /// returns true if we made a decision - bool getStatus(FuncRequest const & cmd, FuncStatus & flag) const; - /// dispatch from innermost inset upwards - void dispatch(FuncRequest const & cmd); - /// get the resut of the last dispatch - DispatchResult const & result() const; - /// add a new cursor slice - void push(Inset & inset); - /// add a new cursor slice, place cursor at front (move backwards) - void pushBackward(Inset & inset); - /// pop one level off the cursor - void pop(); - /// pop one slice off the cursor stack and go backwards - bool popBackward(); - /// pop one slice off the cursor stack and go forward - bool popForward(); - /// make sure we are outside of given inset - void leaveInset(Inset const & inset); + /// reset cursor bottom to the beginning of the top inset + // (sort of 'chroot' environment...) + void reset(); /// sets cursor part + /// this (intentionally) does neither touch anchor nor selection status void setCursor(DocIterator const & it); + /// set the cursor to dit normalised against the anchor, and set selection. + void setCursorSelectionTo(DocIterator dit); /// sets the cursor to the normalized selection anchor void setCursorToAnchor(); - /// - void setCurrentFont(); - // // selection // /// selection active? bool selection() const { return selection_; } - /// set selection; - void setSelection(bool sel) { selection_ = sel; } + /// set selection; this is lower level than (set|clear)Selection + void selection(bool sel) { selection_ = sel; } /// do we have a multicell selection? - bool selIsMultiCell() const + bool selIsMultiCell() const { return selection_ && selBegin().idx() != selEnd().idx(); } /// do we have a multiline selection? - bool selIsMultiLine() const + bool selIsMultiLine() const { return selection_ && selBegin().pit() != selEnd().pit(); } - /// + /// void setWordSelection(bool set) { word_selection_ = set; } /// - bool wordSelection() { return word_selection_; } + bool wordSelection() const { return word_selection_; } /// did we place the anchor? bool mark() const { return mark_; } /// did we place the anchor? @@ -95,14 +129,166 @@ public: void setSelection(DocIterator const & where, int n); /// void clearSelection(); + /// check whether selection contains specific type of inset + /// returns 0 if no selection was made + bool insetInSelection(InsetCode const & inset) const; + /// count occurences of specific inset type in the selection + /// returns 0 if no selection was made + int countInsetsInSelection(InsetCode const & inset) const; + + /// access to normalized selection anchor + CursorSlice normalAnchor() const; + /// access to real selection anchor + DocIterator const & realAnchor() const { return anchor_; } + DocIterator & realAnchor() { return anchor_; } + /// sets anchor to cursor position + void resetAnchor(); + /// access start of selection CursorSlice selBegin() const; /// access end of selection CursorSlice selEnd() const; /// access start of selection DocIterator selectionBegin() const; - /// access start of selection + /// access end of selection DocIterator selectionEnd() const; + + /// + docstring selectionAsString(bool const with_label, + bool const skipdelete = false) const; + /// get some interesting description of top position + void info(odocstream & os, bool devel_mode) const; + /// + docstring currentState(bool devel_mode) const; + + /// fix cursor in circumstances that should never happen. + /// \retval true if a fix occurred. + bool fixIfBroken(); + /// Repopulate the slices insets from bottom to top. Useful + /// for stable iterators or Undo data. + void sanitize(); + + /// + bool undoAction(); + /// + bool redoAction(); + + /// makes sure the next operation will be stored + void finishUndo() const; + /// open a new group of undo operations. Groups can be nested. + void beginUndoGroup() const; + /// end the current undo group + void endUndoGroup() const; + /// end abruptly the current group and create a new one wih the same nesting level + void splitUndoGroup() const; + + /// The general case: prepare undo for an arbitrary range. + void recordUndo(pit_type from, pit_type to) const; + /// Convenience: prepare undo for the range between 'from' and cursor. + void recordUndo(pit_type from) const; + /// Convenience: prepare undo for the single paragraph or cell + /// containing the cursor + void recordUndo(UndoKind kind = ATOMIC_UNDO) const; + /// Convenience: prepare undo for the inset containing the cursor + void recordUndoInset(Inset const * inset = nullptr) const; + /// Convenience: prepare undo for the whole buffer + void recordUndoFullBuffer() const; + /// Convenience: prepare undo for buffer parameters + void recordUndoBufferParams() const; + /// Convenience: prepare undo for the selected paragraphs or cells + void recordUndoSelection() const; + + /// hook for text input to maintain the "new born word" + void markNewWordPosition(); + /// The position of the new born word + /// As the user is entering a word without leaving it + /// the result is not empty. When not in text mode + /// and after leaving the word the result is empty. + DocIterator newWord() const { return new_word_; } + + /// are we in math mode (2), text mode (1) or unsure (0)? + int currentMode() const; + + /// Return true if the next or previous inset has confirmDeletion depending + /// on the boolean before. If there is a selection, return true if at least + /// one inset in the selection has confirmDeletion. + bool confirmDeletion(bool before = false) const; + +private: + /// validate the "new born word" position + void checkNewWordPosition(); + /// clear the "new born word" position + void clearNewWordPosition(); + + /// the anchor position + DocIterator anchor_; + /// do we have a selection? + bool selection_; + /// are we on the way to get one? + bool mark_; + /// are we in word-selection mode? This is set when double clicking. + bool word_selection_; + + /// the start of the new born word + DocIterator new_word_; + // + // math specific stuff that could be promoted to "global" later + // + + // FIXME: make them private +public: + /// The current font settings. This holds the settings for output. + Font current_font; + /// The current display font. This holds the settings of the text + /// in the workarea. + Font real_current_font; +}; + + +/// The cursor class describes the position of a cursor within a document. +class Cursor : public CursorData +{ +public: + /// create the cursor of a BufferView + explicit Cursor(BufferView & bv); + + /// add a new cursor slice + void push(Inset & inset); + /// add a new cursor slice, place cursor at front (move backwards) + void pushBackward(Inset & inset); + /// try to put cursor in inset before it in entry cell, or next one + /// if it is not empty, or exit the slice if there is no next one. + void editInsertedInset(); + + /// pop one level off the cursor + void pop(); + /// pop one slice off the cursor stack and go backwards + bool popBackward(); + /// pop one slice off the cursor stack and go forward + bool popForward(); + /// set the cursor data + void setCursorData(CursorData const & data); + + /// returns true if we made a decision + bool getStatus(FuncRequest const & cmd, FuncStatus & status) const; + /// dispatch from innermost inset upwards + void dispatch(FuncRequest const & cmd); + /// display a message + void message(docstring const & msg) const; + /// display an error message + void errorMessage(docstring const & msg) const; + /// get the result of the last dispatch + DispatchResult const & result() const; + + /// Set the cursor language from current input method language + /* Considers first exact math with the codes used in the document, + * then approximate match among the same list, and finally exact + * or partial match with the whole list of languages. + */ + void setLanguageFromInput(); + /// Set the current font of the cursor from its location. + void setCurrentFont(); + /** * Update the selection status and save permanent * selection if needed. @@ -110,37 +296,21 @@ public: * @return whether the selection status has changed */ bool selHandle(bool selecting); - /// - docstring selectionAsString(bool label) const; - /// - docstring currentState() const; - - /// auto-correct mode - bool autocorrect() const { return autocorrect_; } - /// auto-correct mode - bool & autocorrect() { return autocorrect_; } - /// are we entering a macro name? - bool macromode() const { return macromode_; } - /// are we entering a macro name? - bool & macromode() { return macromode_; } + /// returns x,y position void getPos(int & x, int & y) const; /// return logical positions between which the cursor is situated /** - * If the cursor is at the edge of a row, the position which is "over the + * If the cursor is at the edge of a row, the position which is "over the * edge" will be returned as -1. */ - void getSurroundingPos(pos_type & left_pos, pos_type & right_pos); + void getSurroundingPos(pos_type & left_pos, pos_type & right_pos) const; /// the row in the paragraph we're in Row const & textRow() const; // // common part // - /// move one step backwards - bool posBackward(); - /// move one step forward - bool posForward(); /// move visually one step to the right /** * @note: This method may move into an inset unless skip_inset == true. @@ -160,11 +330,11 @@ public: /// move visually to next/previous row /** * Assuming we were to keep moving left (right) from the current cursor - * position, place the cursor at the rightmost (leftmost) edge of the + * position, place the cursor at the rightmost (leftmost) edge of the * new row to which we would move according to visual-mode cursor movement. * This could be either the next or the previous row, depending on the - * direction in which we're moving, and whether we're in an LTR or RTL - * paragraph. + * direction in which we're moving, and whether we're in an LTR or RTL + * paragraph. * @note: The new position may even be in a new paragraph. * @note: This method will not move out of the current slice. * @return: false if not moved (no more rows to move to in given direction) @@ -173,13 +343,31 @@ public: bool posVisToNewRow(bool movingLeft); /// move to right or left extremity of the current row void posVisToRowExtremity(bool left); + /// Should interpretation of the arrow keys be reversed? + bool reverseDirectionNeeded() const; - /// insert an inset - void insert(Inset *); + /// + /// Insertion (mathed and texted) + /// /// insert a single char void insert(char_type c); /// insert a string void insert(docstring const & str); + /// insert an inset + void insert(Inset *); + /// + /// Insertion (mathed only) + /// + /// insert a math atom + void insert(MathAtom const &); + /// insert a string of atoms + void insert(MathData const &); + /// Like insert, but moves the selection inside the inset if possible + void niceInsert(MathAtom const & at); + /// return the number of inserted array items + /// FIXME: document properly + int niceInsert(docstring const & str, Parse::flags f = Parse::NORMAL, + bool enter = true); /// FIXME: rename to something sensible showing difference to x_target() /// in pixels from left of screen, set to current position if unset @@ -197,25 +385,12 @@ public: /// distance between actual and targeted position during last up/down in text int textTargetOffset() const; - /// access to normalized selection anchor - CursorSlice normalAnchor() const; - // FIXME: this can't be a const & and a const function because - // LFUN_TAB_* wants to move the real anchor. - /// access to real selection anchor - DocIterator & realAnchor(); - /// sets anchor to cursor position - void resetAnchor(); /// access to owning BufferView BufferView & bv() const; - /// get some interesting description of top position - void info(odocstream & os) const; - /// are we in math mode (2), text mode (1) or unsure (0)? - int currentMode(); /// reset cursor bottom to the beginning of the top inset // (sort of 'chroot' environment...) void reset(); - /// for spellchecking - void replaceWord(std::string const & replacestring); + /** * the event was not (yet) dispatched. * @@ -225,13 +400,14 @@ public: * Right Thing (even if my getStatus partner said that I can do it). * It is sort of a kludge that should be used only rarely... */ - void undispatched(); + void undispatched() const; /// the event was already dispatched - void dispatched(); - /// Set which update should be done - void screenUpdateFlags(Update::flags f); + void dispatched() const; + + /// Describe the screen update that should be done + void screenUpdateFlags(Update::flags f) const; /** - * don't call update() when done + * Reset update flags to Update::None. * * Should only be called by an inset's doDispatch() method. It means: * I handled that request and I can reassure you that the screen does @@ -240,54 +416,34 @@ public: * This is a fairly rare event as well and only some optimization. * Not using noScreenUpdate() should never be wrong. */ - void noScreenUpdate(); - /// fix cursor in circumstances that should never happen. - /// \retval true if a fix occured. - bool fixIfBroken(); - - /// output - friend std::ostream & operator<<(std::ostream & os, Cursor const & cur); - friend LyXErr & operator<<(LyXErr & os, Cursor const & cur); - - /// - bool textUndo(); - /// - bool textRedo(); - - /// makes sure the next operation will be stored - void finishUndo() const; - - /// open a new group of undo operations. Groups can be nested. - void beginUndoGroup() const; - - /// end the current undo group - void endUndoGroup() const; - - /// The general case: prepare undo for an arbitrary range. - void recordUndo(UndoKind kind, pit_type from, pit_type to) const; - - /// Convenience: prepare undo for the range between 'from' and cursor. - void recordUndo(UndoKind kind, pit_type from) const; - - /// Convenience: prepare undo for the single paragraph or cell - /// containing the cursor - void recordUndo(UndoKind kind = ATOMIC_UNDO) const; - - /// Convenience: prepare undo for the inset containing the cursor - void recordUndoInset(UndoKind kind = ATOMIC_UNDO) const; + void noScreenUpdate() const; - /// Convenience: prepare undo for the whole buffer - void recordUndoFullDocument() const; + /// Forces an updateBuffer() call + void forceBufferUpdate() const; + /// Removes any pending updateBuffer() call + void clearBufferUpdate() const; + /// Do we need to call updateBuffer()? + bool needBufferUpdate() const; - /// Convenience: prepare undo for the selected paragraphs or cells - void recordUndoSelection() const; + /// Repopulate the slices insets from bottom to top. Useful + /// for stable iterators or Undo data. + void sanitize(); /// void checkBufferStructure(); + /// Determine if x falls to the left or to the side of the middle of the + /// inset, and advance the cursor to match this position. If edit is true, + /// keep the cursor in front of the inset if it matter for dialogs. + /// Note: it does not handle RTL text yet, and is only used in math for now. + void moveToClosestEdge(int x, bool edit = false); + + /// whether the cursor is either at the first or last row + bool atFirstOrLastRow(bool up); + public: //private: - + /// DocIterator const & beforeDispatchCursor() const { return beforeDispatchCursor_; } /// @@ -296,8 +452,6 @@ public: private: /// BufferView * bv_; - /// the anchor position - DocIterator anchor_; /// mutable DispatchResult disp_; /** @@ -315,42 +469,12 @@ private: int x_target_; /// if a x_target cannot be hit exactly in a text, put the difference here int textTargetOffset_; - /// do we have a selection? - bool selection_; - /// are we on the way to get one? - bool mark_; - /// are we in word-selection mode? This is set when double clicking. - bool word_selection_; - /// If true, we are behind the previous char, otherwise we are in front - // of the next char. This only make a difference when we are in front - // of a big inset spanning a whole row and computing coordinates for - // displaying the cursor. - bool logicalpos_; /// position before dispatch started DocIterator beforeDispatchCursor_; /// cursor screen coordinates before dispatch started int beforeDispatchPosX_; int beforeDispatchPosY_; - -// FIXME: make them private. -public: - /// the current font settings - Font current_font; - /// the current font - Font real_current_font; - -private: - - // - // math specific stuff that could be promoted to "global" later - // - /// do we allow autocorrection - bool autocorrect_; - /// are we entering a macro name? - bool macromode_; - - /////////////////////////////////////////////////////////////////// // // The part below is the non-integrated rest of the original math @@ -360,22 +484,17 @@ private: /////////////////////////////////////////////////////////////////// public: - /// - void insert(MathAtom const &); - /// - void insert(MathData const &); - /// return false for empty math insets - bool erase(); /// return false for empty math insets - bool backspace(); + /// Use force to skip the confirmDeletion check. + bool erase(bool force = false); + bool backspace(bool force = false); + /// move the cursor up by sending an internal LFUN_UP /// return true if fullscreen update is needed bool up(); /// move the cursor up by sending an internal LFUN_DOWN, /// return true if fullscreen update is needed bool down(); - /// whether the cursor is either at the first or last row - bool atFirstOrLastRow(bool up); /// move up/down in a text inset, called for LFUN_UP/DOWN, /// return true if successful, updateNeeded set to true if fullscreen /// update is needed, otherwise it's not touched @@ -383,79 +502,58 @@ public: /// move up/down in math or any non text inset, call for LFUN_UP/DOWN /// return true if successful bool upDownInMath(bool up); + /// move forward in math. word: whether to skip a whole "word" (insets with + /// the same mathclass) + bool mathForward(bool word); + /// + bool mathBackward(bool word); /// void plainErase(); /// void plainInsert(MathAtom const & at); - /// - void niceInsert(MathAtom const & at); - /// - void niceInsert(docstring const & str, Parse::flags f = Parse::NORMAL, - bool enter = true); - - /// in pixels from top of screen - void setScreenPos(int x, int y); - /// current offset in the top cell - /// interpret name a name of a macro. Returns true if - /// something got inserted. - bool macroModeClose(); + /// interpret name of a macro or ditch it if \c cancel is true. + /// Returns true if something got inserted. + bool macroModeClose(bool cancel = false); /// are we currently typing the name of a macro? bool inMacroMode() const; /// get access to the macro we are currently typing InsetMathUnknown * activeMacro(); /// get access to the macro we are currently typing InsetMathUnknown const * activeMacro() const; + /// the name of the macro we are currently inputting + docstring macroName(); /// replace selected stuff with at, placing the former - // selection in given cell of atom - void handleNest(MathAtom const & at, int cell = 0); - /// - bool isInside(Inset const *) const; + // selection in entry cell of atom + void handleNest(MathAtom const & at); /// make sure cursor position is valid /// FIXME: It does a subset of fixIfBroken. Maybe merge them? void normalize(); - /// mark current cursor trace for redraw - void touch(); - /// hack for reveal codes - void markInsert(); - void markErase(); /// injects content of a cell into parent void pullArg(); /// split font inset etc void handleFont(std::string const & font); - /// display a message - void message(docstring const & msg) const; - /// display an error message - void errorMessage(docstring const & msg) const; - /// - docstring getPossibleLabel() const; - - /// the name of the macro we are currently inputting - docstring macroName(); - /// where in the curent cell does the macro name start? - int macroNamePos(); /// can we enter the inset? bool openable(MathAtom const &) const; - /// - Encoding const * getEncoding() const; /// font at cursor position Font getFont() const; }; /** - * Notifies all insets which appear in old, but not in cur. And then - * notify all insets which appear in cur, but not in old. - * Make sure that the cursor old is valid, i.e. all inset pointers - * point to valid insets! Use Cursor::fixIfBroken if necessary. + * Notifies all insets which appear in \c old, but not in \c cur. And then + * notify all insets which appear in \c cur, but not in \c old. + * \returns true if cursor is now invalid, e.g. if some insets in + * higher cursor slices of \c old do not exist anymore. In this case + * it may be necessary to use Use Cursor::fixIfBroken. */ bool notifyCursorLeavesOrEnters(Cursor const & old, Cursor & cur); } // namespace lyx -#endif // LYXLCURSOR_H +#endif // LCURSOR_H