+ {
+ // CHARFORMAT or CHARFORMAT2
+ cf.cbSize = sizeof(cf);
+ }
+
+ if ( style.HasFont() )
+ {
+ // VZ: CFM_CHARSET doesn't seem to do anything at all in RichEdit 2.0
+ // but using it doesn't seem to hurt neither so leaving it for now
+
+ cf.dwMask |= CFM_FACE | CFM_SIZE | CFM_CHARSET |
+ CFM_ITALIC | CFM_BOLD | CFM_UNDERLINE;
+
+ // fill in data from LOGFONT but recalculate lfHeight because we need
+ // the real height in twips and not the negative number which
+ // wxFillLogFont() returns (this is correct in general and works with
+ // the Windows font mapper, but not here)
+
+ wxFont font(style.GetFont());
+
+ LOGFONT lf;
+ wxFillLogFont(&lf, &font);
+ cf.yHeight = 20*font.GetPointSize(); // 1 pt = 20 twips
+ cf.bCharSet = lf.lfCharSet;
+ cf.bPitchAndFamily = lf.lfPitchAndFamily;
+ wxStrlcpy(cf.szFaceName, lf.lfFaceName, WXSIZEOF(cf.szFaceName));
+
+ // also deal with underline/italic/bold attributes: note that we must
+ // always set CFM_ITALIC &c bits in dwMask, even if we don't set the
+ // style to allow clearing it
+ if ( lf.lfItalic )
+ {
+ cf.dwEffects |= CFE_ITALIC;
+ }
+
+ if ( lf.lfWeight == FW_BOLD )
+ {
+ cf.dwEffects |= CFE_BOLD;
+ }
+
+ if ( lf.lfUnderline )
+ {
+ cf.dwEffects |= CFE_UNDERLINE;
+ }
+
+ // strikeout fonts are not supported by wxWidgets
+ }
+
+ if ( style.HasTextColour() )
+ {
+ cf.dwMask |= CFM_COLOR;
+ cf.crTextColor = wxColourToRGB(style.GetTextColour());
+ }
+
+#if wxUSE_RICHEDIT2
+ if ( m_verRichEdit != 1 && style.HasBackgroundColour() )
+ {
+ cf.dwMask |= CFM_BACKCOLOR;
+ cf.crBackColor = wxColourToRGB(style.GetBackgroundColour());
+ }
+#endif // wxUSE_RICHEDIT2
+
+ // do format the selection
+ bool ok = ::SendMessage(GetHwnd(), EM_SETCHARFORMAT,
+ SCF_SELECTION, (LPARAM)&cf) != 0;
+ if ( !ok )
+ {
+ wxLogDebug(wxT("SendMessage(EM_SETCHARFORMAT, SCF_SELECTION) failed"));
+ }
+
+ // now do the paragraph formatting
+ PARAFORMAT2 pf;
+ wxZeroMemory(pf);
+ // we can't use PARAFORMAT2 with RichEdit 1.0, so pretend it is a simple
+ // PARAFORMAT in that case
+#if wxUSE_RICHEDIT2
+ if ( m_verRichEdit == 1 )
+ {
+ // this is the only thing the control is going to grok
+ pf.cbSize = sizeof(PARAFORMAT);
+ }
+ else
+#endif
+ {
+ // PARAFORMAT or PARAFORMAT2
+ pf.cbSize = sizeof(pf);
+ }
+
+ if (style.HasAlignment())
+ {
+ pf.dwMask |= PFM_ALIGNMENT;
+ if (style.GetAlignment() == wxTEXT_ALIGNMENT_RIGHT)
+ pf.wAlignment = PFA_RIGHT;
+ else if (style.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
+ pf.wAlignment = PFA_CENTER;
+ else if (style.GetAlignment() == wxTEXT_ALIGNMENT_JUSTIFIED)
+ pf.wAlignment = PFA_JUSTIFY;
+ else
+ pf.wAlignment = PFA_LEFT;
+ }
+
+ if (style.HasLeftIndent())
+ {
+ pf.dwMask |= PFM_STARTINDENT | PFM_OFFSET;
+
+ // Convert from 1/10 mm to TWIPS
+ pf.dxStartIndent = (int) (((double) style.GetLeftIndent()) * mm2twips / 10.0) ;
+ pf.dxOffset = (int) (((double) style.GetLeftSubIndent()) * mm2twips / 10.0) ;
+ }
+
+ if (style.HasRightIndent())
+ {
+ pf.dwMask |= PFM_RIGHTINDENT;
+
+ // Convert from 1/10 mm to TWIPS
+ pf.dxRightIndent = (int) (((double) style.GetRightIndent()) * mm2twips / 10.0) ;
+ }
+
+ if (style.HasTabs())
+ {
+ pf.dwMask |= PFM_TABSTOPS;
+
+ const wxArrayInt& tabs = style.GetTabs();
+
+ pf.cTabCount = (SHORT)wxMin(tabs.GetCount(), MAX_TAB_STOPS);
+ size_t i;
+ for (i = 0; i < (size_t) pf.cTabCount; i++)
+ {
+ // Convert from 1/10 mm to TWIPS
+ pf.rgxTabs[i] = (int) (((double) tabs[i]) * mm2twips / 10.0) ;
+ }
+ }
+
+#if wxUSE_RICHEDIT2
+ if ( m_verRichEdit > 1 )
+ {
+ if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
+ {
+ // Use RTL paragraphs in RTL mode to get proper layout
+ pf.dwMask |= PFM_RTLPARA;
+ pf.wEffects |= PFE_RTLPARA;
+ }
+ }
+#endif // wxUSE_RICHEDIT2
+
+ if ( pf.dwMask )
+ {
+ // do format the selection
+ bool ok = ::SendMessage(GetHwnd(), EM_SETPARAFORMAT,
+ 0, (LPARAM) &pf) != 0;
+ if ( !ok )
+ {
+ wxLogDebug(wxT("SendMessage(EM_SETPARAFORMAT, 0) failed"));
+ }
+ }
+
+ if ( changeSel )
+ {
+ // restore the original selection
+ DoSetSelection(startOld, endOld, SetSel_NoScroll);
+ }
+
+ return ok;
+}
+
+bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
+{
+ if ( !wxTextCtrlBase::SetDefaultStyle(style) )
+ return false;
+
+ if ( IsEditable() )
+ {
+ // we have to do this or the style wouldn't apply for the text typed by
+ // the user
+ wxTextPos posLast = GetLastPosition();
+ SetStyle(posLast, posLast, m_defaultStyle);
+ }
+
+ return true;
+}
+
+bool wxTextCtrl::GetStyle(long position, wxTextAttr& style)
+{
+ if ( !IsRich() )
+ {
+ // can't do it with normal text control
+ return false;
+ }
+
+ // initialize CHARFORMAT struct
+#if wxUSE_RICHEDIT2
+ CHARFORMAT2 cf;
+#else
+ CHARFORMAT cf;
+#endif
+
+ wxZeroMemory(cf);
+
+ // we can't use CHARFORMAT2 with RichEdit 1.0, so pretend it is a simple
+ // CHARFORMAT in that case
+#if wxUSE_RICHEDIT2
+ if ( m_verRichEdit == 1 )
+ {
+ // this is the only thing the control is going to grok
+ cf.cbSize = sizeof(CHARFORMAT);
+ }
+ else
+#endif
+ {
+ // CHARFORMAT or CHARFORMAT2
+ cf.cbSize = sizeof(cf);
+ }
+ // we can only change the format of the selection, so select the range we
+ // want and restore the old selection later
+ long startOld, endOld;
+ GetSelection(&startOld, &endOld);
+
+ // but do we really have to change the selection?
+ bool changeSel = position != startOld || position != endOld;
+
+ if ( changeSel )
+ {
+ DoSetSelection(position, position + 1, SetSel_NoScroll);
+ }
+
+ // get the selection formatting
+ (void) ::SendMessage(GetHwnd(), EM_GETCHARFORMAT,
+ SCF_SELECTION, (LPARAM)&cf) ;
+
+
+ LOGFONT lf;
+ lf.lfHeight = cf.yHeight;
+ lf.lfWidth = 0;
+ lf.lfCharSet = ANSI_CHARSET; // FIXME: how to get correct charset?
+ lf.lfClipPrecision = 0;
+ lf.lfEscapement = 0;
+ wxStrcpy(lf.lfFaceName, cf.szFaceName);
+
+ //NOTE: we _MUST_ set each of these values to _something_ since we
+ //do not call wxZeroMemory on the LOGFONT lf
+ if (cf.dwEffects & CFE_ITALIC)
+ lf.lfItalic = TRUE;
+ else
+ lf.lfItalic = FALSE;
+
+ lf.lfOrientation = 0;
+ lf.lfPitchAndFamily = cf.bPitchAndFamily;
+ lf.lfQuality = 0;
+
+ if (cf.dwEffects & CFE_STRIKEOUT)
+ lf.lfStrikeOut = TRUE;
+ else
+ lf.lfStrikeOut = FALSE;
+
+ if (cf.dwEffects & CFE_UNDERLINE)
+ lf.lfUnderline = TRUE;
+ else
+ lf.lfUnderline = FALSE;
+
+ if (cf.dwEffects & CFE_BOLD)
+ lf.lfWeight = FW_BOLD;
+ else
+ lf.lfWeight = FW_NORMAL;
+
+ wxFont font = wxCreateFontFromLogFont(& lf);
+ if (font.Ok())
+ {
+ style.SetFont(font);
+ }
+ style.SetTextColour(wxColour(cf.crTextColor));
+
+#if wxUSE_RICHEDIT2
+ if ( m_verRichEdit != 1 )
+ {
+ // cf.dwMask |= CFM_BACKCOLOR;
+ style.SetBackgroundColour(wxColour(cf.crBackColor));
+ }
+#endif // wxUSE_RICHEDIT2
+
+ // now get the paragraph formatting
+ PARAFORMAT2 pf;
+ wxZeroMemory(pf);
+ // we can't use PARAFORMAT2 with RichEdit 1.0, so pretend it is a simple
+ // PARAFORMAT in that case
+#if wxUSE_RICHEDIT2
+ if ( m_verRichEdit == 1 )
+ {
+ // this is the only thing the control is going to grok
+ pf.cbSize = sizeof(PARAFORMAT);
+ }
+ else
+#endif
+ {
+ // PARAFORMAT or PARAFORMAT2
+ pf.cbSize = sizeof(pf);
+ }
+
+ // do format the selection
+ (void) ::SendMessage(GetHwnd(), EM_GETPARAFORMAT, 0, (LPARAM) &pf) ;
+
+ style.SetLeftIndent( (int) ((double) pf.dxStartIndent * twips2mm * 10.0), (int) ((double) pf.dxOffset * twips2mm * 10.0) );
+ style.SetRightIndent( (int) ((double) pf.dxRightIndent * twips2mm * 10.0) );
+
+ if (pf.wAlignment == PFA_CENTER)
+ style.SetAlignment(wxTEXT_ALIGNMENT_CENTRE);
+ else if (pf.wAlignment == PFA_RIGHT)
+ style.SetAlignment(wxTEXT_ALIGNMENT_RIGHT);
+ else if (pf.wAlignment == PFA_JUSTIFY)
+ style.SetAlignment(wxTEXT_ALIGNMENT_JUSTIFIED);
+ else
+ style.SetAlignment(wxTEXT_ALIGNMENT_LEFT);
+
+ wxArrayInt tabStops;
+ size_t i;
+ for (i = 0; i < (size_t) pf.cTabCount; i++)
+ {
+ tabStops.Add( (int) ((double) (pf.rgxTabs[i] & 0xFFFF) * twips2mm * 10.0) );
+ }
+
+ if ( changeSel )
+ {
+ // restore the original selection
+ DoSetSelection(startOld, endOld, SetSel_NoScroll);
+ }
+
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+// wxRichEditModule
+// ----------------------------------------------------------------------------
+
+static const HINSTANCE INVALID_HINSTANCE = (HINSTANCE)-1;
+
+bool wxRichEditModule::OnInit()
+{
+ // don't do anything - we will load it when needed
+ return true;
+}
+
+void wxRichEditModule::OnExit()
+{
+ for ( size_t i = 0; i < WXSIZEOF(ms_hRichEdit); i++ )
+ {
+ if ( ms_hRichEdit[i] && ms_hRichEdit[i] != INVALID_HINSTANCE )
+ {
+ ::FreeLibrary(ms_hRichEdit[i]);
+ ms_hRichEdit[i] = NULL;
+ }
+ }
+#if wxUSE_INKEDIT
+ if (ms_inkEditLib.IsLoaded())
+ ms_inkEditLib.Unload();
+#endif
+}
+
+/* static */
+bool wxRichEditModule::Load(Version version)
+{
+ if ( ms_hRichEdit[version] == INVALID_HINSTANCE )
+ {
+ // we had already tried to load it and failed
+ return false;
+ }
+
+ if ( ms_hRichEdit[version] )
+ {
+ // we've already got this one
+ return true;
+ }
+
+ static const wxChar *const dllnames[] =
+ {
+ wxT("riched32"),
+ wxT("riched20"),
+ wxT("msftedit"),
+ };
+
+ wxCOMPILE_TIME_ASSERT( WXSIZEOF(dllnames) == Version_Max,
+ RichEditDllNamesVersionsMismatch );
+
+ ms_hRichEdit[version] = ::LoadLibrary(dllnames[version]);
+
+ if ( !ms_hRichEdit[version] )
+ {
+ ms_hRichEdit[version] = INVALID_HINSTANCE;
+
+ return false;
+ }
+
+ return true;
+}
+
+#if wxUSE_INKEDIT
+// load the InkEdit library
+bool wxRichEditModule::LoadInkEdit()
+{
+ if (ms_inkEditLibLoadAttemped)
+ return ms_inkEditLib.IsLoaded();
+
+ ms_inkEditLibLoadAttemped = true;
+
+ wxLogNull logNull;
+ return ms_inkEditLib.Load(wxT("inked"));
+}
+#endif // wxUSE_INKEDIT
+
+
+#endif // wxUSE_RICHEDIT