⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 text_widget.txt

📁 gtk是linux一款强大的夸平台的图形化开发工具
💻 TXT
📖 第 1 页 / 共 2 页
字号:
Date: Sun, 14 Sep 1997 20:17:06 -0700 (PDT)From: Josh MacDonald <jmacd@CS.Berkeley.EDU>To: gnome@athena.nuclecu.unam.mx, gtk-list@redhat.comSubject: [gtk-list] gtktext widget internal documentationPete convinced me to just write up the text widget and let someone elsefinish it.  I'm pretty busy and have other commitments now.  Sorry.  I thinkI'm not the most qualified for some of the remaining work anyway, because Idon't really know Gtk and it's event model very well.  Most of the work so far was possible without knowing Gtk all that well, it was simply a data structure exercise (though after reading this you might say it was a fairlycomplicated data structure exercise).  I'm happy to answer questions.-joshHigh level description:There are several layers of data structure to the widget.  They areseperated from each other as much as possible.  The first is a gappedtext segment similar to the data structure Emacs uses for representingtext.  Then there is a property list, which stores text properties forvarious ranges of text.  There is no direct relation between the textproperty list and the gapped text segment.  Finally there is a drawnline parameter cache to speed calculations when drawing and redrawinglines on screen.  In addition to these data structures, there arestructures to help iterate over text in the buffer.The gapped text segment is quite simple.  It's parameters are (allparameters I mention here are in the structure GtkText):  guchar* text;  guint text_len;  guint gap_position;  guint gap_size;  guint text_end;TEXT is the buffer, TEXT_LEN is its allocated length.  TEXT_END is thelength of the text, including the gap.  GAP_POSITION is the start ofthe gap, and GAP_SIZE is the gap's length.  Therefore, TEXT_END -GAP_SIZE is the length of the text in the buffer.  The macroTEXT_LENGTH returns this value.  To get the value of a character inthe buffer, use the macro TEXT_INDEX(TEXT,INDEX).  This macro testswhether the index is less than the GAP_POSITION and returnsTEXT[INDEX] or returns TEXT[GAP_SIZE+INDEX].  The functionMOVE_GAP_TO_POINT positions the gap to a particular index.  Thefunction MAKE_FORWARD_SPACE lengthens the gap to provide room for acertain number of characters.The property list is a doubly linked list (GList) of text propertydata for each contiguous set of characters with similar properties.The data field of the GList points to a TextProperty structure, whichcontains:  TextFont* font;  GdkColor* back_color;  GdkColor* fore_color;  guint length;Currently, only font and color data are contained in the propertylist, but it can be extended by modifying the INSERT_TEXT_PROPERTY,TEXT_PROPERTIES_EQUAL, and a few other procedures.  The text propertystructure does not contain an absolute offset, only a length.  As aresult, inserting a character into the buffer simply requires movingthe gap to the correct position, making room in the buffer, and eitherinserting a new property or extending the old one.  This logic is doneby INSERT_TEXT_PROPERTY.  A similar procedure exists to delete fromthe text property list, DELETE_TEXT_PROPERTY.  Since the propertystructure doesn't contain an offset, insertion into the list is anO(1) operation.  All such operations act on the insertion point, whichis the POINT field of the GtkText structure.The GtkPropertyMark structure is used for keeping track of the mappingbetween absolute buffer offsets and positions in the property list.These will be referred to as property marks.  Generally, there arefour property marks the system keeps track of.  Two are trivial, thebeginning and the end of the buffer are easy to find.  The other twoare the insertion point (POINT) and the cursor point (CURSOR_MARK).All operations on the text buffer are done using a property mark as asort of cursor to keep track of the alignment of the property list andthe absolute buffer offset.  The GtkPropertyMark structure contains:  GList* property;  guint offset;  guint index;PROPERTY is a pointer at the current property list element.  INDEX isthe absolute buffer index, and OFFSET is the offset of INDEX from thebeginning of PROPERTY.  It is essential to keep property marks valid,or else you will have the wrong text properties at each property marktransition.  An important point is that all property marks are invalidafter a buffer modification unless care is taken to keep themaccurate.  That is the difficulty of the insert and delete operations,because as the next section describes, line data is cached and byneccesity contains text property marks.  The functions for operatingand computing property marks are: void advance_mark     (GtkPropertyMark* mark); void decrement_mark   (GtkPropertyMark* mark); void advance_mark_n   (GtkPropertyMark* mark, gint n); void decrement_mark_n (GtkPropertyMark* mark, gint n); void move_mark_n      (GtkPropertyMark* mark, gint n); GtkPropertyMark find_mark      (GtkText* text, guint mark_position); GtkPropertyMark find_mark_near (GtkText* text, guint mark_position,                                 const GtkPropertyMark* near);ADVANCE_MARK and DECREMENT_MARK modify the mark by plus or minus onebuffer index.  ADVANCE_MARK_N and DECREMENT_MARK_N modify the mark byplus or minus N indices.  MOVE_MARK_N accepts a positive or negativeargument.  FIND_MARK returns a mark at MARK_POSITION using a linearsearch from the nearest known property mark (the beginning, the end,the point, etc).  FIND_MARK_NEAR also does a linear search, butsearches from the NEAR argument.  A number of macros exist at the topof the file for doing things like getting the current text property,or some component of the current property.  See the MARK_* macros.Next there is a LineParams structure which contains all theinformation neccesary to draw one line of text on screen.  When I say"line" here, I do not mean one line of text seperated by newlines,rather I mean one row of text on screen.  It is a matter of policy howvisible lines are chosen and there are currently two policies,line-wrap and no-line-wrap.  I suspect it would not be difficult toimplement new policies for doing such things as justification.  TheLineParams structure includes the following fields:  guint font_ascent;  guint font_descent;  guint pixel_width;  guint displayable_chars;  guint wraps : 1;  PrevTabCont tab_cont;  PrevTabCont tab_cont_next;  GtkPropertyMark start;  GtkPropertyMark end;FONT_ASCENT and FONT_DESCENT are the maximum ascent and descent of anycharacter in the line.  PIXEL_WIDTH is the number of pixels wide thedrawn region is, though I don't think it's actually being usedcurrently.  You may wish to remove this field, eventually, though Isuspect it will come in handy implementing horizontal scrolling.DISPLAYABLE_CHARS is the number of characters in the line actuallydrawn.  This may be less than the number of characters in the linewhen line wrapping is off (see below).  The bitflag WRAPS tellswhether the next line is a continuation of this line.  START and ENDare the marks at the beginning and end of the line.  Note that END isthe actual last character, not one past it, so the smallest line(containing, for example, one newline) has START == END.  TAB_CONT andTAB_CONT_NEXT are for computation of tab positions.  I will discussthem later.A point about the end of the buffer.  You may be tempted to considerworking with the buffer as an array of length TEXT_LENGTH(TEXT), butyou have to be careful that the editor allows you to position yourcursor at the last index of the buffer, one past the last character.The macro LAST_INDEX(TEXT, MARK) returns true if MARK is positioned atthis index.  If you see or add a special case in the code for thisend-of-buffer case, make sure to use LAST_INDEX if you can.  Veryoften, the last index is treated as a newline.[ One way the last index is special is that, although it is always  part of some property, it will never be part of a property of  length 1 unless there are no other characters in the text. That  is, its properties are always that of the preceding character,  if any.    There is a fair bit of special case code to mantain this condition -  which is needed so that user has control over the properties of  characters inserted at the last position. OWT 2/9/98 ]Tab stops are variable width.  A list of tab stops is contained in theGtkText structure:  GList *tab_stops;  gint default_tab_width;The elements of tab_stops are integers casted to gpointer.  This is alittle bogus, but works.  For example:  text->default_tab_width = 4;  text->tab_stops = NULL;  text->tab_stops = g_list_prepend (text->tab_stops, (void*)8);  text->tab_stops = g_list_prepend (text->tab_stops, (void*)8);is how these fields are initialized, currently.  This means that thefirst two tabs occur at 8 and 16, and every 4 characters thereafter.Tab stops are used in the computation of line geometry (to fill in aLineParams structure), and the width of the space character in thecurrent font is used.  The PrevTabCont structure, of which two arestored per line, is used to compute the geometry of lines which mayhave wrapped and carried part of a tab with them:  guint pixel_offset;  TabStopMark tab_start;PIXEL_OFFSET is the number of pixels at which the line should start,and tab_start is a tab stop mark, which is similar to a property mark,only it keeps track of the mapping between line position (column) andthe next tab stop.  A TabStopMark contains:  GList* tab_stops;  gint to_next_tab;TAB_STOPS is a pointer into the TAB_STOPS field of the GtkTextstructure.  TO_NEXT_TAB is the number of characters before the nexttab.  The functions ADVANCE_TAB_MARK and ADVANCE_TAB_MARK_N advancethese marks.  The LineParams structure contains two PrevTabContstructures, which each contain a tab stop.  The first (TAB_CONT) isfor computing the beginning pixel offset, as mentioned above.  Thesecond (TAB_CONT_NEXT) is used to initialize the TAB_CONT field of thenext line if it wraps.Since computing the parameters of a line are fairly complicated, Ihave one interface that should be all you ever need to figure outsomething about a line.  The function FIND_LINE_PARAMS computes theparameters of a single line.  The function LINE_PARAMS_ITERATE is usedfor computing the properties of some number (> 0) of sequential lines.voidline_params_iterate (GtkText* text,		     const GtkPropertyMark* mark0,		     const PrevTabCont* tab_mark0,		     gboolean alloc,		     gpointer data,		     LineIteratorFunction iter);where LineIteratorFunction is:typedef gint (*LineIteratorFunction) (GtkText* text,                                      LineParams* lp,                                      gpointer data);The arguments are a text widget (TEXT), the property mark at thebeginning of the first line (MARK0), the tab stop mark at thebeginning of that line (TAB_MARK0), whether to heap-allocate theLineParams structure (ALLOC), some client data (DATA), and a functionto call with the parameters of each line.  TAB_MARK0 may be NULL, butif so MARK0 MUST BE A REAL LINE START (not a continued line start; itis preceded by a newline).  If TAB_MARK0 is not NULL, MARK0 may be anyline start (continued or not).  See the code for examples.  Thefunction ITER is called with each LineParams computed.  If ALLOC was

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -