* $Id$ *
* *
* $Log$
- * Revision 1.2 1998/08/12 08:33:23 KB
- * Cursor and insert/delete work much better now, code streamlined, still
- * a minor problem left.
+ * Revision 1.3 1998/11/19 20:34:50 KB
+ * fixes
+ *
+ * Revision 1.8 1998/09/23 08:57:27 KB
+ * changed deletion behaviour
+ *
+ * Revision 1.7 1998/08/16 21:21:29 VZ
+ *
+ * 1) fixed config file bug: it was never created (attempt to create ~/.M/config
+ * always failed, must mkdir("~/.M") first)
+ * 2) "redesign" of "Folder properties" dialog and bug corrected, small change to
+ * MInputBox (it was too wide)
+ * 3) bug in ProvFC when it didn't reckognize the books as being in the correct
+ * format (=> messages "can't reopen book") corrected
+ * 4) I tried to enhance MDialog_About(), but it didn't really work... oh well,
+ * I've never said I was an artist
*
* Revision 1.6 1998/07/08 11:56:56 KB
* M compiles and runs on Solaris 2.5/gcc 2.8/c-client gso
# pragma implementation "kbList.h"
#endif
-#ifdef M_BASEDIR
-# include "Mconfig.h"
-#endif
-
#include "kbList.h"
+
kbListNode::kbListNode( void *ielement,
kbListNode *iprev,
kbListNode *inext)
return *this;
}
kbList::iterator &
-kbList::iterator::operator++(int foo)
+kbList::iterator::operator++(int /* foo */)
{
return operator++();
}
kbList::iterator &
-kbList::iterator::operator--(int bar)
+kbList::iterator::operator--(int /* bar */)
{
return operator--();
}
}
void
-kbList::erase(kbList::iterator & i)
+kbList::doErase(kbList::iterator & i)
{
kbListNode
*node = i.Node(),
next->prev = prev;
// delete this node and contents:
- if(ownsEntries)
- delete *i;
+ // now done separately
+ //if(ownsEntries)
+ //delete *i;
delete i.Node();
// change the iterator to next element:
struct kbListNode *next;
/// pointer to previous node or NULL
struct kbListNode *prev;
- /// pointer to the actual data
+ /// pointer to the actual data
void *element;
/** Constructor - it automatically links the node into the list, if
the iprev, inext parameters are given.
@param inext if not NULL, use this as next element in list
*/
kbListNode( void *ielement,
- kbListNode *iprev = (kbListNode *) NULL,
- kbListNode *inext = (kbListNode *) NULL);
+ kbListNode *iprev = NULL,
+ kbListNode *inext = NULL);
/// Destructor.
~kbListNode();
};
/** Constructor.
@param n if not NULL, the node to which to point
*/
- iterator(kbListNode *n = (kbListNode *) NULL);
+ iterator(kbListNode *n = NULL);
/** Dereference operator.
@return the data pointer of the node belonging to this
iterator
*/
void * operator*();
+ /** This operator allows us to write if(i). It is <em>not</em> a
+ dereference operator and the result is always useless apart
+ from its logical value!
+ */
+ operator void*() const { return node == NULL ? (void*)0 : (void*)(-1); }
+
/** Increment operator - prefix, goes to next node in list.
@return itself
*/
/** Comparison operator.
@return true if not equal.
*/
- bool operator !=(iterator const &) const;
+ bool operator !=(iterator const &) const;
/* Comparison operator.
@return true if equal
*/
- bool operator ==(iterator const &) const;
+ bool operator ==(iterator const &) const;
/** Returns a pointer to the node associated with this iterator.
This function is not for general use and should be
*/
bool ownsObjects(void)
{ return ownsEntries; }
-
+
/** Add an entry at the end of the list.
@param element pointer to data
*/
void *pop_front(void);
/** Insert an element into the list.
- @param i an iterator pointing to the element, before which the
- new one should be inserted. After the insert operation i will
- point to the newly inserted element.
+ @param i an iterator pointing to the element, before which the new one should be inserted
@param element the element data
*/
void insert(iterator & i, void *element);
+ /** Remove an element from the list _without_ deleting the object.
+ @param i iterator pointing to the element to be deleted
+ @return the value of the element just removed
+ */
+ void *remove(iterator& i) { void *p = *i; doErase(i); return p; }
+
/** Erase an element, move iterator to following element.
@param i iterator pointing to the element to be deleted
*/
- void erase(iterator & i);
-
+ void erase(iterator & i) { deleteContent(i); doErase(i); }
+
/* Get head of list.
@return iterator pointing to head of list
*/
/* Query whether list is empty.
@return true if list is empty
*/
- bool empty(void) const
+ inline bool empty(void) const
{ return first == NULL ; }
protected:
kbListNode *first;
/// pointer to last element in list
kbListNode *last;
+protected:
+ /** Erase an element, move iterator to following element.
+ @param i iterator pointing to the element to be deleted
+ */
+ void doErase(iterator & i);
+
+ /** Deletes the actual content if ownsflag is set.
+ param iterator i
+ */
+ inline void deleteContent(iterator i)
+ { if(ownsEntries) delete *i; }
+
private:
/// forbid copy construction
{ node = i.Node(); } \
friend class name; \
public: \
- inline iterator(kbListNode *n = (kbListNode *) NULL) \
+ inline iterator(kbListNode *n = NULL) \
: kbList::iterator(n) {} \
inline type * operator*() \
/* the cast is needed for MS VC++ 5.0 */ \
{ return (type *)((kbList::iterator *)this)->operator*() ; } \
}; \
- inline name(bool ownsEntriesFlag = FALSE) \
+ inline name(bool ownsEntriesFlag = TRUE) \
: kbList(ownsEntriesFlag) {} \
\
- inline void push_back(type *element) \
- { kbList::push_back((void *)element); } \
- \
- inline void push_front(type *element) \
- { kbList::push_front((void *)element); } \
- \
inline type *pop_back(void) \
{ return (type *) kbList::pop_back(); } \
\
inline type *pop_front(void) \
{ return (type *) kbList::pop_front(); } \
\
- inline void insert(iterator & i, type *element) \
- { kbList::insert(i, (void *) element); } \
- \
+ type *remove(iterator& i) \
+ { return (type *)kbList::remove(i); } \
inline void erase(iterator & i) \
- { kbList::erase(i); } \
+ { deleteContent(i); kbList::erase(i); } \
\
inline iterator begin(void) const \
{ return kbList::begin(); } \
~name() \
{ \
kbListNode *next; \
- while ( first != (kbListNode *) NULL ) \
+ while ( first != NULL ) \
{ \
next = first->next; \
if(ownsEntries) \
- delete typecast(first->element); \
+ delete (type *)first->element; \
delete first; \
first = next; \
} \
} \
- private: \
- inline type * typecast(void *ptr) \
- { return (type *) ptr; } \
- }
+protected: \
+ inline void deleteContent(iterator i) \
+ { if(ownsEntries) delete *i; } \
+}
#ifdef MCONFIG_H
/// define the most commonly used list type once:
enum ids{ ID_EDIT = 1, ID_ADD_SAMPLE, ID_CLEAR, ID_PRINT,
ID_PRINT_SETUP, ID_PAGE_SETUP, ID_PREVIEW, ID_PRINT_PS,
ID_PRINT_SETUP_PS, ID_PAGE_SETUP_PS,ID_PREVIEW_PS,
- ID_DPRINT,
+ ID_DPRINT, ID_WRAP, ID_NOWRAP,
ID_WXLAYOUT_DEBUG, ID_QUIT, ID_CLICK, ID_HTML, ID_TEXT, ID_TEST };
file_menu->Append(ID_PREVIEW_PS, "Print Preview PostScript", "Preview (PostScript)");
#endif
file_menu->AppendSeparator();
+ file_menu->Append(ID_WRAP, "Wrap mode", "Activate wrapping at pixel 200.");
+ file_menu->Append(ID_NOWRAP, "No-wrap mode", "Deactivate wrapping.");
+ file_menu->AppendSeparator();
// file_menu->Append( ID_DPRINT, "Direct Print");
file_menu->Append( ID_TEXT, "Export Text");
file_menu->Append( ID_HTML, "Export HTML");
case ID_PRINT:
m_lwin->Print();
break;
+ case ID_NOWRAP:
+ case ID_WRAP:
+ m_lwin->GetLayoutList().SetWrapMargin(
+ event.GetId() == ID_NOWRAP ? -1 : 40);
+ break;
case ID_DPRINT:
{
wxLayoutList llist;
/*
TODO:
- - new cursor movement calculations
- - moving lines and moving across linebreaks still broken
-
- - word wrap
+ - cursor redraw problems
- blinking cursor
- mouse click positions cursor
- selection (SetMark(), GetSelection())
- - DND acceptance of text
-
+ - DND acceptance of text / clipboard support
- wxlwindow: formatting menu: problem with checked/unchecked consistency gtk bug?
*/
-#define USE_NEW_CURSORCODE 1
-
/*
Known wxGTK bugs:
- MaxX()/MaxY() don't get set
wxLayoutList::wxLayoutList()
{
m_DefaultSetting = NULL;
+ m_WrapMargin = -1;
Clear();
}
headOfLine++;
position_HeadOfLine = position;
}
-#if defined( USE_NEW_CURSORCODE )
if(i == m_CursorObject)
CalculateCursor(dc);
-#else
- if(cursorObject == NULL && cursorPos.y == m_CursorPos.y) // look for cursor
- {
- if(cursorPos.x >= m_CursorPos.x &&
- m_CursorPos.x-cursorPos.x+(**i).CountPositions()) // cursor is in current object
- {
- cursorObject = *i;
- CalculateCursor(dc);
- }
- }
-#endif
i++;
}
while(i != end());
CoordType width, height, descent;
CoordType baseLineSkip = 20; //FIXME
- CoordType offset;
- if( FindCurrentObject() == iterator(NULL)) // empty list
+ if( m_CursorObject == iterator(NULL)) // empty list
{
- DrawCursor(dc,true); // erase it
m_CursorCoords = wxPoint(0,0);
m_CursorSize = wxPoint(2,baseLineSkip);
m_CursorMoved = false; // coords are valid
return;
}
- wxLayoutObjectBase &obj = **FindCurrentObject(&offset);
-
- DrawCursor(dc,true); // erase it
+ wxLayoutObjectBase &obj = **m_CursorObject;
m_CursorCoords = obj.GetPosition();
if(obj.GetType() == WXLO_TYPE_TEXT)
{
wxLayoutObjectText *tobj = (wxLayoutObjectText *)&obj;
String & str = tobj->GetText();
- String sstr = str.substr(0,offset);
+ String sstr = str.substr(0,m_CursorOffset);
dc.GetTextExtent(sstr,&width,&height,&descent);
m_CursorCoords = wxPoint(m_CursorCoords.x+width,
m_CursorCoords.y);
void
wxLayoutList::ShowCurrentObject()
{
- CoordType offs;
- wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
-
wxLayoutDebug("CursorPos (%d, %d)", (int) m_CursorPos.x, (int) m_CursorPos.y);
wxLayoutDebug("CursorOffset = %d", (int) m_CursorOffset);
wxLayoutDebug("CursorObject = %p", m_CursorObject);
- wxLayoutDebug("Line length: %d", GetLineLength(i));
-
- if(i == iterator(NULL))
+ if(m_CursorObject == iterator(NULL))
wxLayoutDebug("<<no object found>>");
else
{
- if((*i)->GetType() == WXLO_TYPE_TEXT)
- wxLayoutDebug(" \"%s\", offs: %d", ((wxLayoutObjectText *)(*i))->GetText().c_str(), offs);
+ if((*m_CursorObject)->GetType() == WXLO_TYPE_TEXT)
+ wxLayoutDebug(" \"%s\", offs: %d",
+ ((wxLayoutObjectText *)(*m_CursorObject))->GetText().c_str(),
+ m_CursorOffset);
else
- wxLayoutDebug(" %s", TypeString((*i)->GetType()));
+ wxLayoutDebug(" %s", TypeString((*m_CursorObject)->GetType()));
}
+ wxLayoutDebug("Line length: %d", GetLineLength(m_CursorObject));
+
}
#endif
return m_FoundIterator = i; // not found
}
-wxLayoutObjectList::iterator
-wxLayoutList::FindCurrentObject(CoordType *offset)
-{
- if(offset)
- *offset = m_CursorOffset;
- return m_CursorObject;
-}
-
bool
wxLayoutList::MoveCursor(int dx, int dy)
{
direction = down;
else
direction = up;
-
+
+ wxASSERT(m_CursorObject);
// now move cursor forwards until at the new position:
// first, go to the right line:
do
{
- i = FindCurrentObject(&offs);
+ i = m_CursorObject;
startover: // ugly, but easiest way to do it
if(i == end())
return; // we cannot delete anything more
/* Here we need to treat linebreaks differently.
- If offs==0 we are before the linebreak, otherwise behind. */
+ If m_CursorOffset==0 we are before the linebreak, otherwise behind. */
if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
{
- if(offs == 0)
+ if(m_CursorOffset == 0)
{
m_MaxLine--;
erase(i);
else // delete the object behind the linebreak
{
i++; // we increment and continue as normal
- offs=0;
+ m_CursorOffset=0;
goto startover;
}
}
CoordType len = tobj->CountPositions();
// If we find the end of a text object, this means that we
// have to delete from the object following it.
- if(len == offs)
+ if(len == m_CursorOffset)
{
i++;
- offs = 0;
+ m_CursorOffset = 0;
goto startover;
}
else if(len <= count) // delete this object
else
{
len = count;
- tobj->GetText().erase(offs,len);
+ tobj->GetText().erase(m_CursorOffset,len);
// cursor unchanged
return; // we are done
}
else // delete the following object
{
i++; // we increment and continue as normal
- offs=0;
+ m_CursorOffset=0;
goto startover;
}
}
m_bModified = true;
- CoordType offs;
- wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
+ wxLayoutObjectList::iterator i = m_CursorObject;
-// if(i != iterator(NULL) && (*obj).GetType() == WXLO_TYPE_LINEBREAK)
-// {
-// m_CursorPos.x = 0; m_CursorPos.y ++;
-// }
+ if(i != iterator(NULL) && (*obj).GetType() == WXLO_TYPE_LINEBREAK)
+ {
+ m_CursorPos.x = 0; m_CursorPos.y ++;
+ }
if(i == end())
{
push_back(obj);
m_CursorObject = tail();
}
- else if(offs == 0)
+ else if(m_CursorOffset == 0)
{
insert(i,obj);
m_CursorObject = i;
}
// do we have to split a text object?
- else if((*i)->GetType() == WXLO_TYPE_TEXT && offs != (*i)->CountPositions())
+ else if((*i)->GetType() == WXLO_TYPE_TEXT && m_CursorOffset != (*i)->CountPositions())
{
wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
- String left = tobj->GetText().substr(0,offs); // get part before cursor
- tobj->GetText() = tobj->GetText().substr(offs,(*i)->CountPositions()-offs); // keeps the right half
+ String left = tobj->GetText().substr(0,m_CursorOffset); // get part before cursor
+ tobj->GetText() = tobj->GetText().substr(m_CursorOffset,(*i)->CountPositions()-m_CursorOffset); // keeps the right half
insert(i,obj);
+ m_CursorObject = i; // == obj
insert(i,new wxLayoutObjectText(left)); // inserts before
}
else
m_bModified = true;
- CoordType offs;
- wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
+ wxLayoutObjectList::iterator i = m_CursorObject;
if(i == end())
{
return;
}
- if(i != iterator(NULL) && (**i).GetType() == WXLO_TYPE_LINEBREAK)
- {
- m_CursorPos.x = 0; m_CursorPos.y ++;
- }
-
switch((**i).GetType())
{
case WXLO_TYPE_TEXT:
// insert into an existing text object:
tobj = (wxLayoutObjectText *)*i ;
wxASSERT(tobj);
- tobj->GetText().insert(offs,text);
+ tobj->GetText().insert(m_CursorOffset,text);
m_CursorObject = i;
- m_CursorOffset = offs + text.length();
+ m_CursorOffset = m_CursorOffset + text.length();
m_CursorPos.x += text.length();
break;
case WXLO_TYPE_LINEBREAK:
default:
j = i;
- if(offs == 0) // try to append to previous object
+ if(m_CursorOffset == 0) // try to append to previous object
{
j--;
if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT)
m_CursorOffset = 0;
m_CursorSize = wxPoint(2,(BASELINESTRETCH*m_FontPtSize)/10);
- m_MaxLine = 0;
+ m_MaxLine = 1;
m_LineHeight = (BASELINESTRETCH*m_FontPtSize)/10;
m_MaxX = 0; m_MaxY = 0;
}
+void
+wxLayoutList::SetWrapMargin(long n = -1)
+{
+ m_WrapMargin = n;
+}
+
+void
+wxLayoutList::WrapLine(void)
+{
+ wxASSERT(m_CursorObject);
+
+ iterator i = m_CursorObject;
+
+ if(!DoWordWrap() || !i ) // empty list
+ return;
+ int cursorpos = m_CursorPos.x, cpos, offset;
+
+ if(cursorpos < m_WrapMargin)
+ return;
+
+ // else: break line
+
+ // find the right object to break:
+ // is it the current one?
+
+ i = m_CursorObject;
+ cpos = cursorpos-m_CursorOffset;
+ while(i != begin() && cpos >= m_WrapMargin)
+ {
+ i--;
+ cpos -= (**i).CountPositions();
+ }
+ // now i is the object to break and cpos its position
+
+ offset = m_WrapMargin - cpos;
+ wxASSERT(offset <= (**i).CountPositions());
+
+ // split it
+ if((**i).GetType() == WXLO_TYPE_TEXT)
+ {
+ wxLayoutObjectText &t = *(wxLayoutObjectText *)*i;
+ for(; offset > 0; offset--)
+ if(t.GetText().c_str()[offset] == ' ' || t.GetText().c_str()[offset] == '\t')
+ {
+ String left = t.GetText().substr(0,offset-1); // get part before cursor
+ t.GetText() = t.GetText().substr(offset,t.CountPositions()-offset); // keeps the right halve
+ insert(i,new wxLayoutObjectLineBreak);
+ insert(i,new wxLayoutObjectText(left)); // inserts before
+ break;
+ }
+ if(offset == 0)
+ {
+ // only insert a line break if there isn't already one
+ iterator j = i; j--;
+ if(j && j != begin() && (**j).GetType() != WXLO_TYPE_LINEBREAK)
+ insert(i,new wxLayoutObjectLineBreak);
+ else
+ return; // do nothing
+ }
+ }
+ else
+ insert(i,new wxLayoutObjectLineBreak);
+ m_MaxLine++;
+ m_CursorPos.y++;
+ m_CursorPos.x -= offset;
+ m_CursorOffset -= offset;
+}
/******************** printing stuff ********************/
wxLayoutPrintout::wxLayoutPrintout(wxLayoutList &llist,
bool wxLayoutPrintout::HasPage(int pageNum)
{
- return pageNum < m_NumOfPages;
+ return pageNum <= m_NumOfPages;
}
/// set font colours by name
inline void SetFontColour(char const *fg, char const *bg = NULL) { SetFont(-1,-1,-1,-1,-1,fg,bg); }
+ /** Sets the wrap margin in cursor positions.
+ @param n the wrap margin, -1 to disable auto wrap
+ */
+ void SetWrapMargin(long n = -1);
+
+ /// Wraps the current line if word wrap is enabled.
+ void WrapLine(void);
/** Re-layouts the list on a DC.
@param dc the dc to layout for
/// return a pointer to the default settings (dangerous, why?) FIXME:
wxLayoutObjectCmd const *GetDefaults(void) const { return m_DefaultSetting ; }
- wxLayoutObjectList::iterator FindCurrentObject(CoordType *offset = NULL);
+ /// returns the iterator for the object under the cursor
+ wxLayoutObjectList::iterator GetCurrentObject(CoordType *offset =
+ NULL)
+ { if(offset) *offset = m_CursorOffset; return m_CursorObject; }
+
// get the length of the line with the object pointed to by i, offs
// only used to decide whether we are before or after linebreak
CoordType GetLineLength(wxLayoutObjectList::iterator i,
/// find the object to the cursor position and returns the offset
/// in there
wxLayoutObjectList::iterator FindObjectCursor(wxPoint *cpos, CoordType *offset = NULL);
+ /// get the wrap margin
+ inline long GetWrapMargin(void) const { return m_WrapMargin; }
+ /// do we do wrapping?
+ inline bool DoWordWrap(void) const { return m_WrapMargin != -1; }
private:
/// Resets the font settings etc to default values
void ResetSettings(wxDC &dc);
wxPoint m_FoundCursor;
/// remembers the iterator to the object related to m_FoundCursor
wxLayoutObjectList::iterator m_FoundIterator;
+ /// the wrap margin
+ long m_WrapMargin;
};
class wxLayoutPrintout: public wxPrintout
break;
case WXK_END:
p = m_llist.GetCursor();
- p.x = m_llist.GetLineLength(m_llist.FindCurrentObject(NULL));
+ p.x = m_llist.GetLineLength(m_llist.GetCurrentObject());
m_llist.SetCursor(p);
break;
case WXK_DELETE :
if(event.ControlDown()) // delete to end of line
{
help = m_llist.GetLineLength(
- m_llist.FindCurrentObject(NULL))
+ m_llist.GetCurrentObject())
- m_llist.GetCursor().x;
m_llist.Delete(help ? help : 1);
}
case WXK_F1:
m_llist.Debug();
break;
+ case WXK_F2:
+ m_llist.WrapLine();
+ break;
#endif
default:
String tmp;
tmp += keyCode;
m_llist.Insert(tmp);
+ m_llist.WrapLine();
}
break;
}