When you start adding multiple Legato scripts to the same menu in GoFiler, the menu can become quite crowded. Repeating the same logo, the default “LS” for a Legato script, doesn’t help at all. To combat this problem, GoFiler 4.19a introduced a new way of defining custom logos for Legato scripts. Using this feature can make individual scripts stand out and help the user identify them more easily. Custom icons can also add a professional veneer and polish to your script, which is always nice to do particularly if the script is being deployed to multiple users on a permanent basis.
Friday, August 25. 2017
LDC #49: Making Scripts Stand Out With Image Icons
To add an item to a menu in Legato, we commonly have used the MenuAddFunction function. This function can take a couple of different parameters, but the way it’s been demonstrated in previous posts shows the function taking a single string array parameter with certain named values. With the release of GoFiler 4.19a, a few new parameter types are now accepted in addition to the previous ones:
InternalBitmap | Bitmap Name – Bitmap name for an internal, existing menu function for use in displaying an associated icon. This cannot point to a script defined bitmap. If SmallBitmap or LargeBitmap are used, this parameter is overridden. | |
SmallBitmap | Small Bitmap Name – The name of a resource defined within the script or a bitmap file. This bitmap must be 22x22 pixels or less for display as a small ribbon or menu item. | |
LargeBitmap | Large Bitmap Name – The name of a resource defined within the script or a bitmap file. This bitmap must be 40x35 (width/height) pixels or less for display as a large ribbon item. |
Using these new values, an example script setup function could look like this:
/****************************************/ int setup() { /* Called from Application Startup */ /****************************************/ string fnScript; /* Us */ string item[10]; /* Menu Item */ int rc; /* Return Code */ /* */ /* ** Add Menu Item */ /* * Define Function */ item["Code"] = "EXTENSION_ALIGN_OUTLINE"; /* Function Code */ item["MenuText"] = "&Align Outline Text"; /* Menu Text */ item["Description"] = "<B>Align Outline Text</B> "; /* Description (long) */ item["Description"]+= "\r\rBreaks outline out into aligned blocks.";/* * description */ item["SmallBitmap"] = "HTML_ALIGN_OUTLINE"; /* * Check for Existing */ rc = MenuFindFunctionID(item["Code"]); /* Look for existing */ if (IsNotError(rc)) { /* Was already be added */ return ERROR_NONE; /* Exit */ } /* end error */ /* * Registration */ rc = MenuAddFunction(item); /* Add the item */ if (IsError(rc)) { /* Was already be added */ return ERROR_NONE; /* Exit */ } /* end error */ fnScript = GetScriptFilename(); /* Get the script filename */ MenuSetHook(item["Code"], fnScript, "run"); /* Set the Test Hook */ return ERROR_NONE; /* Return value (does not matter) */ } /* end setup */
The SmallBitmap item in this example is pointing to the resource named HTML_ALIGN_OUTLINE. In order for this to actually work though, HTML_ALIGN_OUTLINE needs to be defined as a resource. A resource declaration can be at the start or end of the file, but it would have this format:
#beginresource <NAME> <TYPE> <VALUE> #endresources
In the example setup function above, the resource is named HTML_ALIGN_OUTLINE. We used a Bitmap file, so type would be BITMAP. The VALUE can be either the name of a separate file or it can be a hexadecimal representation of the image itself, which we discuss a little later. Specifying a file location is probably the easiest way to do it. So, for our example, the code would look like:
#beginresource HTML_ALIGN_OUTLINE BITMAP “my_bitmap.bmp” #endresources
Of course, this relies on the image being in the scripts folder. Otherwise the file “my_bitmap.bmp” would not be found, and the default Legato icon would be loaded instead. Aside from bitmaps, icon files can also be used. They have an “.ico” extension, and their type would be ICON instead of BITMAP. Using a separate image file can work fine, but if you want your script to be more portable, having everything compressed into a single file is probably a better idea. Legato allows you to define a resource as embedded hexadecimal values by omitting the VALUE from the resource declaration. Immediately below the NAME line, a ‘{’ character (or the statement ‘begin’) must appear, followed by the hexadecimal data in single quotes with each byte having a space delimiter. A close brace should end the hexadecimal declaration. An example resource defined this way would look like this:
#beginresource HTML_ALIGN_OUTLINE BITMAP { '42 4D 78 06 00 00 00 00 00 00 36 00 00 00 28 00' '00 00 14 00 00 00 14 00 00 00 01 00 20 00 00 00' '00 00 42 06 00 00 12 0B 00 00 12 0B 00 00 00 00' '00 00 00 00 00 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 B8 82 4D 00 B8 82 4D 00 B8 82' '4D 00 B8 82 4D 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 72 72 72 00 FF FF' 'FF 00 FF FF FF 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 72 72 72 00 72 72 72 00 72 72' '72 00 FF FF FF 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 B8 82 4D 00 B8 82 4D 00 B8 82' '4D 00 B8 82 4D 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 72 72 72 00 FF FF' 'FF 00 FF FF FF 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 B8 82 4D 00 B8 82 4D 00 B8 82' '4D 00 B8 82 4D 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 00 00 ' } #endresource
This can also be compacted by removing the single quotes and all space characters. However if you do use this compact format, you need to add the statement ‘compact’ after the statement ‘begin’. This type of resource statement looks like this:
name BITMAP begin compact 424D3E010000000000003E00000028000000400000002000000001000100000000000001000000... FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF end
If you have a bitmap or icon file that you want to convert into hexadecimal format so it can be made into an image icon in GoFiler, one of the stock Legato scripts with which the application ships is the “View File as Binary” script. This allows you to view the file as a hexadecimal representation, so you can copy/paste the hex values out into a script file that you’re developing. This script is accessible under the File ribbon in GoFiler in the Tools menu.
For a full example of what a complete script with an icon added looks like, we’ve added an image icon to last week’s script. Here is the complete AlignOutlinedText script file with added image icon:
// // // GoFiler Legato Script - Align Outlined Text // ------------------------------------------ // // Rev 06/30/2017 // 08/16/2017 // // // (c) 2017 Novaworks, LLC -- All rights reserved. // // Examines any HTML file for a paragraph followed by up to 5 words, followed by a tab or 5+ non-breaking // spaces. If it finds them, it wraps the initial words in a font tag and deletes the non-breaking // spaces. // /********************************************************/ /* Global Items */ /* ------------ */ /********************************************************/ #define NBSP "(( )|(&NBSP;)|( )|( ))" #define NBSP_ONLY "^"+NBSP+"{5,}$" #define TAB_CHAR "	" /* font tags for SM, MD, and LG values defined below */ #define FONT_TAG_SM "<FONT STYLE=\"display: inline-block; width: 0.5in; float: left; white-space:nowrap\">" #define FONT_TAG_MD "<FONT STYLE=\"display: inline-block; width: 1in; float: left; white-space:nowrap\">" #define FONT_TAG_LG "<FONT STYLE=\"display: inline-block; width: 1.5in; float: left; white-space:nowrap\">" #define UNDERLINE_TAG "<U>" #define UNDERLINE_CLOSE "</U>" #define CLOSE_FONT "</FONT>" /* threshold is used with CHARS_SM,CHARS_MD,CHARS_LG to */ /* * calculate font tag to use. */ #define CHAR_SIZE_THRESHOLD 8 /* threshold for character levels */ #define CHARS_SM 0 /* small */ #define CHARS_MD 1 /* medium */ #define CHARS_LG 2 /* large */ #define MAX_LEAD_IN_WORDS 3 /* max words in a lead-in segment */ #define MIN_NBSP_AFTER_LEAD_IN 5 /* minimum NBSP's after lead in */ int run (int f_id, string mode);/* Call from Hook Processor */ int setup (); string get_font_tag (int text_width); int get_word_length (string test); string replace_in_string (string data, string find, string replace); boolean test_font_nbsp (int psx, int psy, handle sgml, handle edit_object); boolean test_nbsp (int psx, int psy, handle sgml, handle edit_object); int counter; /****************************************/ int setup() { /* Called from Application Startup */ /****************************************/ string fnScript; /* Us */ string item[10]; /* Menu Item */ int rc; /* Return Code */ /* */ /* ** Add Menu Item */ /* * Define Function */ item["Code"] = "EXTENSION_ALIGN_OUTLINE"; /* Function Code */ item["MenuText"] = "&Align Outline Text"; /* Menu Text */ item["Description"] = "<B>Align Outline Text</B> "; /* Description (long) */ item["Description"]+= "\r\rBreaks outline out into aligned blocks.";/* * description */ item["SmallBitmap"] = "HTML_ALIGN_OUTLINE"; /* * Check for Existing */ rc = MenuFindFunctionID(item["Code"]); /* Look for existing */ if (IsNotError(rc)) { /* Was already be added */ return ERROR_NONE; /* Exit */ } /* end error */ /* * Registration */ rc = MenuAddFunction(item); /* Add the item */ if (IsError(rc)) { /* Was already be added */ return ERROR_NONE; /* Exit */ } /* end error */ fnScript = GetScriptFilename(); /* Get the script filename */ MenuSetHook(item["Code"], fnScript, "run"); /* Set the Test Hook */ return ERROR_NONE; /* Return value (does not matter) */ } /* end setup */ /****************************************/ int main() { /* Initialize from Hook Processor */ /****************************************/ setup(); /* Add to the menu */ return ERROR_NONE; /* Return value (does not matter) */ } /* end setup */ /****************************************/ int run(int f_id, string mode) { /* Call from Hook Processor */ /****************************************/ int px,py; /* start pos of paragraph text */ int text_width; /* the width of the lead in text */ int ex,ey,sx,sy; /* positional variables */ boolean matches; /* if matches a replace pattern */ dword type; /* type of window */ string font_tag; /* font tag to write */ string content; /* content of an SGML tag */ string closetag; /* closing tag to write out */ string element; /* sgml element */ handle sgml; /* sgml object */ handle edit_object; /* edit object */ handle edit_window; /* edit window handle */ string text; /* closing element of sgml object */ /* */ if (mode!="preprocess"){ /* if mode is not preprocess */ return ERROR_NONE; /* return no error */ } /* */ counter = 0; /* reset counter from last run */ edit_window = GetActiveEditWindow(); /* get handle to edit window */ if(IsError(edit_window)){ /* get active edit window */ MessageBox('x',"Cannot get edit window."); /* display error */ return ERROR_EXIT; /* return */ } /* */ type = GetEditWindowType(edit_window) & EDX_TYPE_ID_MASK; /* get the type of the window */ if (type!=EDX_TYPE_PSG_PAGE_VIEW && type!=EDX_TYPE_PSG_TEXT_VIEW){ /* and make sure type is HTML or Code */ MessageBox('x',"This is not an HTML edit window."); /* display error */ return ERROR_EXIT; /* return error */ } /* */ edit_object = GetEditObject(edit_window); /* create edit object */ sgml = SGMLCreate(edit_object); /* create sgml object */ element = SGMLNextElement(sgml); /* get the first sgml element */ while(element != ""){ /* while element isn't empty */ if (IsError(element)){ /* if it couldn't read the element */ MessageBox('x',"Could not read HTML element, aborting."); /* print error */ return ERROR_EXIT; /* return error */ } /* */ if (FindInString(element, "<p", 0, false)>(-1)){ /* if the element is a paragraph */ matches = true; /* reset matches */ sx = SGMLGetItemPosSX(sgml); /* get sgml start */ sy = SGMLGetItemPosSY(sgml); /* get sgml start */ ex = SGMLGetItemPosEX(sgml); /* set sgml end */ ey = SGMLGetItemPosEY(sgml); /* set sgml end */ switch (matches){ /* switch on boolean matches */ case matches = test_nbsp(sx, sy, sgml, edit_object): /* try case 2 */ break; /* end */ //case matches = test_font_nbsp(ex, ey, sgml, edit_object): /* try case 1 */ //break; /* end */ default: /* if nothing happened */ SGMLSetPosition(sgml, ex, ey); /* set to end of item */ break; /* */ } /* */ } /* */ element = SGMLNextElement(sgml); /* get the next sgml element */ } /* */ CloseHandle(edit_object); /* close edit object */ MessageBox('i',"Found and modified %d paragraphs.",counter); /* messagebox */ return ERROR_NONE; /* Exit Done */ } /* end setup */ /****************************************/ boolean test_font_nbsp(int psx, int psy, handle sgml, handle edit_object){/* tests for spacers in font tag */ /****************************************/ int px,py; /* start pos of paragraph text */ int text_width; /* the width of the lead in text */ int ex,ey,sx,sy; /* positional variables */ string font_tag; /* font tag to write */ string content; /* content of an SGML tag */ string closetag; /* closing tag to write out */ string element; /* sgml element */ string text; /* closing element of sgml object */ /* */ SGMLSetPosition(sgml,psx,psy); /* reset to start of paragraph */ px = psx; /* store prior start */ py = psy; /* store prior end */ element = SGMLNextElement(sgml); /* get the next element */ while (FindInString(element, "<font", 0, false)<0 && /* while not a font tag */ element!="</p>" && element!=""){ /* and not at the end of P */ if (FindInString(element, "<a", 0, false)>(-1)){ /* if next element is an anchor */ SGMLNextElement(sgml); /* advance 2 times */ px = SGMLGetItemPosEX(sgml); /* get px */ py = SGMLGetItemPosEY(sgml); /* get py */ element = SGMLNextElement(sgml); /* advance 2 times */ } /* */ else{ /* */ break; /* if not an A tag, break */ } /* */ } /* */ if (FindInString(element, "<font", 0, false)>(-1)){ /* if the next element is a font tag */ sx = SGMLGetItemPosSX(sgml); /* start of font tag */ sy = SGMLGetItemPosSY(sgml); /* start of font tag */ content = ReadSegment(edit_object,px,py,sx,sy); /* get content of lead-in */ text_width = GetStringLength(content); /* get width of text */ content = SGMLFindClosingElement(sgml,SP_FCE_CODE_AS_IS); /* get the content of the font tag */ content = TrimPadding(content); /* remove leading / trailing space */ if (IsRegexMatch(content, NBSP_ONLY)){ /* check if font tag is only NBSP's */ SGMLFindClosingElement(sgml); /* move to close of tag */ ex = SGMLGetItemPosEX(sgml); /* end of font tag */ ey = SGMLGetItemPosEY(sgml); /* end of font tag */ font_tag = get_font_tag(text_width); /* get font tag to use */ if (font_tag!=""){ /* if we have a font tag to use */ WriteSegment(edit_object,"",sx,sy,ex,ey); /* remove font tag */ WriteSegment(edit_object,CLOSE_FONT,sx,sy); /* write close font tag */ WriteSegment(edit_object,font_tag,px,py,px,py); /* write begin font tag */ SGMLSetPosition(sgml,px,py); /* set SGML position */ counter++; /* increment count */ return true; /* return true */ } /* */ } /* */ } /* */ return false; /* return false */ } /****************************************/ boolean test_nbsp(int psx, int psy, handle sgml, handle edit_object){ /* test if only NBSP's in after leadin */ /****************************************/ handle wp; /* word parser */ int lct; /* lead in count */ int nct; /* nbsp count */ int sx,sy; /* startponits of paragraph content */ int ex,ey; /* endpoints of paragraph content */ int text_width; /* width of lead in text */ boolean is_tab; /* true if dealing with tab char */ boolean ended_lead_in; /* has lead in ended? */ boolean last_word_nbsp; /* was last char nbsp? */ boolean is_nbsp; /* is this char an nbsp? */ boolean underline; /* true if underlining */ string u_tag; /* underline tag */ string u_close; /* close underline tag */ string tag_type; /* type of tag to look for */ string font_tag; /* font tag to use */ string last_word; /* the last word ` */ string lead_in; /* lead in string */ string nbsp_string; /* nbsp_string */ string wp_word; /* parsed word */ string content; /* content of paragraph */ string new_lead_in; /* new lead-in wrapped in font tags */ string element; /* next element */ /* */ SGMLSetPosition(sgml,psx,psy); /* reset to start of paragraph */ element = SGMLNextElement(sgml); /* get next SGML element */ sx = SGMLGetItemPosEX(sgml); /* get end of P tag */ sy = SGMLGetItemPosEY(sgml); /* get end of P tag */ content = SGMLFindClosingElement(sgml, SP_FCE_CODE_AS_IS); /* get content of paragraph */ ex = SGMLGetItemPosSX(sgml); /* get start of close tag */ ey = SGMLGetItemPosSY(sgml); /* get start of close tag */ wp = WordParseCreate(WP_SGML_TAG,content); /* create parser for content of para */ wp_word = WordParseGetWord(wp); /* get next word */ while(wp_word!=""){ /* while we have a next word */ if (IsRegexMatch(wp_word,NBSP)){ /* test if nbsp */ is_nbsp = true; /* its a nbsp */ } /* */ else{ /* if it's not an nbsp */ if (wp_word==TAB_CHAR){ /* if it's a tab char */ is_tab = true; /* remember we've got a tab */ } /* */ is_nbsp = false; /* store value */ } /* */ if (IsSGMLTag(wp_word)==false){ /* if it's not an SGML tag */ if (!ended_lead_in){ /* if lead in hasn't ended */ if (is_tab){ /* if it's a tab character */ nbsp_string = wp_word; /* add char to space string */ nct = 5; /* counts as 5 spaces */ break; /* stop processing words */ } /* */ if (last_word_nbsp == true && is_nbsp == false){ /* if last word was nbsp, but not eoli */ lead_in = GetStringSegment(lead_in,0, /* remove extra space from lead-in */ GetStringLength(lead_in)-1); /* * remove extra space */ lead_in += last_word + wp_word; /* add last word and this word to string*/ text_width+=get_word_length(last_word)+ /* add last_word width to width */ get_word_length(wp_word); /* add wp_word width to width */ last_word = ""; /* reset last word */ last_word_nbsp = false; /* reset last word nbsp */ lct+=2; /* increment lead in counter by 2 */ } /* */ else { /* */ if (last_word_nbsp == false && is_nbsp == false){ /* if neither word was nbsp */ lead_in += wp_word+" "; /* add word to lead_in */ text_width+= get_word_length(wp_word); /* add length of word to word length */ lct ++; /* increment lead in word count */ } /* */ } /* */ if(last_word_nbsp == true && is_nbsp){ /* if this and last word were nbsps */ ended_lead_in = true; /* lead in is over */ nbsp_string = last_word + wp_word; /* store as start of nbsp string */ nct = 2; /* non breaking space count is 2 */ last_word = wp_word; /* store word as last word */ } /* */ if (last_word_nbsp == false && is_nbsp){ /* if nbsp but last word was not */ last_word = wp_word; /* store last word */ last_word_nbsp = true; /* remember last word is nbsp */ } /* */ } /* */ else{ /* if lead in has ended */ if (is_nbsp){ /* if it's a nbsp */ nbsp_string += wp_word; /* add to nbsp string */ nct++; /* increment nonbreaking space counter */ } /* */ else{ /* if lead in is over and not nbsp */ break; /* break out of loop */ } /* */ } /* */ } /* */ else{ /* if it is an SGML tag */ if (!ended_lead_in){ /* if still inside lead_in */ if (FindInString(wp_word,"<U")>(-1)){ /* if it's an underline */ underline = true; /* set underlined to true */ } /* */ } /* */ } /* */ wp_word = WordParseGetWord(wp); /* gets the next word */ } /* */ if (lct == 0){ /* if no lead-in */ return false; /* return */ } /* */ if ( lct <= MAX_LEAD_IN_WORDS && nct >= MIN_NBSP_AFTER_LEAD_IN){ /* if it meets criteria for lead-in */ font_tag = get_font_tag(text_width); /* get font tag to use */ lead_in = TrimString(lead_in); /* remove leading / trailing spaces */ if (underline){ /* if underlining */ u_tag = UNDERLINE_TAG; /* underline tag to write out */ u_close = UNDERLINE_CLOSE; /* underline close to write out */ } /* */ else{ /* if not underlining */ u_tag = ""; /* blank tag */ u_close = ""; /* blank tag */ } /* */ new_lead_in = font_tag + u_tag + lead_in + u_close + CLOSE_FONT; /* wrap lead in with new font tag */ content = replace_in_string(content,lead_in,new_lead_in); /* replace lead in */ if (content==""){ /* if nothing was replaced */ return false; /* return false */ } /* */ content = ReplaceInString(content,nbsp_string,""); /* remove nbsp's */ WriteSegment(edit_object,content,sx,sy,ex,ey); /* write segment out */ counter++; /* increment counter */ CloseHandle(wp); /* close handle */ return true; /* return that we did something */ } /* */ CloseHandle(wp); /* close handle */ return false; /* */ } /****************************************/ string get_font_tag(int text_width){ /* return appropriate font tag */ /****************************************/ string font_tag; /* font tag to return */ /* */ switch (text_width/CHAR_SIZE_THRESHOLD){ /* switch on width of lead-in text */ case (CHARS_SM): /* if small */ font_tag = FONT_TAG_SM; /* use small tag */ break; /* break switch */ case (CHARS_MD): /* if medium */ font_tag = FONT_TAG_MD; /* use medium font tag */ break; /* break switch */ case (CHARS_LG): /* if large */ font_tag = FONT_TAG_LG; /* use large font tag */ break; /* break */ default: /* if none of the above */ font_tag = ""; /* do not set a font tag */ break; /* break */ } /* */ return font_tag; /* return selected value */ } /****************************************/ int get_word_length(string test){ /* gets the length of a word */ /****************************************/ if (IsSGMLCharacterEntity(test)){ /* test if it's a character entity */ return 1; /* counts as 1 character */ } /* */ if (IsSGMLTag(test)){ /* if it's an SGML tag */ return 0; /* doesn't render, has zero width */ } /* return true */ return GetStringLength(test); /* return default length of word */ } /****************************************/ string replace_in_string(string data, string find, string replace){ /* replace the first occurrence in a str*/ /****************************************/ int begin; /* beginning of the replaced segment */ int length; /* length of segment to rpelace */ string front; /* front part of my new string */ string back; /* back part of my new string */ /* */ length = GetStringLength(find); /* length of segment to replace */ begin = InString(data,GetStringSegment(find,0,1)); /* find start of replace string in data */ if (begin<0){ /* if not found */ return ""; /* return nothing */ } /* */ front = GetStringSegment(data,0,begin); /* get front of new string */ back = GetStringSegment(data,begin+length); /* get back of new string */ return front+replace+back; /* return new string */ } /* */ #beginresource HTML_ALIGN_OUTLINE BITMAP { '42 4D 78 06 00 00 00 00 00 00 36 00 00 00 28 00' '00 00 14 00 00 00 14 00 00 00 01 00 20 00 00 00' '00 00 42 06 00 00 12 0B 00 00 12 0B 00 00 00 00' '00 00 00 00 00 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 B8 82 4D 00 B8 82 4D 00 B8 82' '4D 00 B8 82 4D 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 72 72 72 00 FF FF' 'FF 00 FF FF FF 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 72 72 72 00 72 72 72 00 72 72' '72 00 FF FF FF 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 B8 82 4D 00 B8 82 4D 00 B8 82' '4D 00 B8 82 4D 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 72 72 72 00 FF FF' 'FF 00 FF FF FF 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 B8 82 4D 00 B8 82 4D 00 B8 82' '4D 00 B8 82 4D 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 72 72' '72 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF' 'FF 00 FF FF FF 00 FF FF FF 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 CC 00 FF 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 72 72' '72 00 72 72 72 00 72 72 72 00 72 72 72 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 CC 00 FF 00 CC 00 FF 00 CC 00' 'FF 00 CC 00 FF 00 00 00 ' } #endresource
The MenuAddFunction function with these new parameters and a few resource statements make it easy to include menu/ribbon icons in your script. Customizing GoFiler this way adds another layer of usability and even a little graphic pizzazz to your Legato scripts.
Steven Horowitz has been working for Novaworks for over five years as a technical expert with a focus on EDGAR HTML and XBRL. Since the creation of the Legato language in 2015, Steven has been developing scripts to improve the GoFiler user experience. He is currently working toward a Bachelor of Sciences in Software Engineering at RIT and MCC. |
Additional Resources
Legato Script Developers LinkedIn Group
Primer: An Introduction to Legato