NO

Author Topic: RichEdit Syntax Coloring  (Read 566 times)

Offline Grincheux

  • Member
  • *
  • Posts: 40
  • Never be pleased, always improve
    • Arachne
RichEdit Syntax Coloring
« on: January 07, 2020, 07:29:47 pm »
I know Scintilla (Notepad++, CodeBlocks...), Monaco (Microsoft), but that's all.
But they are in C++ !

I wonder how to do to syntax coloring with RichEdit. Is there an other solution rather than subclassing?
What do you use Mr Pelle in your IDE ?
-------------------------
Kenavo

Offline jj2007

  • Member
  • *
  • Posts: 515
Re: RichEdit Syntax Coloring
« Reply #1 on: January 08, 2020, 12:21:09 pm »
Since it's a RichEdit control, you can set the colours for each character via EM_SETCHARFORMAT. Works perfectly :)

Offline Pelle

  • Administrator
  • Member
  • *****
  • Posts: 2034
    • http://www.smorgasbordet.com
Re: RichEdit Syntax Coloring
« Reply #2 on: January 12, 2020, 06:18:03 pm »
What do you use Mr Pelle in your IDE ?
I use my own code.

With the Pelles C Setup you can optionally install source code of samples for the Add-In SDK.
The two samples CppFile (for the C++ language) and JsonFile (for the JSON language) demonstrates parsing of these two languages.
Other languages can be parsed in a similar way.

Basically, the samples parse one source line at the time, filling an array with positions where a new color is needed (and which color it is).
Once you have this array, printing this source line, or updating a RichEdit control, shouldn't be too complicated I think...
/Pelle

Offline Grincheux

  • Member
  • *
  • Posts: 40
  • Never be pleased, always improve
    • Arachne
Re: RichEdit Syntax Coloring
« Reply #3 on: January 12, 2020, 08:37:29 pm »
Thank You.


I will investigate. The syntax color is the only thing that it is missing, for me.
-------------------------
Kenavo

Offline Robby

  • Member
  • *
  • Posts: 1
Re: RichEdit Syntax Coloring
« Reply #4 on: Yesterday at 06:42:51 pm »
This might be of help for those experimenting with EM_SETCHARFORMAT...
Code: [Select]
#define WIN32_DEFAULT_LIBS //Avoid ShellExecute linker errors.
#define WIN32_LEAN_AND_MEAN 
#include <windows.h>   
#include <commctrl.h>
#include <richedit.h>
#include <ntsecAPI.h>
#include <shellapi.h>
#include <wininet.h>
#include "main.h"

static LRESULT WINAPI MainWndProc(HWND, UINT, WPARAM, LPARAM);
HFONT MakeFontEx(LPCWSTR, int, int, DWORD, DWORD);

// ****************************************************************************

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, WCHAR *pszCmdLine, int nCmdShow)

  // Initialize common controls, needed for MANIFEST's
  INITCOMMONCONTROLSEX icc = {sizeof(icc), ICC_WIN95_CLASSES};
  InitCommonControlsEx(&icc);

  HMODULE hRichEditLib = LoadLibraryW(L"MsftEdit.dll");  /* Load RichEdit "RichEdit50W" v4.1 */

   
  // Register the main window class
  WNDCLASSEX WinClass;
  WinClass.cbSize        = sizeof(WNDCLASSEX);
  WinClass.style         = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
  WinClass.lpfnWndProc   = MainWndProc;
  WinClass.cbClsExtra    = 0;
  WinClass.cbWndExtra    = 0;
  WinClass.hInstance     = hInstance;
  WinClass.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDR_ICO_MAIN));
  WinClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  WinClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);   
  WinClass.lpszMenuName  = 0;
  WinClass.lpszClassName = L"SimpleClass"; 
  WinClass.hIconSm       = LoadIcon(hInstance, MAKEINTRESOURCE(IDR_ICO_MAIN));   

  HWND hWnd;
  if (RegisterClassEx(&WinClass))

    hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,
                          L"SimpleClass",
                          L"RichEdit",
                          WS_OVERLAPPEDWINDOW,
                          (GetSystemMetrics(SM_CXSCREEN) - 500) / 2, //Center window on desktop
                          (GetSystemMetrics(SM_CYSCREEN) - 300) / 2, //Center window on desktop
                          500,
                          300,
                          NULL,
                          NULL,
                          hInstance,
                          0);
   
   // Show and paint the main window
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   // Pump messages until we are done
   MSG msg;
   while (GetMessage(&msg, NULL, 0, 0) > 0)
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }

   FreeLibrary(hRichEditLib);

   return msg.wParam;
}

//****************************************************************************

static LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   wchar_t pURL[INTERNET_MAX_URL_LENGTH];
   CREATESTRUCT * pCreateStructure;
   ENLINK *param = (ENLINK *)lParam;

   switch (msg)
   {
     case WM_CREATE:
       pCreateStructure = (LPCREATESTRUCT) lParam; //Get instance from wWinMain
       static HINSTANCE hInstance;
       hInstance = pCreateStructure->hInstance;

       #ifdef _WIN64
         SetWindowText(hwnd, L"Simple app - 64bit");
       #else
         SetWindowText(hwnd, L"Simple app - 32bit");
       #endif

       RECT rc;
       GetClientRect(hwnd, &rc); //Get client rectangle

       //Create a richedit control
       static HWND hEdit;
       hEdit = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_RIGHTSCROLLBAR, L"RichEdit50W", L"",
                              WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL |
                              ES_WANTRETURN | ES_SAVESEL | ES_NOHIDESEL | WS_VSCROLL | WS_TABSTOP,
                              2, 2, rc.right - 4, rc.bottom - 4,
                              hwnd, NULL, hInstance, NULL);
       //URL detection
       SendMessage(hEdit, EM_AUTOURLDETECT, TRUE, 0);
       SendMessage(hEdit, EM_SETEVENTMASK, 0, ENM_LINK | ENM_PROTECTED);

       //Create a font
       static HFONT hFont;
       hFont = (HFONT) MakeFontEx(L"Segoe UI", 12, FW_NORMAL, FALSE, FALSE); //Create desired font
       SendMessage(hEdit, WM_SETFONT, (WPARAM) hFont, TRUE);

       SendMessage(hEdit, WM_SETTEXT, 0, (LPARAM)
       TEXT("\n RichEdit50W - RichEdit make powerfull controls!\n\n"
            " http://www.smorgasbordet.com/pellesc/\n"
            " {Double click to go...}")); //Set text

       //Set control background color
       SendMessage(hEdit, EM_SETEDITSTYLE, SES_EXTENDBACKCOLOR, 0); //Extend background color
       SendMessage(hEdit, EM_SETBKGNDCOLOR, 0, RGB(200, 200, 200)); //Set background color

       //Set selection fore and back color
       CHARFORMAT2W ChrFormat = {sizeof(CHARFORMAT2),0,0,0,0,0,0,0,L"",0,0,0,0,0,0,0,0,0,0,0};
       ChrFormat.dwMask       = CFM_COLOR | CFM_BACKCOLOR; //Flag for fore and back color
       ChrFormat.crTextColor  = RGB(200, 0, 255);            //Fore color
       ChrFormat.crBackColor  = RGB(255, 255, 0);          //Back color
       SendMessage(hEdit, EM_SETSEL, 29, 40);              // Select some text
       SendMessage(hEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &ChrFormat); //Set selection fore and back color
       SendMessage(hEdit, EM_SETSEL, -1, -1); //Remove selection by moving caret to the end
       SetFocus(hEdit); //Set focus
       break;

     case WM_NOTIFY:
       if((param)->nmhdr.hwndFrom == hEdit) //Only hEdit
       {
         if((param)->nmhdr.code == EN_LINK) //If we got EN_LINK code
         {
           if((param)->msg == WM_LBUTTONDBLCLK) //If it is a double click
           {
             DWORD UrlLen = ((param)->chrg.cpMax - (param)->chrg.cpMin + 2); //Get lenght of URL
             TEXTRANGE TxtRange;
             TxtRange.chrg = (param)->chrg; //Copy text range
             TxtRange.lpstrText = pURL;  //Point to URL
             SendMessage(hEdit, EM_GETTEXTRANGE, 0, (LPARAM) &TxtRange); //Get the URL text
             ShellExecute(NULL, L"open", pURL, L"", L"", SW_SHOW); //Open the URL using default browser.
             PostMessage(hEdit, EM_SETSEL, (param)->chrg.cpMin, (param)->chrg.cpMin); //Remove selection
           }
         }
         return FALSE;
       }
       break;
     
     case WM_SIZE:
       if (wParam != SIZE_MINIMIZED)
       {
         MoveWindow(hEdit, 2, 2, LOWORD(lParam) - 4, HIWORD(lParam) - 4, TRUE); //Resize the richedit control
       }
       break;

     case WM_DESTROY:
       PostQuitMessage(0); //Say bye!
       break;

     default:
       return DefWindowProc(hwnd, msg, wParam, lParam);
       break;
   }
}

//****************************************************************************

void MakeFontExEnumCharSet(ENUMLOGFONT elf, NEWTEXTMETRIC ntm, DWORD FontType, DWORD CharSet)
 {
   //Get type of character set - ansi, symbol. A must for some fonts.
   CharSet = elf.elfLogFont.lfCharSet;
 }

//****************************************************************************

HFONT MakeFontEx(LPCWSTR wFontName, int PointSize, int fBold, DWORD fItalic, DWORD fUnderline)
 {
 HDC hDC = GetDC(HWND_DESKTOP);
 DWORD CyPixels = GetDeviceCaps(hDC, LOGPIXELSY);
 DWORD CharSet;
 EnumFontFamilies(hDC, wFontName, &MakeFontExEnumCharSet, CharSet);
 ReleaseDC(HWND_DESKTOP, hDC);
 PointSize = 0 - (PointSize * CyPixels) / 72;

 HFONT font;
 font =  CreateFont(PointSize, 0, //Height, width(default=0)
                    0, 0,         //Escapement(angle), orientation
                    fBold,        //Weight (%FW_DONTCARE = 0, %FW_NORMAL = 400, %FW_BOLD = 700)
                    fItalic,      //Italic
                    fUnderline,   //Underline
                    FALSE,        //StrikeThru
                    CharSet, OUT_TT_PRECIS,
                    CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
                    FF_DONTCARE, wFontName); 
  return font;
 
  }

//****************************************************************************
//