reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

richedit-win32.cpp (3076B)


      1 /* ReaPack: Package manager for REAPER
      2  * Copyright (C) 2015-2025  Christian Fillion
      3  *
      4  * This program is free software: you can redistribute it and/or modify
      5  * it under the terms of the GNU Lesser General Public License as published by
      6  * the Free Software Foundation, either version 3 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU Lesser General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser General Public License
     15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16  */
     17 
     18 #include "richedit.hpp"
     19 
     20 // This is the Win32 implementation of RichEdit
     21 // The macOS implementation is in richedit.mm, Linux is in richedit-generic.cpp
     22 
     23 #include "dllimport.hpp"
     24 #include "win32.hpp"
     25 
     26 #include <memory>
     27 #include <richedit.h>
     28 #include <sstream>
     29 
     30 static void HandleLink(ENLINK *info, HWND handle)
     31 {
     32   const CHARRANGE &range = info->chrg;
     33 
     34   std::wstring url(range.cpMax - range.cpMin, 0);
     35 
     36   TEXTRANGE tr{range, url.data()};
     37   SendMessage(handle, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
     38 
     39   if(info->msg == WM_LBUTTONUP)
     40     ShellExecute(nullptr, L"open", url.c_str(), nullptr, nullptr, SW_SHOW);
     41 }
     42 
     43 void RichEdit::Init()
     44 {
     45   LoadLibrary(L"Msftedit.dll");
     46 }
     47 
     48 RichEdit::RichEdit(HWND handle)
     49   : Control(handle)
     50 {
     51   SendMessage(handle, EM_AUTOURLDETECT, true, 0);
     52   SendMessage(handle, EM_SETEVENTMASK, 0, ENM_LINK);
     53   SendMessage(handle, EM_SETEDITSTYLE,
     54     SES_HYPERLINKTOOLTIPS, SES_HYPERLINKTOOLTIPS);
     55 
     56   // available since Windows 10 version 1703
     57   static DllImport<decltype(SetDialogControlDpiChangeBehavior)>
     58     _SetDialogControlDpiChangeBehavior
     59     {L"user32.dll", "SetDialogControlDpiChangeBehavior"};
     60 
     61   if(_SetDialogControlDpiChangeBehavior) {
     62     _SetDialogControlDpiChangeBehavior(handle,
     63       DCDC_DISABLE_FONT_UPDATE, DCDC_DISABLE_FONT_UPDATE);
     64   }
     65 }
     66 
     67 RichEdit::~RichEdit() = default;
     68 
     69 void RichEdit::onNotify(LPNMHDR info, LPARAM lParam)
     70 {
     71   switch(info->code) {
     72   case EN_LINK:
     73     HandleLink((ENLINK *)lParam, handle());
     74     break;
     75   };
     76 }
     77 
     78 void RichEdit::setPlainText(const std::string &text)
     79 {
     80   Win32::setWindowText(handle(), text.c_str());
     81 }
     82 
     83 bool RichEdit::setRichText(const std::string &rtf)
     84 {
     85   std::stringstream stream(rtf);
     86 
     87   EDITSTREAM es{};
     88   es.dwCookie = (DWORD_PTR)&stream;
     89   es.pfnCallback = [](DWORD_PTR cookie, LPBYTE buf, LONG size, LONG *pcb) -> DWORD {
     90     std::stringstream *stream = reinterpret_cast<std::stringstream *>(cookie);
     91     *pcb = (LONG)stream->readsome((char *)buf, size);
     92     return 0;
     93   };
     94 
     95   SendMessage(handle(), EM_STREAMIN, SF_RTF, (LPARAM)&es);
     96 
     97   if(es.dwError)
     98     return false;
     99 
    100   GETTEXTLENGTHEX tl{};
    101   LONG length = (LONG)SendMessage(handle(), EM_GETTEXTLENGTHEX, (WPARAM)&tl, 0);
    102 
    103   if(!length)
    104     return false;
    105 
    106   // scale down a little bit, by default everything is way to big
    107   SendMessage(handle(), EM_SETZOOM, 3, 4);
    108 
    109   return true;
    110 }