Click here to Skip to main content
15,867,488 members
Articles / word

the Wordinator - a Creative Writer's Word-Processor - C#2022

Rate me:
Please Sign up or sign in to vote.
4.96/5 (33 votes)
14 Aug 2021CPOL49 min read 44.7K   1.8K   46   28
In this article, you will learn about a word-processor that makes use of multiple dictionaries, pop-up definitions and an interactive multi-button picturebox expedited with a swift Sweep And Prune algorithm.
An easy to use tool dedicated to creative writing and composition.

 

Part I: How I Scraped Merriam-Webster's Dictionary

Part II: Merriam-Webster's Dictionary: Converting HTML to RTF

Zipped Dictionary Files 

Update : 2024/03/25 15h27Image 1

Introduction

I'm a writer. I write. Most of the time, I write software but every so often, I need to change speed and write a story, or even a novel. Anyone can use commercially available word-processors and do very well. I'm willing to guess that not many authors, aside from the independently-destitute like myself, build & test their own word-processors. Few spend weeks and months typing dictionaries into databases to incorporate them into their writing tools and none post articles about how they scraped Merriam-Webster's website to complement their hacking skills with a bit of prose.

What you're reading here today is the result of all that.

Watch a short editing video 

 

Background

Back when WiFi was not freely available in soup kitchens, internet cafés charged good coin to let you see the marvels of the information super-highway and librarians shushed you off after only one hour of working at a dusty old CRT screen chugging along their slow and overcrowded pipe, so scraping non-existing online dictionaries was a thing of fantasy.  Word processors could spell check but getting a definition required leafing through a heavy book at the frightening peril of getting a paper-cut.  So, if you wanted a word-processor to include a dictionary, you either packed your CD-ROM with what you could afford and wobbled from one app to the other while trying not to crash your 30MHz 386, or you just looked it up in grandpa's big-word book.  Unless you were hardcore enough to borrow a dictionary from the library and renewed it every three weeks while you typed each word entry into your PC, then saved them onto your crowded harddrive. Yes, yes, I think the word hardcore is appropriate, otherwise I'd have to resort to self-abusive language unsuitable for the non-TOR tip of the internet.

So, if you've read my previous article, Spell Weller but Grammar's Up to You, then you're probably aware of my affinity for spending 100s of hours, typing dictionary after dictionary, day-in & day-out, into my computer(this particular neurosis of mine is currently in remission and hasn't affected my day-to-day in over 14 years, thanks to my new 'scraping-hobby' and a semblance of a social life). It took me only six weeks to type the mediocre volume: Webster's New Explorer Dictionary. A dozen dictionaries and hundreds of typos later, I give them all to you, dear reader, for free. Just go to the web-link above to access them off my GoogleDrive


Since this app relies heavily on the files I scraped from Merriam Webster's website, please feel free to make a donation to them in thanks for their great work.


Installation

The app auto-detects the dictionary files and directories but you have to put them where they are expected to be found. 

If you want to use the dictionaries (main reason why you'd want this app in the first place)

You can either

  1. download a 'starter kit' of the most basic dictionaries (3x English Thesaurus and MW Dictionary) here.  Decompress the Wordinator.7Zip file onto your c:\ harddrive. (7Zip app required).  There are 100s of thousands of files to decompress, you might want to get a coffee, just let it do its thing.  
  2.  or create a directory on your hard-drive

C:\Words_Dictionaries\

Then download the dictionaries you want from my Google Drive and decompress them in the above directory.

N.B - as of 2023/07/21 - Heading List changes requires downloading file below

 ----> Heading List - Dictionary support Files 

When you're done, it should look something like this:

Image 2

Note to the Newbie

For those of you who wandered in here without a clue as to how to run a C# application, don't worry. It's a simple matter.

  1. Download the source code and extract it from the .zip file somewhere you'll know where to find it.
  2. Download Visual Studio 2019 from Microsoft and follow the instructions to install that essential Software Development Kit (SDK).
  3. Double click the fancy new icon that appears on your desktop.
  4. Select the 'open solution' button when prompted - or use the file-menu to open a 'solution'.
  5. Find the source-code you downloaded.
  6. Select the words.sln file and press ok.
  7. When it's loaded, you can
    • run the app in debugger-mode (slightly slower than the executable) by pressing F5
    • or, compile the application by pressing the Ctrl-Shift-B key-combination and then find the executable in the source-code's subdirectory c:/WhereverYouPutTheSourceCode/Bin/Debug/words.exe

The source code on offer here today for the low-low price of zip-nothing is the word-processor I wrote ten years ago that I used to write my fourth novel Cleats of the Counter-Revolution. I've worked on this app considerably since then and it's looking pretty good.

HUD - Heads Up Display

  As there are many commands at your disposal the HUD will help you find your tools when you need them, and then hide away when you don't. 

Image 3

Using the App

This word processor is a little different from most.  It's designed to keep your notes, chapters and stories organized.  Essentially, you create a 'project' and then add files that you write to your project.  All the files in your project can be accessed in the Notes-List tab and you can scroll through these, view and edit them in a text-editor.  When you select a note from the Project's Notes List in this way, the content of that file will appear in a Note-Editor

Image 4

The square button at the bottom left of the Notes-Editor (circled in green in the image above) lets you move the Notes Editor over top of the Main Editor to get a better view of it and its contents.  Clicking this button will move the Notes-Editor away from its normal location and will place it in front of (and hiding) the Main-Editor.

You can use the context-menu (right click your mouse over the Notes-List area) to add Headings (call them 'notes' or 'files').  When you do, a blue boxed area with a textbox will appear waiting for you to give this new 'note' a name or 'heading'.    For how to create a new file, read the 'Note-Pilot' section below.  Dispose of an editor by moving its tab into the trash bin.

Move Tabs Around

You can grab any tab and move it from one location to another.  To move a tab, make sure it is selected then, while holding the mouse down, move the tab to where you want to put it and release the mouse button over another region, or into the trash bin that will appear at the lower left of the screen.

Image 5  

Accents

Both the Notes-Editor and the Main-Editor allow the user to type accents into their text.  As of this writing the accents that are included are the main three french language accents

accent-grave           ì            (little hat to the left)

accent-aïgue           í            (little hat to the right)

accent-circonflex    î            (little hat proper)

To type in an accented vowel, the user need only precede the intended vowel with the character '\' (which is sacrificed by the app for this single purpose) and then follow this character with either the intended vowel or the QWERTY keyboard key located above or below that same vowel.  Once the app recognizes the two-character (e.g. "\e") combination these two characters are removed from the text and replaced by the appropriate accented vowel.  The key above results in Accent-grave (little hat to the left) and the key below produces the accent-aïgue(little hat to the right) and the vowel itself results in the accent-circonflex (little hat proper).

These codes are currently hard-coded into the software and can easily be changed in the classKeyboard 's instantiation method.

Editing

You can edit any file you're working on in an Editor by selecting the Note you want in the list of Notes and then, using the context menu in the Notes-List tab where you make that selection, click on 'Edit'.  Your story, note or novel chapter will then appear in a new Editor.

Quick-Editing

you can 'expand' your text such that each sub-clause is presented onto a separate line with the key command 

Shift-Alt + PageDown 

delete empty spaces & collate adjacent thoughts (two separate lines) with the key-combo

Ctrl + Delete

then move ideas up/down one line at a time with the

Alt-Shift + Up arrow

or 

Alt-Shift + Down arrow

When you've finished editing your text, use the command 

Shift-Alt + PageUp

and you're done.

 

Image 6

 

Polish Table

 

Image 7

Although you can do all your editing and never have anything to do with 'Polish Table' feature, you might want to have a look at this curio.  What the Polish-Table feature does exactly is allow you to edit your text in an alternate 'magnifying glass' editor and focus on one sentence at a time. 
The main editor's Alt-Shift + PgUp / PgDown keys already lets you work with 'expanded' text that can be 'collapsed' back into their traditional forms.  However, if you edit the collapsed text it will not remember the 'expanded' version and botched the 'expand text' operation for you.  Thankfully, to avoid this problem you can now edit in the Polish-Table editor.  

if you feel adventuresome and want to try the Polish-Table feature, its new and requires a four-point harness to strap in.  You might want to back up your work, and have a look at the EditRecall feature while you're here.  Its not exactly buggy or wonky but its so unusual a concept it needs explaining.  Your text is still in the Rtx editor saved as a microsoft RichTextFile (.rtf).  That concept doesn't change.  But your expanded verses (sentences that cover entire pages) are saved in a separate sub-directory in .xml files (xml documents with .Expand file extensions).  Each entry has a 'password' to access it.  All the 'passwords' are inserted into a binary-tree (data base) and when you select a new sentence in the main editor, if the 'password' is correct you get your 'expanded text' back.  

Ok, i put myself through this for no reason, sure but one has to suffer for their art.

Every time you 'Collapse' your text in the main editor, that 'expanded' text gets saved into the xml document mentioned above, each chapter of your work will have one.  And when you ask the editor (main editor) to 'Expand' your text (Alt-Shift + PgDown) it will look at your selected text, check if its the right 'password' and find the exact way  you expanded your text the last time you collapsed that identical sentence.  This will still happen even if you don't use the Polish Table. 

To get started with this feature, just press F10 and the main-editor's selected 'clause'(text with a box drawn around it) will be copied onto the Polish-Table.

pressing Ctrl-S, or clicking the 'save' button Image 8, while working in the Polish-Table, will copy your Polish-Table editor's changes back onto the main-editor. When you 'save' your work at the polishing table, it not only saves the text there but also changes the selected text in your main editor.   If the Polish-Table is 'Toggled' (red button) then every mouse-click on the MainEditor forces the user to edit the same text in the Polish-Table when it finds one.  

So you write a line.  Press F10 to create a new entry in your Polish-Table work area.  Work in the Polish-Table area to edit the contents of that one sentence.  If you want to break the sentence in two, combine two into one, your expand the relevant sentences in the main-editor, edit them there, then collapse them in the main editor.  Combining two into one will leave an unused entry in your list, while splitting one into two creates two new ones and abandons the old.  Either way, you can clean up the list with the Image 9 button which scans your file and deletes entries that don't have a matching 'password' in the main text.   

 Its still new, only a few weeks old.  I've been using it so its not too bad.  But remember that... if you load a different entry before saving your work, that work will be lost.  If you do save your work but the cursor in the main-editor was at a different spot your 'Collapsed Text' will overwrite the text selected in the main-editor, regardless.  Its like driving a stick when there was a crank under the hood, only the exhaust fumes are not as raunchy.

A great thing besides is that, on the Polish-Table, every line of your text gets to show off its curves.  You can see in the image above, that the main-editor is found below and the Polish-Table.  The idea is to disposition your text in such a way as to, not only add a little flare to its presentation, but also simplify the language by isolating collection of words like adjectives and the nouns they modify.  Hanging appositions off the edge, and sub-clause your columns.  It becomes easier to express complicated ideas, and convoluted arguments, by indenting the various sub-clauses of your text.  This approach mimics the file-folders common to most computers, or indentation that makes software legible at all.  

ok, so this is really just my thing.  but its still kind of cool, have a look at this Facebook post

 

 

Toolbar

Image 10

  1. Image 11is your word underline icon.   toggles on/off.  When toggled on, all words that begin with the same spelling as the word currently beneath the mouse cursor will be underlined.  Helps discover how many times you repeat yourself.
  2. Image 12 is your CopyCutter icon - toggles on/off a data-gathering tool convenient when doing on-line research CopyCutter automatically inserts text 'copied' to Windows ClipBoard.  When toggled on this icon turns red Image 13 and can be set to automatically shut off after a period of time when left unused.  see below
  3. Image 14the WordColumn Tab feature, is great for poetry line dispositions and allows you to select multiple lines of text and move them as a block without altering their positions relative to each other.  F5 to toggle on/off.
  4. Image 15Text Encapsulator feature toggle - draw a box around the currently selected text.  The text encapsulated is defined by the selected clause capture type selected
  5. Image 16Defined Words feature toggle - sets the user current selected text start value to words in a list triggered by a user's mouse-move over (without a mouseclick)
  6. Image 17 Image insert 
  7. Image 18debug - its only rumoured to exist 

Tool bar's other UI 

Image 19

you can quickly scroll through the different user defined highlighting forecolor / backcolor combinations for your creative writing.  Located at the top right of the Editor's tool-bar, this feature currently has two functionalities : Clause UI or Font UI and can be set via a mouse-click on the left edge column of reactive buttons.  

Clause UI - clause type can be selected by clicking the right column of buttons.  Using the mouse wheel over the center of the clauseUI will scroll the highlighting of the text located beneath the cursor : word, subclause, sentence, paragraph or verse.  Scrolling over the clause type selector column to the right in similar manner to scroll the highlight clause type under the mouse wheel and not alter the type of clause the user has selected  (unless you do it too quickly then you're on your own)

Font UI - the textbox's ZoomFactor is displayed here.  User can zoom in/out with a mouse-wheel.  Or reset Zoom to 1.0 with a mouseclick.

Double-mouseclick anywhere 'not a button' is equivalent to a Ctrl-Delete key stroke.

 

Images inserted into the text 

It turns out adding a lot of images into your document takes up a lot of memory.  This came to a crisis for me last week when I tried to build a project around a scraped and OCR'd Perlego textbook.   I was inserting every table, image and postcard I found and fattened my document so much the app collapsed, had a seizure and quit the league.  

So now the images you insert, either via Ctrl-V or Image 20 tool bar button, gets copied to the HD in your project's Images subdirectory.  The images are no longer found in the Rtf, to the great relief of my CPU that can't manage excessively large files. 

(For best results you should keep your individual 'chapters' below 4000 words.)

The app sticks a text marker in your work that looks like  (*+-]1[-+*), where the '1' is an internal ID number which tells it what its dealing with.  Change this code and the app has no idea you want an image there.  It makes no attempt to reposition your text around it, that will come later, but now I have a new Textbook on Principles And Applications Of Agricultural Meteorology and learning about Climate Change with an interactive Textbook.  Awesome. 

 

The example below (text from the National Post - Scams on Steroids article (20240303)

 

Image 21

Image 22

Image 23

Image 24

Image 25

Image 26

Image 27

 

N.B. - you can't currently copy these images from one note to another.  If you paste the image into your text it will generate a 2nd, 3rd .. identical file in the Image directory, to avoid this you can use the ToolBar ImageInsert button Image 28 to tell it which file to insert(which is drawn on the Rtx mentioned above).   I'm working on an improvement. 

 

 

Word Column Tab

F5 toggles this feature which allows you to grab entire blocks of poetry and move them as a unit without disturbing their positions relative to each other.   When toggled on, the text-area's back color will change to a nauseating orange, if you can still hold your lunch through this troubling experience, use the mouse to select the area to the left of the text your want to move.  A vertical red line will appear to the right of the area you've selected.  You can then slide the text sideways by grabbing the red line with your mouse.  

Image 29

N.B.  the ruler settings for your text need to be set to zero (as shown in the top-left red circle of the image above)

N.B.B. - its mostly bug-free.  if it looks wonky ... press Escape and start again. 

N.B.B.B. - the truth about peanuts, and their lies, must be taken with a grain of salt 

Image 30

 

Right mouse click over the Highlighter label and the following groupbox will appear

Image 31

You can see in the image above that there are 9 color combinations with their Titles listed in the Highlighter Color Sequence Editor.  When you scroll through the colors, the editor will select the next valid entry in your sequence along the scrolling direction and alter the color of your selected text.  You can toggle off/on any of these selections by clicking the check-box to the left of each color.  To change the colors, simply use the context menu over the textbox of the color your want to change.

Word Shift

You can slide the word currently under the cursor either forward/backward in the text with the Ctrl-Shift-Alt Right/Left arrow key combinations. 

Copy Cutter

Copy Cutter is a great on-line research tool.  Either RichTextBox will allow you to toggle the CopyCutter feature independently by either clicking the CopyCutter the ToolBar icon Image 32 or through the context menu.  When toggled on, Copy Cutter's ToolBar icon will turn red Image 33 and check the content of MicroSoft's ClipBoard once every second.  When it does, it will paste any new text or image it finds there into the RichTextBox as if you had Pasted it there yourself.  This way, you can select text on a web-site and copy it into the MS-ClipBoard (either by Ctrl-C, Ctrl-X key combinations or with the context menu's 'Copy' menu item) without ever returning to the Word app itself.  Just read, highlight and copy.   Entire Wiki page, Project Gutenberg eBooks or news articles can be quickly summarized into your project's research notes using this feature.  Every item found in the ClipBoard is inserted on its own line with a leading hyphen.    Highlight or indent, at your leisure.

Copy_Cutter-Auto-Shut-Off feature is found in the Main Editor's context menu Options described below.  A delay period can be programmed for the Copy-Cutter feature to automatically shut itself off if left unused for too long.  

While CopyCutter feature is enabled, it will disable the selected UseClipBoard dictionary.

Image 34

You can access the CopyCutter options through the regular options menu (right-mouse click for ContentMenu and select 'Options') by clicking the 'Copy Cutter' button near the bottom of the Options Menu.

Reader

The Reader option can be toggled on/off from the RichTextBox's context menu.  When toggled on, user-input will be limited to the arrows, Home and End keys and will not allow any editing to be made to the text.  Wherever you move the the cursor, the app will highlight the entire line of text which should help you deliver public readings without skipping a line or repeating yourself.  When your thumb isn't there to help you direct your eyes to the next line this highlight-the-text-as-you-reading feature can be handy.

 

Definition Tracker

The Definition Tracker allows you to scroll through all the word entries in a selected dictionary.  If you use the context-menu here you'll see a list of the Dictionaries you have installed on your computer.  Choose a selection and that Dictionary's entire list of Headings will appear for you to scroll using the MouseWheel.  When you type in the Main-Editor the Word-List will automatically cycle to the word that matches nearest in spelling to the text under the cursor when you pause in your typing.  This may help you find words you're not sure how to spell, like 'hemorrhage', which I still can't spell right, even after typing the entire Medical Dictionary! 

Image 35

N.B. alt-spellings require latest MW Dictionary.7zip after 2022/10/30

While typing in the Main-Editor you can use three fast-keys to control the Headings-List

  • Ctrl-Alt- A  scroll-up
  • Ctrl-Alt- Z  scroll-down
  • Ctrl-Alt- Q  insert selected heading from heading list into your text

The Word-List files can be downloaded from the the link at the top or from here.  Each one of the files in this compressed download contains one dictionary's Word-List files.  And each Dictionary expects to find its own Word-List files in its own directory.  However, if you decompress the lot into the C:\Words_Dictionaries\ directory then the app will find them there and copy them to where it needs them to be.  If you download the Source-Code without adding these files to the C:\Words_Dictionaries\ directory then the app will generate a new copy for you whenever you select a dictionary Word-List which hasn't been used before ... but these can take some time to build.  The smaller dictionaries only take a minute or less, but some of the bigger ones can take up to an hour.  You can watch it work while you have your coffee or you can just download them... either way works.  

If you let the app build its own Word-Lists(alpha & reverse alpha), its best to let it finish once it has started because if it initializes the final output file without completing the task, the next time you launch the app, it will detect the presence of that file, assume its been completed and work with what it has without telling you that there is a problem(the data is incomplete).  Should this happen, exit the program and go to that Dictionary's main sub-directory, e.g. in the case of MerriamWebster's English Dictionary go to 

C:\Words_Dictionaries\MWENDict\

using your Windows Explorer and delete the half-completed file

C:\Words_Dictionaries\MWENDict\HeadingList.fil

then launch the app again.

Image 36

Dictionary Searches

N.B. Dictionary Searches are different from the Note Heading Searches as explained below.

You can program the app to search any combination of dictionaries you want by going to the main menu bar near the top and select Dictionary Selection.  When you do, the Dictionary Selection form will appear as shown below.

Image 37

As you can see from the image above, all the dictionaries are listed on individual panels.  Each of these panels can be scrolled left/right with the scroll bar at the bottom.  For each panel, you have the option to toggle on any, or all, of the available dictionaries.  Each dictionary can be either set to search only the Heading of a word entry in the dictionary, the content of its definition, both the Heading and the Content or not at all.   You'll notice that the Rhymer.com dictionary is missing two buttons, this is due to the fact that its a really awesome dictionary and does not require a content-search since the heading list is exhaustive.  The Key-combination you want to assign for each of these panels is printed at the top and, although the Ctl-Shift keys are common to all of these panels you can program which letter-or-number you want to combine with these to summon that particular search.  In the image above you can see in the first panel on the left that the Merriam-Webster's English Dictionary matches its Heading search with the Ctrl-Shift-W key combination.  So, whatever word is beneath your cursor in either of the editors, you can search for it's definition in the Merriam-Webster's dictionary by making this key-combination.  You can create new panels using the Add button near the top of this form or delete any panel with thae Delete button located at the bottom of the panel you wish to delete.

There are two other buttons at the bottom of each panel besides the Delete button.  Both of these buttons are toggles.

  1. Use Clip Board - when this is toggled-on, any other panel with this same button toggled-on will have its button toggled-off, and the most recent selection will be used for the 'Use Clip Board' feature.  This feature allows you to highlight text from a web-browser, other word-processor or any Windows environment when you Copy selected text(either with the mouse or the Ctrl-C or Ctrl-X key combinations) into Microsoft's 'clipboard' memory space.  The app will test the content of this memory once every second, and if it finds new text there it will then run that text through the selected panel's search and pop-up the results as if the Ctrl-Shift-Key combination for that panel had been pressed over that word in the editor's work area.  Both the Use-Clip-Board and the CopyCutter options use the same MS-ClipBoard test and will not search the selected dictionary if the CopyCutter feature is enabled.
  2. Pop-Up Reference - the selection of the Pop-Up-Reference toggle button is similar to the Use Clip Board.  The Pop-Up Reference feature, however, applies to the Dictionary output form, which I will talk about further below.  When this feature is enabled, letting the mouse hover over a word in the Dictionary Definition Output textbox tells the selected dictionary to search the word resting beneath the mouse and provide its definition in a pop-up window.

You have the means of setting a delay time for the pop-up definition to appear when the mouse hovers in the Dictionary Results text box. In the Dictionary Selection form shown below, there is a 'PopUpDelay Time' button near the top.

Image 38

When you move the mouse cursor over it, a listbox appears providing you with option settings.

Image 39

You can set the delay time required for the mouse to hover motionless over a word (in the Dictionary search result textbox before that word's definition Pops-Up. Clicking on a word in the Dictionary Result Text Box will still launch a search for that word and the results will appear as a regular word-search but, alternately, if you selected the last option 'Right-Mouse Click', that word's definition will appear in a 'Pop-Up' window(as if it were a hover search) leaving your original search results intact rather than generate an entirely different search and search results.

This can be handy when you're searching through lists of rhyming words from the Rhyming dictionary or lists of synonyms pulled out of a thesaurus. The word you're looking at in the definition may look and sound good for where you are in your creative writing but you may not be certain of its definition, having this pop-up means of quickly getting that word's definition can be a real time saver. Might spare you the embarrassment of shamelessly abusing your readers by rhyming euphoniously but not getting your meaning across, if you know what I mean.

 

 

Search Results

Image 40

MultiPanelSearch_Sequential 

You can tell the app to find thesaurus entries to all the words in a sentence of sequence of words with the Ctrl-Shift-Q key combination.  The number of words it will search is limited by the number of Definition Ports(described below) you have opened, and they will search for their given word in whatever dictionary each specific DefPort search last.  To help ease your thesaurian endeavours, it will ignore any short common words in your sentence that are found in the list of QuickInsert words above the DefPorts.  

MultiPanelSearch_Single

this command is similar to the MultiWordSearch_Sequentiel, with the difference that it will search the same one word found under the user's cursor in all of the DefPorts.  This is convenient if you have three different thesauruses and to search the same word in all of them.  Ctrl-Shift-W - (next key over to Q).

Default MultiPanel Search dictionary selection 

   the dictionary selections that will appear when you make either MutiPanel Search Single or Sequential can be set using the context menu at the top edge of the list of defPorts.  Set the number of panels you want, select their respective dictionaries to your preferred settings, and when you are satisfied with your choice, move your mouse over the top edge of the defPorts list and the right-mouse will produce a context menu.  both lists are independent from each other, so you can have 3 different thesauruses for single-word searches AND 5 defPorts with your bestest dictionary in all of them when you're doing a wow-dazzler five-word she-bang.

 

Double-clicking any word in your text will launch a MultiWordSearch - if the user's cursor is found in the second half of the word being clicked, the app will execute a MultiWordSearch_Single and, alternately, MultiWordSearch_Sequential when the cursor is over the first half of the word.

 

While in either editor's work area, you can use any of these key-combinations to manipulate the Dictionary Results Form.

  • Ctrl-Shift-Z scroll down the list of results
  • Ctrl-Shift-A scroll up the list of results
  • Ctrl-Shift-X deletes all copies and removes them from the screen
  • Ctrl-Shift-S delete most recent search result

You can left-click on a word in the panelDefinitionNavigator and summon that word's definition in the same dictionary where the current definition was loaded.  Three navigation buttons

  1. ¤ home
  2. < back
  3. > forward 
  4. X delete this Definition Navigator

can be used to cycle through the definitions that particular panelDefinitionNavigator has provided.

 

N.B. the Dictionary Search Result fast-keys to scroll up/down are identical to the Heading-List scroll up/down insert text commands and the Highlighter scroll up/down.  They all Scroll-Up on key-press 'A' and Scroll-Down on key-press 'Z' where 

  1. Search             Ctrl-Shift          + A/Z
  2. Heading List   Ctrl-Alt             + A/Z
  3. Highlighter     Ctrl-Shift-Alt    + A/Z

    - and you could always call up the HUD by pressing F9

Rhyme Dictionary

There is a separate RhymeDictionary that is set apart from the list of dictionaries seen above.  The Rhymer.com dictionary you may have downloaded off my GoogleDrive lists far too many words that only have a single trailing syllable in common with the word  you're trying to rhyme and forces you to sift through thousands of words that really don't rhyme so well.  To fix this I made an app which uses a Ternary Tree to help reduce the number of useless rhyme words.  You can read about that app and download it to use separately in its own Rhymes article on the CodeProject website.

Since the database it uses to run is 100MB, it is larger than the CodeProject website's file size limit of 10MB.  You can't download it and you don't need to do anything to have this feature because Words will generate the needed database in the background the first time it discovers it isn't there.  It will put messages on the form's top-left banner informing you of this and will only take 15-20 minutes to complete.   This happens in the background so your writing experience will not be affected by this work.  When it is ready, the final message on the form's top banner will briefly inform you and you will then be able to use it much in the same way you might use any of the other dictionaries by pressing the key combination Ctrl-Shift-R.  The results will appear in the same type of DefinitionPilot box as the other searches but will not allow you to navigate from definition to definition with it. 

 

Words Never Searched

Image 41

Below the list of Search results and above the definition ports is a region that holds any number of buttons.  Moving your mouse over these buttons you will notice the cursor changing for three regions equally divided from left to right regions of its surface.

these are :

  1. Image 42 - to insert this 'word' into your text
  2. Image 43 - to swap this 'word' for the word selected in your text
  3. Image 44 - to discard this button

If you look at the list above you'll notice most of them are all common words you'll find in most fiction.  The 'cleric' option, however, is a little unusual.  I created it because I have a priest in my novel who plays a central role in the sly-maneuvering happening to the rest of the characters.  This button is convenient, not to insert 'cleric' into my text but to summon the 'cleric' thesaurus entry and select other synonyms for this word.  Similarly for words like 'reply' and 'say' or 'call'. 

In this way editing can sometimes feel like you're playing a videogame...  You can use the mouse to make changes while you're sipping your coffee.

These buttons are created via the text editing area's context menu 'Words Never Searched'

 

WordAnalyzer

The WordAnalyzer is located below the Notes on the Notes region.  This tool provides you with a list of all the words you have written in your text so far and keeps track of how many times they each appear.  This can help you notice if you're using too many instance of an uncommon word so you can better choose alternate synonyms from your thesaurus.  You can reorder the list alphabetically or by their count by clicking the Alpha & Count buttons on the upper left.  The Word Analyzer will follow along while you type and only lag behind you half a second before scrolling the list to the word beneath the mouse cursor the moment you stop typing.  It counts the words every time you stop typing so its always up to date and the numbers at the top reflect the number of unique words (left), total number of words (right) and the ratio of unique words overall as a number between 0.0 and 1.0.  

To the right of this information is the Search Textbox(this is where the WordListView_Search button copies a selected word from a search result), you can type in this textbox and the Word Analyzer will scroll down to it if it is found in your text, or scroll to the word nearest to it alphabetically.  By double clicking on a word the app will do a word-search in your text and select the next instance of that word for every time you double click it on the list.  

When you switch from one Editor (alt or main) the Word Analyzer will automatically analyzer the text of the newly focused RichTextBox.

The Lock (not seen in image below) allows you to redraw the WordMap for the same 'locked' word while editing the text.  When unlocked the selected word would be changed as the user edits the text and a new word-map will be drawn for the word currently under the text-editing cursor.

Image 45

Defined Words

Image 46 icon on the ToolBar 

The Defined Words feature lets you move the mouse over the text(with shift-key pressed) and the cursor will find the selection, telling the DefinitionTracker to jump to and find you, and your audience, that definition.... pronto. 

 

Note Pilot 

Image 47

Notes in your Words app are bits of data stored in your project file.  These bits of data have information like:

  1. Title
  2. Point of View (POV)
  3. Chapter Number
  4. Year/month/day - Hour & Minute 
  5. location of the RichTextBox on your harddrive (optional)

You'll notice that option (5) 'location of the RichTextBox on your harddrive' is optional.  This is because these 'bits of data' in your project file are not actually writing projects when you first create them they are only containers with the option of referencing a specific file you can write to.  This may seem strange but it allows you to organize your information in these separate folders. 

Your project can have sub-folders with 

  • chapters
  • character descriptions
  • historical information
  • technological research
  • outlines

and anything else you can imagine.  You can move from one 'folder' to the next by either moving 'up' to the parent folder (display its parent list such that the current folder is shown in the sub list) or move 'down' into one of the options in the Notes list by double clicking a selection.  the up Image 48 and down Image 49 buttons let you move the current selection (black file) up/down inside its list.  There is no possibility to move out/into a different folder at the moment so the existing files are stuck where they are unless you press the context menu's Note Delete button to remove it from its current 'folder' and then navigate to the folder you want to move 'up' one directory by clicking on the "<<<<< [dir name]" label at the top or click 'into' a folder by double clicking it in the Notes List below.  in a way similar to using Microsoft's Windows File Explorer.

This may seem complicated and counter-intuitive but I use it extensively and its great.   

Use the content menu (right mouse over Note Pilot) - you can create a folder (note) and it will become a 'note item' or 'bit of data' in your project's file.  This information will tell the app that your 'folder' is also a file and that file will load when you select it in the list of Notes at the top left of your screen. 

 but its still only just a 'folder' until you click on the Image 50 you will tell Words that you intend to use this Note as an actual file to write your short-story, notes, research or outline into.  The icon you clicked will then change to Image 51, the Path label to the right of it will no be enabled (you can click on it, see below), the a RichTextFile will be created on your harddrive in the location pointed to in the Path to the right of the check box. 

You can edit the note's title, POV or date/time info by selecting the note (left mouse click) then right-mouse over the region you wish to edit and an editable UI text box will appear.

The Title of your Note will be the name of the file.  When you change your Note's Title it's corresponding file (if it has one) will also be changed.  You can relocate the file inside Words by clicking the path on the right and telling the app where to put it but if you move your file externally (using Windows Explorer) your project will not know where to find it and you won't be able to edit it anymore. (your best option is to find it and put it back or delete the note from your project and create a new one).

I think I'll get around to making a video to better explain how to use the Notes and NotePilot but... that'll have to wait for another time.

You can edit notes information by pressing down on the right-mouse button over a field you wish to edit.  Date fields are separated by a right-slash (year/month/day) and the time requires a colon between the Hours:Minutes - don't use characters the Windows OS will refuse in a file name when editing the Title of your chapters (notes) ... and you're good.

Note Heading Search

You can search Notes Headings for specific articles or chapters to read, refer or edit.  

Ctrl-Shift + F1   - Search word under cursor

 

Image 52

The search results can be found in your project's Root, along with the Backup Files explained below.

 

Word Suggestion

The word suggestion was something I was requested to build for a separate project Dlús : Irish Language Word Processor.  As it was so easy to implement I went ahead and used that code to include it here.   It does what its name implies - suggest words as you type.  The words it suggests are taken from your text and will only offer those that begin with the same spelling as the word you're currently typing.  This feature is relatively common and easy to use, just press the up/down keys on your keyboard to make a suggestion and then tab to insert the word into your text.  Most of the time its not all that necessary but if you have a character in your novel with an oddly spelled or unusually long name, this can help you spell it the same all the time.

Good for the two-finger typists too.

Image 53

Memory Restore

Since the average high-school math calculator has Memory/Recall settings you may feel comfortable with the Words' Memory Restore feature which is very similar to what you had in high school ...  except it is used to store/recall text instead of numbers.  

Image 54

Memory Restore is similar to your pocket calculator's Memory-Store & Memory-Recall functions but with unlimited memory in up to 10 different folders.  You can easily sort your work into whatever categories you want then use it later, using the [Alt]+[0-9 digit keys].  The text you've saved will be stored in the MemoryRestore folder you've keyed in, e.g. alt-3 to store the selected text in Memory Folder #3.   Use the textbox to change, edit or re-dub your memory 'call-sign'.  This text will appear on the HUD panel when you hold down the Alt key.  Since each memory cell (0-9) can store as many text clippings as you like, you can use the scroll bar at the right of the text. 

Novel Formatter

The NovelFormatter tab will format your PolishTable work in real time. 

You can also format your novel into a single Rtf of Pdf document, via the button at the bottom left of its window.  Formatting options allow you to include (or leave out) the different components of chapter heading information : Chapter Number, Title, Date, Time & POV, and their respective fonts. 

N.B. the PDF ZoomFactor is copied from the user's main chapter editor, and the page size is measured from the NovelFormatter's tab size.  

Map Feature 

You can add images to help you write your project using the Map Feature.  

Image 55

AnimationEditor 

You can create 'animations' using the AnimationEditor.  These animations are attached to the PolishTable Entry loaded.  

Image 56

Image 57

Options 

F3 - toggles the Options panel's visibility 

 Image 58  

You can access the options panel using the main editor's context menu and click on Options menu item.

The interface is user-friendly and intuitive although the options themselves may not be self-evident.  Here are some quick notes to help you figure them out.

  • Word Suggestion - when toggled on the app will suggest words that are already in your text and begin with the same spelling as the word you're currently typing.  Press up/down arrows on your keypad to make a selection and tab to insert the word into your text
  • Rtx Message Scrolling - is a toggle option which, when toggled on the app will scroll messages on the user's working area
  • Copy Cutter Auto Shut Off Delay - Copy Cutter can be programmed to automatically shut off when it is unused for a given period of time.  The settings available are 1, 5, 15, 30 or 60 minutes before Copy Cutter automatically disables itself.  You can disable the Auto-Shut Off feature by setting this option to Never
  • AutoSave - is a toggle option which, when set to true, your main working area will be automatically saved every five minutes and overwrite the file it was loaded from.  Very convenient, if that's what you want.
  • Backup Time Period - determines how frequently the current editor is saved in a separate backup-file
  • Backup Files Total Number - limits the number of separate back-up files are kept - these back-up files can be accessed by the user at any time by back-stepping (Left Arrow in the Note Pilot) to the root 'directory' and then double click the 'Back up' notes.

You can access the CopyCutter options by clicking the 'CopyCutter' button at the bottom of the Options list. 

Options - Features

The features controls determines which of the app's feature 'tab pages' are available to the user, like Rhymish or Encryption.

Image 59

User password 

you now have the option to 'log out' - this lets any user 'tinker' with your writing but none of the changes will be saved to the file until you log back in.  Use the right-mouse button's context menu in the main editing area to log-out, or display the login prompt later.  

If you forget your password - you could exercise your coding craft to undigest the encrypted passwords with the source-code provided.  

or ... you could go to the same directory where the executable is found and delete the encrypted text file.    it has the same 'filename' this scheme has for my 'Latin Project' article 

                                    "PassivePeriphrastic.txt"

the Code

MultiButtonPictureBox

The classMultiButtonPic is essentially a picture box with rectangles mapped out onto it that your user can interact with using the mouse cursor.

Image 60

Everything beneath the 'add' & 'hide' buttons (except the textbox with the 'W') are buttons drawn on a common picture box. The Ctrl 'button' is the only one that doesn't interact. The rows of four '¤' set the selected search style for each dictionary. There are also three buttons at the bottom 'Use Clip Board', 'Pop Up Reference' & 'Delete'. The response time is great. Each button can be set to toggle independently from the others and the widget's internal mouse events can be overwritten in order to use these buttons like they were radio-buttons on a common panel.

Here's the Mouse-click event inside the multi-button:

C#
//

MouseEventHandler _eventHandler_MouseClick;
public MouseEventHandler eventHandler_MouseClick
{
  get { return _eventHandler_MouseClick; }
  set
  {
    if (_eventHandler_MouseClick != value)
    {
      if (_eventHandler_MouseClick != null)
        MouseClick -= _eventHandler_MouseClick;
      MouseClick -= Event_MouseClick;

      _eventHandler_MouseClick = value;
            
      if (_eventHandler_MouseClick != null)
        MouseClick += _eventHandler_MouseClick;
      else
        MouseClick += Event_MouseClick;
    }
  }
}

virtual public void Event_MouseClick(object sender, MouseEventArgs e)
{
  if (cButtonUnderMouse != null)
  {
    if (cButtonUnderMouse.CanBeToggled)
      cButtonUnderMouse.Toggle();
  }
}
//

by setting the MBP (instance of a classMultiButtonPic) _eventHandler_MouseClick to an event in your app, that event will override the MBP's mouse click event. Here's how it happens in this app:

The event is set in the panelSelectDictionary class:

C#
//
cMBP.eventHandler_MouseClick = cMBP_HTMLTagList_Click;
//

Then the event itself takes over the job of toggling what needs to be toggled in order for groups of buttons to be mutually exclusively toggled (like radio-buttons on a common panel) in the case of the search-type rows of buttons next to the names of the dictionaries.

C#
//

private void cMBP_HTMLTagList_Click(object sender, EventArgs e)
{
classCK_Objects.classMultiButtonPic cMBPSender = (classCK_Objects.classMultiButtonPic)sender;
classCK_Objects.classMultiButtonPic.classButton cBtn = 
   (classCK_Objects.classMultiButtonPic.classButton)cMBPSender.cButtonUnderMouse;
if (cBtn != null)
{
  if (cBtn.Tag != null)
  {
    classButtonArray cBtnArray = (classButtonArray)cBtn.Tag;
    classBinTrees.classDictionary cDictionary = cBtnArray.cDictionary;
    int intIndex = cBtnArray.lstButtons.IndexOf(cBtn);
    if (intIndex < (int)enuSearchType._num)
    {
      cBtnArray.eSearchType = (intIndex >= 0 && intIndex < (int)enuSearchType._num)
                        ? (enuSearchType)intIndex
                        : enuSearchType._num;
      for (int intBtnCounter = 0; 
                intBtnCounter < (int)enuSearchType._num; intBtnCounter++)
      {
        cBtn = cBtnArray.lstButtons[intBtnCounter];
        cBtn.Toggled
            = cBtn.Highlight
            = intBtnCounter == intIndex;
      }
      cMBPSender.Refresh();
      if (cBtnPopupReference.Toggled)
        formDictionarySelection.instance.pnlPopUpReference = this;
    }
  }
  else
  {
    panelSelector.enuTypeButton eButtonType = (panelSelector.enuTypeButton)cBtn.obj;
    switch (eButtonType)
    {
      case panelSelector.enuTypeButton.UseClipBoard:
        {
          cBtn.Toggle();
          if (cBtn.Toggled)
          {
            for (int intPnlCounter = 0; intPnlCounter < 
                       formDictionarySelection.instance.lstPnlSelector.Count; intPnlCounter++)
            {
              panelSelector pnlSel = 
                           formDictionarySelection.instance.lstPnlSelector[intPnlCounter];
              if (pnlSel != this && pnlSel.cBtnUseClipBoard.Toggled)
              {
                pnlSel.cBtnUseClipBoard.Toggled = false;
                pnlSel.cBtnUseClipBoard.Highlight = false;
                pnlSel.cMBP.Refresh();
              }
            }
            formDictionarySelection.instance.pnlUseClipBoard = this;
          }
          else
          {
            formDictionarySelection.instance.pnlUseClipBoard = null;
          }
          formDictionarySelection.instance.TmrClipboard_Set();
        }
        break;

// some cases deleted for brevity

      default:
        {
        }
        break;
    }
  }
}

//

In the case of the UseClipBoard button, it needs to look at other panels to make certain that no two panels list dictionaries to be searched whenever your user copies text onto the MS clipboard (which is convenient for use outside this word-processor, e.g., while in your web-browser).

panelSP - a panel with scroll bars

The Dictionary Selection form and the Dictionary Output form's list of 'copied' results both use the panelSP class that includes a pair of scroll bars on a regular Windows panel. It is a convenient way to display objects because you can add as many panels onto it (presumably with other objects on each panel) in as large an internal area as you like.  The way it works is by adding panels to it the panelSP will provide you with a SweepAndPruneElement (I'll call these spEle's for this explanation). You can then set the location of each of these spEle's anywhere you want and the panelSP will make room for them in its internal imaginary space called recArea.  The panelSP has another rectangular property call recVisible. This recVisible is the same size as the panel on your screen but its location will vary with the values of the scroll bars. By sweeping the scroll bars the user is telling the panelSP which region of its recArea is to be displayed on the screen and then panelSP figures out which of your panels (spEle's) should be visible and then it will position those MS Panel objects where they are supposed to be on the screen given the scroll bar values. The panelSP allows you to group many objects (as long as they're contained in an MS panel) onto it and will provide the user with scroll-bars to see all those objects. You, as a programmer, never set the panel's location (resize it all you like) but rather position it in the panelSP's imaginary recArea and that data will inform the panelSP as to what needs to appear on the screen given the user's scroll-bar values. 

Sweep And Prune

The Sweep and Prune algorithm is implemented as its own class and can be used with any kind of objects from characters in a string (just set the Y value to a constant and use the character index as X) to a map of the cities in Britney Spears's World Tour. You create elements, define their regions and add them to the map. Then when you ask it 'what is under Point(x, y)?' it spits-up whatever you've got hiding under there. Here's a good article to help you understand the algorithm.  Both the MultiButtonPic class and the panelSP class, as well as the SPObjects class all use similar Sweep and Prune algorithms to keep track of the objects they are handling.

Defined Words

The user interface to quickly find and draw, then detect Defined Words that appear under the mouse cursor requires five steps 

  1. build and sort a list of all indices where each Defined Word appears in the text 
  2. when user scroll/text changes settle - evaluate start/end indices of visible text 
  3. select from sorted list - those word entries appearing on the screen 
  4. create a Sweep and Prune map of area on screen to find those words
  5. mouse-move event handler quizzes SP map and sets RTX.Select() to word triggered 

1) Build and sort list

it scans the text for entries of the user's list of words then matches them with the Index at which they were found and put in a list.  This list is then sorted by ascending Index values.

public static void ResetToRtx_to_Rtx()
{
    Clear();
    if (rtx == null) return;
    string strValidChar = "'-";
    using (RichTextBox rtxTemp = new RichTextBox())
    {
        rtxTemp.Rtf = rtx.Rtf;
        rtxTemp.SelectAll();
        rtxTemp.Text = rtxTemp.Text.ToUpper();
        foreach (string word in lstWords)
        {
            int intFind = rtxTemp.Text.IndexOf(word);
            while (intFind >= 0)
            {
                char chrBefore = (intFind > 0 ? rtxTemp.Text[intFind - 1] : ' ');
                char chrAfter = (intFind + word.Length  < rtxTemp.Text.Length -2) 
                                                        ? rtxTemp.Text[intFind 
                                                                    + word.Length] 
                                                        : ' ';


                bool bolBefore = !char.IsLetter(chrBefore) 
                                  || strValidChar.Contains(chrBefore);

                bool bolAfter= !char.IsLetter(chrAfter) 
                                  || strValidChar.Contains(chrAfter );
                            
                if (bolBefore && bolAfter)
                {
                    new classIndexWord_Item(word, intFind);

                }
                intFind = rtxTemp.Text.IndexOf(word, intFind + 1);
            }
        }

    }

    IEnumerable<classIndexWord_Item> query = lst.OrderBy(DW => DW.Index);
    lst = (List<classIndexWord_Item>)query.ToList<classIndexWord_Item>();
}

  as I only just put this together a few days ago and haven't tested it on larger files than my short chapters(2500 words or less).  Its likely that I'll soon have to break this task up into small chores and run them on a timer to improve UI and user experience.

2 & 3) Measure rtx visible indices

the

public static List<classIndexWord_Item> lstWordsVisible

property uses points at the top(and just above)-left and bottom(and just below)-right of the user's text to determine which character indices are visible 

// find start
int intBorder_Height = 256;
Point ptTL = new Point(0, -intBorder_Height);
Point ptBR = new Point(rtx.Width, rtx.Height + intBorder_Height);
int intIndex_TL = rtx.GetCharIndexFromPosition(ptTL);
int intIndex_BR = rtx.GetCharIndexFromPosition(ptBR);

then and uses a "test mid/way, half-step check and jump again" approach to find the words listed after the start intIndex_TL and before the end intIndex_BR 

int intStepSize = lst.Count;
int intTest = 0;
int intDir = 1;

int intFail = 0;
int intFaile_Max = 32;

int intWord_FirstFound_Index = 0;
do
{
    intStepSize /= 2;
    if (intStepSize < 1)
    {
        intStepSize = 1;
        intFail++;
    }

    intTest += intStepSize * intDir;
    if (intTest < 0)
        intTest = 0;
    if (intTest >= lst.Count)
        intTest = lst.Count - 1;
    classIndexWord_Item cWDI_Test = lst[intTest];

    intDir = (int)Math.Sign(intIndex_TL- cWDI_Test.Index);
    if (intDir > 0 && intTest > intWord_FirstFound_Index)
        intWord_FirstFound_Index = intTest;
} while (intFail < intFaile_Max);

then returns the list of words visible on the screen.

4) Create a Sweep and Prune map of visible words 

as described in the previous section - SP_Build() creates a map of the screen

public static void SP_Build()
{
    cSP.lstElements.Clear();
    if (ckRtx_Focused == null) return;

    int intGuessedFontHeight = 20;
    int intTL = ckRtx_Focused.rtx.GetCharIndexFromPosition(new Point(0, 0));

    for (int intCounter = 0; 
         intCounter < lstItemsVisible.Count; 
         intCounter++)
    {
        classIndexWord_Item cWordItem = lstItemsVisible[intCounter];
        Point ptTL = ckRtx_Focused.rtx.
                          GetPositionFromCharIndex(cWordItem.Index);
        Point ptTemp = ckRtx_Focused.rtx.
                          GetPositionFromCharIndex(cWordItem.Index 
                                                   + cWordItem.Word.Length);
        Point ptBR = new Point(ptTemp.X, 
                               ptTL.Y + intGuessedFontHeight);
                
        if (ptBR.X < ptTL.X)
            ptBR.X = ptTL.X + intGuessedFontHeight;


        Ck_Objects.classSweepAndPrune.classElement 
                      cEle_New = new classSweepAndPrune.classElement();
        cEle_New.rec = new Rectangle(ptTL, 
                                     new Size(ptBR.X - ptTL.X, 
                                              ptBR.Y - ptTL.Y));
        cEle_New.obj = (object)cWordItem;

        cSP.Add(ref cEle_New);
    }
}

5) Mouse Move polls SP Map 

then the rtx.MouseMove() event handler tests what word is located under the user's mouse

private void rtxCK_MouseMove(object sender, MouseEventArgs e)
{
    if (groupboxDefinedWords.Toggle)
    {
        Point ptMouse = new Point(e.X, e.Y);
        groupboxDefinedWords.classIndexWord_Item 
              cItemUnderMouse = groupboxDefinedWords.cItemUnderPoint(ptMouse);
        if (cItemUnderMouse != null)
        {
            if (cItemUnderMouse.Index >= 0 
              && cItemUnderMouse.Index 
                 + cItemUnderMouse.Word.Length < rtx.Text.Length)
                rtx.Select(cItemUnderMouse.Index, 0);
        }
    }
}

asking the groupboxDefinedWords what word is under the mouse at a given point 

public static classIndexWord_Item cItemUnderPoint(Point pt)
{
    if (ckRtx_Focused == null) return null;

    if (ckRtx_Focused.CharIndex_TL_Changed)
    {
        List<classIndexWord_Item> lstVisible = classIndexWord_Item.lstWordsVisible;
        SP_Build();
        ckRtx_Focused.CharIndex_TL_Changed = false;
    }

    Ck_Objects.classSweepAndPrune.classElement cEleFound = cSP.Search(pt);
    if (cEleFound != null)
        return (classIndexWord_Item)cEleFound.obj;
    else
        return null;
}

Definition Navigator - RTX twins

Many of the dictionaries are not stored in RichTextFiles(.rtf) but some are plain old TextFiles(.txt) and have no formatting with regards to Fonts or color.  This is because I, believing that having these resources would help me in my writing (though I learned nothing about medicine while typing the Medical Dictionary having these tools at my disposal while writing has greatly improved my talents), hand-typed, page-by-page (with strategically inserted typos for your reading entertainment) a dozen dictionaries before going mad... stabbing my neighbours and spending years in jail proudly boasting having nothing but violence on my criminal record.  By the time I got out of prison there was this thing called the 'Internet' and scraping 100s of thousands of files off commercial websites like Merriam-Webster was way cooler than spending endless hours typing word-definitions into my computer everyday and gathering Postal-Steam in the process.  This experience, along with having read Amy Vanderbilt : Complete Book of Etiquette while eating in homeless kitchens surrounded by emotionally unstable alcoholics and homeless drug addicts has, oddly enough, made me a better writer.

Let me make a list of all the dictionaries and where they came from ... just for the record

Hand Typed Dictionaries 

  1. Dictionary : Crime
  2. Dictionary : English
  3. Dictionary : Euphemisms
  4. Dictionary : Italian
  5. Dictionary : Latin(revised)
  6. Dictionary : Medical
  7. Dictionary : Nineteenth Century Slang
  8. Dictionary : Prison Slang
  9. Dictionary : Proper Names
  10. Dictionary : Southern Expressions
  11. Dictionary : Spanish
  12. Dictionnaire : Francais
  13. Thesaurus : English

Parsed from a downloaded PDF file

  1. Dictionary : Nautical 

Scraped from the Internet

  1. Dictionary : English MW
  2. Dictionary : Irish-English
  3. Thesaurus : English MW
  4. Dictionary : Etymology EtymOnline.com
  5. Thesaurus : French Usito 
  6. Dictionnaire Francais

That means that all the dictionaries listed above, with the exception of the last three are TextFiles.  In order to embellish the output of these files, this app loads the TextFiles, finds the Heading (the first line of text) and prints the heading in a different Font/Color than the rest of that word entry's definition.  In order to do this it has to add the Heading, set the font & color then add the definition.  Doing this the was causing the RichTextBox to print things sequentially.  This resulted in a mess performance for the user to watch as the definition was being written in blue then re-fonted, then set to black ... its a mess.  Weeks could be spent letting my laptop re-build each TextFile into an appropriate RichTextFile but that will wait until I have another box on the side to perform these chores.  Perhaps there's another way to load the RichTextBox that is not so jumpy but... I haven't put the effort in to figure that out.

Since my resolved means of performing this operation is so unsightly, and may cause epileptic seizures to the unwary, I implemented something I resorted to in my previous project Dlús : Irish Language Word Processor where I was asked to translate some English text into Irish in the scraped Irish dictionary's definition, and make this an option for the user.  This required editing the RichTextFile while loading it into the RichTextBox you see on the screen and resulted in the same poor quality that editing a TextFile to display into a RichTextBox required.  The solution I opted for was to use two RichTextBoxes drawn in front of each.  Do the work on the one that's not visible(behind the first) then bring it to the front when its done.  Kind of like drawing graphics for a video-game : use two screen images, flash the next one on the screen when you're done drawing it.

Here's some of the code.  The array of two RichTextBoxes are initialized in 

public panelDefinitionNavigator(ref classDictionary cDictionary)
{
    // code excised for brevity

    rtx_Array[0] = new RichTextBox();
    rtx_Array[1] = new RichTextBox();

    for (int intRTXCounter = 0; intRTXCounter < rtx_Array.Length; intRTXCounter++)
    {
        Controls.Add(rtx);
        rtx.SizeChanged += rtx_SizeChanged;
        rtx.Tag = (object)this;
        rtx.BorderStyle = BorderStyle.None;
        rtx.KeyDown += formDictionaryOutput.RtxOutput_KeyDown;
        rtx.KeyUp += formDictionaryOutput.RtxOutput_KeyUp;
        rtx.KeyPress += formDictionaryOutput.RtxOutput_KeyPress;
        rtx.MouseEnter += formDictionaryOutput.RtxOutput_MouseEnter;
        rtx.MouseEnter += _MouseEnter;
        rtx.MouseLeave += formDictionaryOutput.RtxOutput_MouseLeave;
        rtx.MouseDoubleClick += formDictionaryOutput.RtxOutput_MouseDoubleClick;
        rtx.MouseMove += formDictionaryOutput.RtxOutput_MouseMove;
        rtx.MouseDown += formDictionaryOutput.RtxOutput_MouseDown;
        rtx.MouseWheel += formDictionaryOutput.RtxOutput_MouseWheel;
        rtx.VScroll += formDictionaryOutput.RtxOutput_VScroll;
        RTX_Swap();
    }

    // code excised for brevity
}

Since I had the code working with a single RichTextBox called rtx, creating an array with a different name and adding a property that used the same name as the original RichTextBox incorporated the changes with the rest of the code much easier.  There is an integer keeping track of which of the two RichTextBoxes in the array is referred to as rtx by the rest of the project and the work of loading/editing the next definition is done in the alternate RichTextBox which is hidden behind the current.  When that work is done, a call to the RTX_Swap() method swaps the current/alternate RichTextBoxes and pulls the current one to the front of the other.  And we're done.

public RichTextBox[] rtx_Array = new RichTextBox[2];

int intRTXIndex_Current = 0;
void RTX_Swap()
{
    intRTXIndex_Current = (intRTXIndex_Current + 1) % 2;
    rtx.BringToFront();
}

public  RichTextBox rtx      { get { return rtx_Array[intRTXIndex_Current]; }}
private RichTextBox rtx_Next { get { return rtx_Array[(intRTXIndex_Current + 1) % 2]; }}

in the code below you can see the rtx_Next being written to and then pulled to the front with a call to RTX_Swap()

case enuFileExtensions.txt:
    {
        classFileContent cFileContent = new classFileContent(cDictionary.strSourceDirectory, 
                                                             strFilename.Substring(strFilename.Length - 12, 8));
        if (cFileContent.Heading != null && cFileContent.Definition != null)
        {
            RichTextBox rtxRef = rtx_Next;
            rtxRef.Clear();
            classStringLibrary.RTX_AppendText(ref rtxRef, 
                                              cFileContent.Heading.Trim(), 
                                              formDictionaryOutput.fntWordHeading, 
                                              Color.Blue, 
                                              0);
            classStringLibrary.RTX_AppendNL(ref rtxRef);
            if (cFileContent.alt_Heading != null)
            {
                classStringLibrary.RTX_AppendText(ref rtxRef, 
                                                  cFileContent.alt_Heading.Trim(), 
                                                  formDictionaryOutput.fntWordHeading, 
                                                  Color.LightBlue, 
                                                  0);
                classStringLibrary.RTX_AppendNL(ref rtxRef);
            }

            classStringLibrary.RTX_AppendText(ref rtxRef, 
                                              cFileContent.Definition, 
                                              formDictionaryOutput.fntWordDefinition, 
                                              Color.Black, 
                                              0);
            rtxRef.Select(0, 0);
            rtxRef.ScrollToCaret();
            RTX_Swap();
        }
    }
    break;

The Definition Tracker does not use the same binary-trees used for a normal 'heading-search'.  When the data-file for this feature is created in each dictionary's sub-directory, the list-builder loads each RTF file then not only adds the exact spelling of the first word-entry on the file but adds also 'alternate spellings' in a binary tree on the hard drive.  It then traverses the bin-tree in-order to create a separate file which indexed, equal sized records of entry-headings and corresponding root filenames.  This file is indexed by the Definition Tracker's VerticalScroll bar in its VscBar_ValueChanged() event handler which is calibrated to it.  Change the vsc.Value and the MultiButtonPicturebox (scrollable word list) draws the words that match the user's request.

Definition Navigator Click or DoubleClick

I was having trouble getting the MouseDoubleClick event (insert word into text) NOT trigger the MouseClick event(display selected word's definition beneath the moust) until I used a Timer to delay and execute the MouseClick only if the MouseDoubleClick doesn't happen.  When the user only wants to explore definitions of words by single-clicking on them in the Navigator, the Navigator loads a new definition and puts it on the screen.  A mouse double-click tells the Navigator to insert the word being double-clicked into the text the user is working on.  But... the double-click event cannot happen without the first click causing the regular single-mouse-click event from occurring.  This resulted in the user clicking once(the first of the double clicks) loading a new definition and then double-clicking the word in the new definition, thereby inserting the wrong word into the user's text. 

To solve this, I added a timer.  The timer has a 500ms delay and is enabled at the MouseDown event.

public static void RtxOutput_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        WordUnderMouse_PopUpDefinition(sender);
    }
    else
    {
        rtxOutput_MouseClick_Sender = sender;
        rtxOutput_MouseClick_MouseEventArgs = e;
        tmrClick_WaitForDoubleClick.Interval = 500;
        tmrClick_WaitForDoubleClick.Enabled = !tmrClick_WaitForDoubleClick.Enabled;
    }
}

The MouseDown event's parameters are recorded and the timer is enabled.  Since the MouseDoubleClick disables the timer, the MouseClick event is aborted when the user double-clicks.

public static void RtxOutput_MouseDoubleClick(object sender, MouseEventArgs e)
{
    tmrClick_WaitForDoubleClick.Enabled = false;
    WordUnderMouse_Insert(sender, new Point(e.X, e.Y));
}

But if the user takes too long (500ms) or actually only intends a single-click, then the timer's event is triggered and the work to be done for a single-click is executed.

 
private void tmrClick_WaitForDoubleClick_Tick(object sender, EventArgs e)
{
    tmrClick_WaitForDoubleClick.Enabled = false;
    _RtxOutput_MouseClick(rtxOutput_MouseClick_Sender, rtxOutput_MouseClick_MouseEventArgs);
}



public static void _RtxOutput_MouseClick(object sender, MouseEventArgs e)
{
    if (bolIgnoreMouseUp)
    {
        bolIgnoreMouseUp = false;
        return;
    }
    rtxCalling = (RichTextBox)sender;
    switch (e.Button)
    {
        case MouseButtons.Left:
            {
                WordUnderMouse_Search(sender, new Point(e.X, e.Y));
            }
            break;

        case MouseButtons.Right:
            {
                WordUnderMouse_PopUpDefinition(sender);
            }
            break;

        case MouseButtons.Middle:
            break;
    }
}

Updates

Code Updates - latest changes

code updates Greatest Hits

 

 

      

 

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO unemployable
Canada Canada
Christ Kennedy grew up in the suburbs of Montreal and is a bilingual Quebecois with a bachelor’s degree in computer engineering from McGill University. He is unemployable and currently living in Moncton, N.B. writing his next novel.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA18-Aug-21 17:26
professionalȘtefan-Mihai MOGA18-Aug-21 17:26 
GeneralRe: My vote of 5 Pin
Christ Kennedy19-Aug-21 1:07
mvaChrist Kennedy19-Aug-21 1:07 
QuestionA novelist-programmer, eh? Me too. Pin
DaveCline12-Jul-21 10:13
DaveCline12-Jul-21 10:13 
AnswerRe: A novelist-programmer, eh? Me too. Pin
Christ Kennedy13-Jul-21 6:48
mvaChrist Kennedy13-Jul-21 6:48 
GeneralRe: A novelist-programmer, eh? Me too. Pin
Jacques Abada16-Aug-21 2:13
Jacques Abada16-Aug-21 2:13 
GeneralRe: A novelist-programmer, eh? Me too. Pin
Christ Kennedy16-Aug-21 7:40
mvaChrist Kennedy16-Aug-21 7:40 
GeneralMy vote of 5 Pin
Vincent Radio12-Jul-21 7:05
professionalVincent Radio12-Jul-21 7:05 
GeneralRe: My vote of 5 Pin
Christ Kennedy13-Jul-21 6:38
mvaChrist Kennedy13-Jul-21 6:38 
QuestionSpell checker Pin
Franc Morales10-Jul-21 21:34
Franc Morales10-Jul-21 21:34 
AnswerRe: Spell checker Pin
Christ Kennedy11-Jul-21 0:18
mvaChrist Kennedy11-Jul-21 0:18 
GeneralMy vote of 3 Pin
Vincent Radio25-May-21 3:37
professionalVincent Radio25-May-21 3:37 
GeneralRe: My vote of 3 Pin
Christ Kennedy25-May-21 11:31
mvaChrist Kennedy25-May-21 11:31 
PraiseMessage Closed Pin
22-May-21 7:56
Member 1521159322-May-21 7:56 
Questionsubject Pin
Mohit Singh 202121-May-21 23:05
professionalMohit Singh 202121-May-21 23:05 
AnswerRe: subject Pin
Christ Kennedy22-May-21 1:44
mvaChrist Kennedy22-May-21 1:44 
QuestionObject reference not set to an instance of an object Pin
dawiemos10-Jan-20 22:30
dawiemos10-Jan-20 22:30 
AnswerRe: Object reference not set to an instance of an object Pin
Christ Kennedy23-Jan-20 4:09
mvaChrist Kennedy23-Jan-20 4:09 
GeneralRe: Object reference not set to an instance of an object Pin
dawiemos29-Mar-20 20:26
dawiemos29-Mar-20 20:26 
GeneralRe: Object reference not set to an instance of an object Pin
Christ Kennedy30-Jan-21 5:06
mvaChrist Kennedy30-Jan-21 5:06 
QuestionCode Critique Pin
Marc Clifton10-Oct-19 3:03
mvaMarc Clifton10-Oct-19 3:03 
AnswerRe: Code Critique Pin
Christ Kennedy11-Oct-19 4:23
mvaChrist Kennedy11-Oct-19 4:23 
Questionmail.com is blocked Pin
dawiemos26-Sep-19 9:59
dawiemos26-Sep-19 9:59 
AnswerRe: mail.com is blocked Pin
Christ Kennedy26-Sep-19 22:52
mvaChrist Kennedy26-Sep-19 22:52 
QuestionMissing RHYMDICT on your server Pin
monglung25-Sep-19 10:27
professionalmonglung25-Sep-19 10:27 
AnswerRe: Missing RHYMDICT on your server Pin
Christ Kennedy25-Sep-19 15:07
mvaChrist Kennedy25-Sep-19 15:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.