home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / yacl-012.zip / ui / font.cxx < prev    next >
C/C++ Source or Header  |  1995-04-09  |  31KB  |  1,142 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6. /*
  7.  *
  8.  *          Copyright (C) 1994, M. A. Sridhar
  9.  *  
  10.  *
  11.  *     This software is Copyright M. A. Sridhar, 1994. You are free
  12.  *     to copy, modify or distribute this software  as you see fit,
  13.  *     and to use  it  for  any  purpose, provided   this copyright
  14.  *     notice and the following   disclaimer are included  with all
  15.  *     copies.
  16.  *
  17.  *                        DISCLAIMER
  18.  *
  19.  *     The author makes no warranties, either expressed or implied,
  20.  *     with respect  to  this  software, its  quality, performance,
  21.  *     merchantability, or fitness for any particular purpose. This
  22.  *     software is distributed  AS IS.  The  user of this  software
  23.  *     assumes all risks  as to its quality  and performance. In no
  24.  *     event shall the author be liable for any direct, indirect or
  25.  *     consequential damages, even if the  author has been  advised
  26.  *     as to the possibility of such damages.
  27.  *
  28.  */
  29.  
  30. #if defined(__GNUC__)
  31. #pragma implementation
  32. #endif
  33.  
  34.  
  35. #include "base/objset.h"
  36. #include "base/intset.h"
  37. #include "base/strgseq.h"
  38. #include "ui/font.h"
  39. #include "ui/applic.h"
  40. #include "ui/cntroler.h"
  41. #include "ui/visualob.h"
  42. #include "ui/dsplsurf.h"
  43.  
  44.  
  45. CL_Sequence<UI_FontInfo> UI_Font::_allFonts;
  46.  
  47. #if defined(__MS_WINDOWS__)
  48. long UI_Font::_ppi = 0;
  49. #elif defined(__OS2__)
  50. #include <string.h>
  51. static CL_IntegerSet _LocalIdSet (0, 0); // The local id's currently in use.
  52.                                          // Local id zero is always in use.
  53. #endif
  54.  
  55. static const DEFAULT_POINT_SIZE = 11;
  56.  
  57. #if defined (__MS_WINDOWS__)
  58. #include <windows.h>
  59. typedef TEXTMETRIC NativeFontStruct;
  60.  
  61. #elif defined (__OS2__)
  62. typedef FONTMETRICS NativeFontStruct;
  63.  
  64. #elif defined (__X_MOTIF__)
  65. #include <X11/Intrinsic.h>
  66. #include <X11/StringDefs.h>
  67. #include <X11/Xatom.h>
  68. #include <X11/Xlib.h>
  69.  
  70. typedef XFontStruct NativeFontStruct;
  71.  
  72. #endif
  73.  
  74.  
  75.  
  76. class UI_FontEntry: public UI_FontDesc {
  77.  
  78. public:
  79.     UI_FontEntry (short pt = 0, const char* tf = "", 
  80.                   UI_NativeFontRep nm = (UI_NativeFontRep) NULL,
  81.                   ulong style = 0, bool sf = FALSE
  82.                  );
  83.     ~UI_FontEntry ();
  84.  
  85.     bool Italic()      {return _style & UIFont_Italic;};
  86.     bool Underline()   {return _style & UIFont_Underline;};
  87.     bool BoldFace()    {return _style & UIFont_BoldFace;};
  88.     bool StrikeOut()   {return _style & UIFont_StrikeOut;};
  89.     bool IsFixed ();
  90.     bool IsScalable () const;
  91.     
  92.     short Ascent()  const;
  93.     short Descent() const;
  94.     UI_ResourceHandle Handle()      const  { return _handle;   };
  95. #if defined(__X_MOTIF__)
  96.     NativeFontStruct* FontInfo ()          { return _font;     };
  97. #else
  98.     NativeFontStruct* FontInfo ()          { return &_font;    };
  99. #endif
  100.     void              RemoveReference()    { _refcnt --;       };
  101.     void              AddReference()       { _refcnt ++;       };
  102.     short             RefCount ()   const  { return _refcnt;   };
  103.     short             Height ()     const;
  104.     short             Width  ()     const;
  105.     void Handle         (UI_ResourceHandle h)   { _handle = h; };
  106.     void  FetchFontData (UI_ResourceHandle hdc);
  107.  
  108.     const char* ClassName () const {return "UI_FontEntry";}
  109.  
  110. private:
  111.     UI_NativeFontRep  _nativeName;
  112.     UI_ResourceHandle _handle;
  113.     bool              _stockfont;
  114.  
  115. #if defined(__X_MOTIF__)
  116.     NativeFontStruct* _font;
  117. #else
  118.     NativeFontStruct  _font;
  119. #endif
  120.     short             _refcnt;
  121.  
  122.     friend UI_Font;
  123. };
  124.  
  125.  
  126.  
  127. class FontEntrySet: public CL_ObjectSet {
  128.  
  129. public:
  130.     ~FontEntrySet () {DestroyContents();};
  131. };
  132.  
  133. static FontEntrySet _FontEntries;
  134.  
  135.  
  136. UI_Font::UI_Font
  137. #if defined(__MS_WINDOWS__) || defined(__OS2__)
  138.     (UI_VisualObject*) // We don't use the parameter under Windows or OS/2
  139. #else
  140.     (UI_VisualObject* v)
  141. #endif
  142. : UI_DisplayResource (NULL)
  143. {
  144.     _Init ();
  145. }
  146.  
  147. void UI_Font::_Init
  148. #if defined(__MS_WINDOWS__) || defined(__OS2__)
  149.     (UI_VisualObject*) // We don't use the parameter under Windows or OS/2
  150. #else
  151.     (UI_VisualObject* v)
  152. #endif
  153. {
  154.     _entry = NULL;
  155. #if defined (__MS_WINDOWS__)
  156.     _nativeName  = SYSTEM_FONT;
  157.     _stockFont   = TRUE;
  158.     _Setup (_nativeName);
  159.  
  160. #elif defined(__OS2__)
  161.     _ptSize   = 10;
  162.     _typeFace = "System";
  163.     _style    = 0;
  164.     _Setup ();
  165. #elif defined (__X_MOTIF__)
  166.     XrmDatabase xrdb;
  167.     XrmValue    fontvalue;
  168.     UI_VObjCollection* parent = 0;
  169.     CL_String resource, resourceStack [20], resourceClass;
  170.     char *restype [20];
  171.     short i = 0;
  172.  
  173.     xrdb = XrmGetDatabase (_TheApplication->Controller().AppDisplay()); 
  174.     if (!xrdb) {
  175.         CL_Error::Warning ("UI_Font::UI_Font: Can't get  resource database!");
  176.         return;
  177.     }
  178.     if (!v)
  179.         _nativeName = "fixed";
  180.     else {
  181.         parent   = v->Parent();
  182.         resourceStack [i++] = v->InstanceName();
  183.         while (parent) {
  184.             resourceStack [i++] = parent->InstanceName();
  185.             parent              = parent->Parent();
  186.         }
  187.         resource = _TheApplication->AppClass () + ".";
  188.         while (i > 0) {
  189.             resource      += resourceStack [--i];
  190.             resource      += ".";
  191.         }
  192.         resourceClass += "*Font";
  193.         resource      += "font";
  194.         if (!XrmGetResource (xrdb, (char *)resource.AsPtr(),
  195.                              (char *) resourceClass.AsPtr(),
  196.                              restype, &fontvalue))
  197.             _nativeName = "fixed";
  198.         else
  199.             _nativeName = (char *)fontvalue.addr;
  200.     }
  201.     _Setup (_nativeName);
  202.  
  203. #endif
  204.  
  205. }
  206.  
  207.  
  208.  
  209. UI_Font::UI_Font (const CL_String& typeface, short pts, ulong style)
  210.                  : UI_DisplayResource (NULL)
  211. {   
  212.     _entry = NULL;
  213.     _typeFace  = typeface;
  214.     _ptSize    = pts;
  215.     _style     = style;
  216.     _stockFont = FALSE;
  217.     _Setup ();
  218. }
  219.  
  220.  
  221.  
  222. UI_Font::UI_Font (UI_DrawingSurface* sfc)
  223. : UI_DisplayResource (sfc)
  224. {   
  225.     _Init ();
  226. }
  227.  
  228.  
  229.  
  230. UI_Font::UI_Font (const UI_Font& f): UI_DisplayResource (f._clientCtxt)
  231. {
  232.     _entry = NULL;
  233.     _typeFace   = f._typeFace;
  234.     _ptSize     = f._ptSize;
  235.     _style      = f._style;
  236.     _handle     = 0;
  237.     _stockFont  = f._stockFont;
  238.     _nativeName = f._nativeName;
  239.     _Setup ();
  240. }
  241.  
  242.  
  243.  
  244. UI_Font::~UI_Font()
  245. {
  246.     UI_FontEntry* rfe = (UI_FontEntry *) _entry;
  247.     if (rfe) {
  248.         rfe->RemoveReference();
  249.         if (rfe->RefCount() == 0) {
  250.             _FontEntries.Remove (rfe);
  251.             delete rfe;
  252.         }
  253.     }
  254. }
  255.  
  256.  
  257.  
  258. void UI_Font::UseClient  (UI_DrawingSurface* client)
  259. {
  260.     _clientCtxt = client;
  261.     if (_clientCtxt)
  262.         _Setup ();
  263. }
  264.  
  265.  
  266.  
  267. bool UI_Font::IsFixed () const
  268. {
  269.     return _entry ? ((UI_FontEntry*) _entry)->IsFixed() : TRUE;
  270. }
  271.  
  272.  
  273. long UI_Font::Height () const
  274. {
  275.     return _entry ? ((UI_FontEntry*) _entry)->Height() : 0;
  276. }
  277.  
  278.  
  279.  
  280. long UI_Font::Width () const
  281. {
  282.     return _entry ? ((UI_FontEntry*) _entry)->Width() : 0;
  283. }
  284.  
  285.  
  286.  
  287. #if defined(__MS_WINDOWS__)
  288. static UI_ResourceHandle _GetFontHandle (const UI_FontDesc& font,
  289.                                          HDC dev_ctxt)
  290. {
  291.     LOGFONT lf;
  292.     CL_String face = font.TypeFace();
  293.     if (face.Size() <= 0)
  294.         return GetStockObject (SYSTEM_FONT);
  295.     long   pixels_per_inch;
  296.     short  ptSize  = font.PointSize ();
  297.     ulong  style   = font.Style ();
  298.     
  299.     pixels_per_inch      = GetDeviceCaps (dev_ctxt, LOGPIXELSY);    
  300.     lf.lfHeight          =  (pixels_per_inch * ptSize)/72;
  301.     lf.lfWidth           = 0;
  302.     lf.lfEscapement      = 0;
  303.     lf.lfOrientation     = 0;
  304.     lf.lfWeight          = style & UIFont_BoldFace ? FW_BOLD:FW_NORMAL;
  305.     lf.lfItalic          = style & UIFont_Italic ? TRUE : FALSE;
  306.     lf.lfUnderline       = style & UIFont_Underline ? TRUE : FALSE;
  307.     lf.lfStrikeOut       = style & UIFont_StrikeOut ? TRUE : FALSE;
  308.     lf.lfCharSet         = DEFAULT_CHARSET;
  309.     lf.lfOutPrecision    = OUT_DEFAULT_PRECIS;
  310.     lf.lfClipPrecision   = CLIP_DEFAULT_PRECIS;
  311.     lf.lfQuality         = DEFAULT_QUALITY;
  312.     lf.lfPitchAndFamily  = DEFAULT_PITCH |FF_DONTCARE;
  313.  
  314.     for (short i = 0; i < face.Length() && i < LF_FACESIZE-1;i++)
  315.         lf.lfFaceName[i] = face[i];
  316.  
  317.     lf.lfFaceName[i]     = '\0';
  318.  
  319.     return (UI_ResourceHandle) CreateFontIndirect (&lf);
  320. }
  321.  
  322.  
  323. #elif defined(__OS2__)
  324. static UI_ResourceHandle _GetFontHandle (const UI_FontDesc& font,
  325.                                          HPS dev_ctxt)
  326. {
  327.     ulong style = font.Style ();
  328.     FATTRS fatr;
  329.     fatr.usRecordLength  = sizeof fatr;
  330.     fatr.lMatch          = 0;            // Do not force match
  331.     fatr.idRegistry      = 0;            // Use default registry
  332.     fatr.usCodePage      = 850;          // Code page 850
  333.     fatr.lMaxBaselineExt = 0;
  334.     fatr.lAveCharWidth   = 0;
  335.     fatr.fsType          = 0;
  336.     fatr.fsFontUse       = 0;
  337.     fatr.fsSelection     = 
  338.         (style & UIFont_Underline ? FATTR_SEL_UNDERSCORE : 0) |
  339.         (style & UIFont_Italic    ? FATTR_SEL_ITALIC     : 0) |
  340.         (style & UIFont_StrikeOut ? FATTR_SEL_STRIKEOUT  : 0) |
  341.         (style & UIFont_BoldFace  ? FATTR_SEL_BOLD       : 0);
  342.     CL_String faceName = font.TypeFace();
  343.     if (style & UIFont_BoldFace)
  344.         faceName += " Bold";
  345.     if (style & UIFont_Italic)
  346.         faceName += " Italic";
  347.     strcpy (fatr.szFacename, faceName.AsPtr());
  348.     UI_ResourceHandle h = _LocalIdSet.SmallestNonMember();
  349.     if (h > 254)
  350.         CL_Error::Warning ("Font: GetFontHandle: Too many fonts requested.");
  351.     if (GpiCreateLogFont (dev_ctxt, NULL, h, &fatr) == GPI_ERROR)
  352.         return 0;
  353.     _LocalIdSet.Add (h);
  354.     return h;
  355. }
  356. #endif
  357.  
  358.  
  359. long UI_Font::Width (const char* string) const
  360. {
  361.     if (_clientCtxt)
  362.         return _clientCtxt->TextWidth (string);
  363. #if defined(__X_MOTIF__)
  364.     return TextWidth (string);
  365. #elif defined(__OS2__)
  366.     HPS hps = WinGetPS (HWND_DESKTOP);
  367.     POINTL textBox[TXTBOX_COUNT];
  368.     GpiQueryTextBox (hps, strlen (string), (char*) string,
  369.                      TXTBOX_COUNT, textBox);
  370.     WinReleasePS (hps);
  371.     return textBox[TXTBOX_CONCAT].x;
  372. #elif defined(__MS_WINDOWS__)
  373.     HDC dev_ctxt = CreateDC ("DISPLAY", NULL, NULL, NULL);
  374.     if (dev_ctxt <= 0)
  375.         return 0;
  376.     UI_FontDesc desc (_typeFace, _ptSize, _style);
  377.     HFONT hFont = _GetFontHandle (desc, dev_ctxt);
  378.     CL_String s (string);
  379.     HFONT old = SelectObject (dev_ctxt, hFont);
  380.     long width = GetTextExtent (_handle, s.AsPtr(), s.Size());
  381.     SelectObject (dev_ctxt, old);
  382.     DeleteObject (hFont);
  383.     return width;
  384. #endif
  385. }
  386.  
  387.  
  388.  
  389.  
  390. short UI_Font::PointSize() const
  391. {
  392.     return _entry ? ((UI_FontEntry*) _entry)->PointSize() : _ptSize;
  393. }
  394.  
  395.  
  396.  
  397. CL_String UI_Font::TypeFace() const
  398. {
  399.     if (_entry)
  400.         return ((UI_FontEntry*) _entry)->TypeFace();
  401.     return _typeFace;
  402. }
  403.  
  404.  
  405.  
  406. bool UI_Font::Italic() const
  407. {
  408.     return _entry ? ((UI_FontEntry*) _entry)->Italic()
  409.         : (_style & UIFont_Italic);
  410. }
  411.  
  412.  
  413.  
  414. bool UI_Font::Underline() const
  415. {
  416.      return _entry ? ((UI_FontEntry*) _entry)->Underline()
  417.          : (_style & UIFont_Underline);
  418. }
  419.  
  420.  
  421.  
  422. bool UI_Font::BoldFace() const
  423. {
  424.     return _entry ?  ((UI_FontEntry*) _entry)->BoldFace()
  425.         :  (_style & UIFont_BoldFace);
  426. }
  427.  
  428.  
  429.  
  430. bool UI_Font::StrikeOut() const
  431. {
  432.     return _entry ? ((UI_FontEntry*) _entry)->StrikeOut()
  433.         :  (_style & UIFont_StrikeOut);
  434. }
  435.  
  436.  
  437. short UI_Font::Ascent () const
  438. {
  439.     return _entry ? ((UI_FontEntry*) _entry)->Ascent() : 0;
  440. }
  441.  
  442. short UI_Font::Descent () const
  443. {
  444.     return _entry ? ((UI_FontEntry*) _entry)->Descent() : 0;
  445. }
  446.  
  447. bool UI_Font::IsScalable () const
  448. {
  449.     return _entry ? ((UI_FontEntry*) _entry)->IsScalable() : FALSE;
  450. }
  451.  
  452.  
  453.  
  454. void UI_Font::PointSize (short sz)
  455. {
  456.     if (_ptSize == sz || !PrepareToChange())
  457.         return;
  458.     _ptSize = sz;
  459.     _handle = 0;
  460.     _stockFont = FALSE;
  461.     _Setup ();
  462.     Notify();
  463. }
  464.  
  465.  
  466.  
  467. void UI_Font::TypeFace (const char* str)
  468. {
  469.     if (_typeFace == str || !PrepareToChange())
  470.         return;
  471.     _typeFace = CL_String (str).InLowerCase ();
  472.     _handle = 0;
  473.     _stockFont = FALSE;
  474.     _Setup ();
  475.     Notify();
  476. }
  477.  
  478.  
  479.  
  480. void UI_Font::Italic (bool val)
  481. {
  482.     if ((_style & UIFont_Italic ? TRUE : FALSE) == val || !PrepareToChange())
  483.         return;
  484.     if (val)
  485.         _style |= UIFont_Italic;
  486.     else
  487.         _style &= ~UIFont_Italic;
  488.     _handle = 0;
  489.     _stockFont = FALSE;
  490.     _Setup ();
  491.     Notify();
  492. }
  493.  
  494.  
  495.  
  496. void UI_Font::Underline(bool val)
  497. {
  498.     if ((_style & UIFont_Underline ? TRUE : FALSE) == val ||
  499.         !PrepareToChange())
  500.         return;
  501.     if (val)
  502.         _style |= UIFont_Underline;
  503.     else
  504.         _style &= ~UIFont_Underline;
  505.     _handle = 0;
  506.     _stockFont = FALSE;
  507.     _Setup ();
  508.     Notify();
  509. }
  510.  
  511.  
  512.  
  513. void UI_Font::BoldFace(bool val)
  514. {
  515.     if ((_style & UIFont_BoldFace ? TRUE : FALSE) == val ||
  516.         !PrepareToChange())
  517.         return;
  518.     if (val)
  519.         _style |= UIFont_BoldFace;
  520.     else
  521.         _style &= ~UIFont_BoldFace;
  522.     _handle = 0;
  523.     _stockFont = FALSE;
  524.     _Setup ();
  525.     Notify();
  526. }
  527.  
  528.  
  529.  
  530. void UI_Font::StrikeOut(bool val)
  531. {
  532.     if ((_style & UIFont_StrikeOut ? TRUE : FALSE) == val ||
  533.         !PrepareToChange())
  534.         return;
  535.     if (val)
  536.         _style |= UIFont_StrikeOut;
  537.     else
  538.         _style &= ~UIFont_StrikeOut;
  539.     _handle = 0;
  540.     _stockFont = FALSE;
  541.     _Setup ();
  542.     Notify();
  543. }
  544.  
  545.  
  546.  
  547. #if defined(__OS2__)
  548.  
  549. static void _SetupPointSize (HPS hps, short pointSize)
  550. {
  551.     // This function is based on the code on Page 362 of Petzold's book.
  552.     LONG   xRes, yRes ;
  553.     SIZEF  sizef ;
  554.  
  555.     HDC hdc = GpiQueryDevice (hps) ;
  556.     DevQueryCaps (hdc, CAPS_HORIZONTAL_FONT_RES, 1, &xRes) ;
  557.     DevQueryCaps (hdc, CAPS_VERTICAL_FONT_RES,   1, &yRes) ;
  558. //     POINTL aptl[2] ;
  559. //     pointSize *= 10; // Because the following code uses decipoints
  560. //     aptl[0].x = 0 ;
  561. //     aptl[0].y = 0 ;
  562. //     static const int DPM = 28346; // # decipoints per meter
  563. //                                   //  (Petzold, p. 367) 
  564. //     static const int DPM2 = DPM/2;
  565. //     aptl[1].x = (16 * xRes * pointSize + DPM2) / DPM;
  566. //     aptl[1].y = (16 * yRes * pointSize + DPM2) / DPM;
  567. //     GpiConvert (hps, CVTC_DEVICE, CVTC_PAGE, 2L, aptl) ;
  568. //     sizef.cx = (aptl[1].x - aptl[0].x) << 12 ;
  569. //     sizef.cy = (aptl[1].y - aptl[0].y) << 12 ;
  570.     sizef.cx = MAKEFIXED (xRes * pointSize / 72, 0);
  571.     sizef.cy = MAKEFIXED (yRes * pointSize / 72, 0);
  572.     GpiSetCharBox (hps, &sizef) ;
  573. }
  574.  
  575. void  UI_Font::_Setup()
  576. {
  577.     // Under OS/2, we don't use the FontEntries set, because fonts are tied
  578.     // to presentation spaces under OS/2, unlike under Windows.
  579.     if (!_clientCtxt)
  580.         return;
  581.     UI_FontDesc desc (_typeFace, _ptSize, _style);
  582.     HPS dev_ctxt = _clientCtxt->Handle();
  583.     GpiSetCharSet (dev_ctxt, LCID_DEFAULT);
  584.     if (_handle)
  585.         GpiDeleteSetId (dev_ctxt, _handle);
  586.     UI_FontEntry* fe  = new UI_FontEntry
  587.         ((short) _ptSize, _typeFace, _nativeName,
  588.          _style, _stockFont);
  589.     if (!fe)
  590.         return; // No memory
  591.     _handle = _GetFontHandle (desc, dev_ctxt);
  592.     if (!GpiSetCharSet (dev_ctxt, _handle))
  593.         UI_Application::PMError();
  594.     _SetupPointSize (dev_ctxt, _ptSize);
  595.     fe->Handle (_handle);
  596.     fe->FetchFontData (dev_ctxt);
  597.     _height = fe->Height();
  598.     _width  = fe->Width();
  599.     if (_entry)
  600.         delete (UI_FontEntry*) _entry;
  601.     _entry = fe;
  602.     GpiSetCharSet (dev_ctxt, _handle);
  603. }
  604.  
  605.  
  606. #elif defined(__MS_WINDOWS__)
  607. void  UI_Font::_Setup()
  608. {
  609.     UI_FontEntry *fe  = new UI_FontEntry
  610.         ((short) _ptSize, _typeFace, _nativeName,
  611.          _style, _stockFont);
  612.     
  613.     UI_FontEntry* entry = (UI_FontEntry*) _FontEntries.Find (fe);
  614.  
  615.     bool    tmpDsplSfc   = FALSE;
  616.     UI_ResourceHandle dev_ctxt = 0;
  617.  
  618.     if (!entry) {
  619.         if (_clientCtxt)
  620.             dev_ctxt = _clientCtxt->Handle();
  621.         else {
  622.             dev_ctxt = CreateDC ("DISPLAY", NULL, NULL, NULL);
  623.             if (dev_ctxt <= 0)
  624.                 return;
  625.             tmpDsplSfc = TRUE;
  626.         }
  627.         UI_FontDesc desc (_typeFace, _ptSize, _style);
  628.         _handle = _GetFontHandle (desc, dev_ctxt);
  629.         fe->Handle (_handle);
  630.         fe->FetchFontData (dev_ctxt);
  631.         _height = fe->Height();
  632.         _width  = fe->Width();
  633.         if (tmpDsplSfc)
  634.             DeleteObject (dev_ctxt);
  635.         UI_FontEntry* alloc = (UI_FontEntry*) _FontEntries.Find (fe);
  636.         if (alloc) {
  637.             delete fe;
  638.             entry = alloc;
  639.         }
  640.         else {
  641.             entry = fe;
  642.             _FontEntries.Add (entry);
  643.         }
  644.     }
  645.     UI_FontEntry*  e = (UI_FontEntry*) _entry;
  646.     if (!e ||  e != entry) {
  647.         entry->AddReference ();
  648.         _entry    = entry;
  649.         _handle   = entry->Handle();
  650.         if (e) {
  651.             e->RemoveReference ();
  652.             if (e->RefCount() == 0) {
  653.                 _FontEntries.Remove (e);
  654.                 delete e;
  655.             }
  656.         }
  657.     }
  658.     else
  659.         _handle = entry->Handle();
  660.     if (!tmpDsplSfc && dev_ctxt)
  661.         SelectObject (dev_ctxt, _handle);
  662. }
  663.  
  664. #elif defined (__X_MOTIF__)
  665. void  UI_Font::_Setup()
  666. {
  667.     UI_FontEntry *fe  = new UI_FontEntry
  668.         ((short) _ptSize, _typeFace, _nativeName,
  669.          _style, _stockFont);
  670.     if (_entry && *(UI_FontEntry*) _entry == *fe)
  671.         return;
  672.     UI_FontEntry* entry = (UI_FontEntry*) _FontEntries.Find (fe);
  673.     Display* dpy = _TheApplication->Controller().AppDisplay();
  674.     int count = 0;
  675.     char **fontNames;
  676.     CL_String name;
  677.  
  678.     if (!entry) {
  679.         bool itals = FALSE;
  680.         CL_String ptString;
  681.         if (_nativeName.Size() == 0 || _nativeName.CharIndex ('-') >= 0) {
  682.             itals = _style & UIFont_Italic;
  683.             ptString = _ptSize > 0 ? CL_String (_ptSize)
  684.                  : CL_String("*");
  685.             name.AssignWithFormat ("-*-%s-%s-%c-*--%s-*-*-*-*-*-*-*", 
  686.                                    _typeFace.AsPtr(), 
  687.                                    _style & UIFont_BoldFace ? "bold": "medium",
  688.                                     (itals ? 'i' : 'r'), ptString.AsPtr());
  689.         }
  690.         else
  691.             name = _nativeName;
  692.         fontNames = XListFonts (dpy, (char *) name.AsPtr(), 1, &count);
  693.         if (itals && !fontNames) {
  694.             name.AssignWithFormat ("-*-%s-%s-%c-*--%s-*-*-*-*-*-*-*", 
  695.                                    _typeFace.AsPtr(), 
  696.                                    _style & UIFont_BoldFace ? "bold": "medium",
  697.                                    'o' , ptString.AsPtr()); 
  698.             fontNames = XListFonts (dpy, (char *) name.AsPtr(), 1, &count);
  699.         }
  700.         if (fontNames == NULL) {
  701.             CL_Error::Warning ("UI_Font::_Setup(): Font %s not matched",
  702.                                name.AsPtr());
  703.             _handle = 0;
  704.             return;
  705.         }
  706.         _nativeName = name;
  707.         _handle = (UI_ResourceHandle) XLoadFont (dpy, fontNames [0]);
  708.         fe->Handle (_handle);
  709.         fe->FetchFontData (_handle);
  710.         entry = fe;
  711.         _FontEntries.Add (entry);
  712.         XFreeFontNames (fontNames);
  713.     }
  714.  
  715.     UI_FontEntry*  e = (UI_FontEntry*) _entry;
  716.     if (!e ||  e != entry) {
  717.         entry->AddReference ();
  718.         _entry    = entry;
  719.         _handle   = entry->Handle();
  720.         if (e) {
  721.             e->RemoveReference ();
  722.             if (e->RefCount() == 0) {
  723.                 _FontEntries.Remove (e);
  724.                 delete e;
  725.             }
  726.         }
  727.     }
  728.  
  729. }
  730.     
  731. #endif
  732.   
  733.  
  734.  
  735.  
  736.  
  737. #if defined(__MS_WINDOWS__) || defined(__X_MOTIF__)
  738. void  UI_Font::_Setup (UI_NativeFontRep nativerep)
  739. {
  740. #if defined(__MS_WINDOWS__)
  741.     LOGFONT lf;
  742.     
  743.     _handle = GetStockObject (nativerep);
  744.     GetObject (_handle, sizeof (LOGFONT), (LPSTR) &lf);
  745.     _ptSize    = DEFAULT_POINT_SIZE;
  746.     _style = 0;
  747.     if (lf.lfWeight ==  FW_BOLD)
  748.         _style |= UIFont_BoldFace;
  749.     if (lf.lfItalic)
  750.         _style |= UIFont_Italic;
  751.     if (lf.lfStrikeOut)
  752.         _style |= UIFont_StrikeOut;
  753.     if (lf.lfUnderline)
  754.         _style |= UIFont_Underline;
  755.     
  756. #elif defined (__X_MOTIF__)
  757.     int count     = 0;
  758.     if (nativerep.CharIndex ('-') < 0) {
  759.         // No '-' in the font name: maybe something like 9x15
  760.         _ptSize = 0;
  761.         _style = 0;
  762.         _typeFace = nativerep;
  763.         _nativeName = nativerep;
  764.     }
  765.     else {
  766.         long ptsize   = nativerep.Field (6, "-").AsLong ();
  767.         CL_String tf  = nativerep.Field (2, "-");
  768.         bool italic   = nativerep.Field (4, "-") [0] == 'o';
  769.         bool ul       = FALSE;
  770.         bool boldface = nativerep.Field (3, "-") == (const char *)"bold";
  771.         bool so       = FALSE;
  772.  
  773.         _ptSize       = ptsize;
  774.         _typeFace     = tf;
  775.         _style |= (italic   ? UIFont_Italic     : 0) |
  776.                   (ul       ? UIFont_Underline  : 0) |
  777.                   (boldface ? UIFont_BoldFace   : 0) |
  778.                   (so       ? UIFont_StrikeOut  : 0);
  779.     }
  780.     _nativeName   = nativerep;
  781.  
  782. #endif    
  783.  
  784.     _Setup();
  785. }
  786. #endif // defined(__MS_WINDOWS__) || defined(__X_MOTIF__)
  787.  
  788.  
  789. void UI_Font::operator= (const UI_FontDesc& o)
  790. {
  791.     if (!PrepareToChange())
  792.         return;
  793.     _typeFace  = o.TypeFace();
  794.     _ptSize    = o.PointSize();
  795.     _style     = o.Style();
  796.     _stockFont = FALSE;
  797. #if defined(__X_MOTIF__)
  798.     _nativeName = "";
  799. #elif defined(__MS_WINDOWS__)
  800.     _nativeName = 0;
  801. #elif defined(__OS2__)
  802.     _nativeName = 0;
  803. #endif
  804.     _Setup ();
  805.     Notify();
  806. }
  807.  
  808.  
  809. void UI_Font::operator= (const CL_Object& o)
  810. {
  811.     if (CL_String (o.ClassName()) != "UI_FontDesc") // Must use RTTI
  812.         return;
  813.     *this = (const UI_FontDesc&) o;
  814. }
  815.  
  816. #if defined(__X_MOTIF__)
  817. long UI_Font::TextWidth (const CL_String& s) const
  818. {
  819.     UI_FontEntry* entry = (UI_FontEntry*) _entry;
  820.     if (!_entry)
  821.         return 0;
  822.     return XTextWidth (entry->_font, s.AsPtr(), s.Size());
  823. }
  824. #endif
  825.  
  826.  
  827. void* UI_Font::NativeFontStruct () const
  828. {
  829.     UI_FontEntry* entry = (UI_FontEntry*) _entry;
  830.     if (!entry)
  831.         return 0;
  832. #if defined(__X_MOTIF__)
  833.     return entry->_font;
  834. #else
  835.     return &(entry->_font);
  836. #endif
  837. }
  838.  
  839. #if defined(__X_MOTIF__)
  840. void UI_Font::operator= (const char* name)
  841. {
  842.     _Setup (name);
  843. }
  844.  
  845. #endif
  846.  
  847.  
  848. // ---------------------- Font enumeration method ------------------------
  849.  
  850. #if defined(__X_MOTIF__)
  851.  
  852. const CL_Sequence<UI_FontInfo>& UI_Font::AvailableFonts ()
  853. {
  854.     Display *dpy = XtDisplay (_TheApplication->Controller().ShellWidget());
  855.     int count;
  856.     char* fontSpec = "-*-*-*-*-*--*-*-*-*-*-*-*-*";
  857.     char** fontNames = XListFonts (dpy, "*", 10000, &count);
  858.     if (!fontNames || count <= 0)
  859.         return _allFonts;
  860.     for (long i = 0; i < count; i++) {
  861.         long style = 0;
  862.         CL_String field[12];
  863.         CL_String name = fontNames[i];
  864.         short n = name.Split (field, 11, "-");
  865.         if (n <= 2) 
  866.             continue;
  867.         unsigned long val;
  868.         short points;
  869.         if (field[3] == "o" || field[3] == "i")
  870.             style |= UIFont_Italic;
  871.         if (field[2] == "bold")
  872.             style |= UIFont_BoldFace;
  873.         points = field[6].AsLong() / 10;
  874.         UI_FontInfo f (field[1], points, style);
  875.         if (points == 0) {
  876.             f._ptSize = 0;
  877.             f._scalable = TRUE;
  878.         }
  879.         f._fixedWidth = field[10] == "m";
  880.         _allFonts.Add (f);
  881.     }
  882.     XFreeFontNames (fontNames);
  883.     _allFonts.Sort();
  884.     return _allFonts;
  885. }
  886.  
  887. #elif defined(__MS_WINDOWS__)
  888.  
  889. int CALLBACK GetFontNames (LOGFONT FAR* lpnlf, TEXTMETRIC FAR*, int,
  890.                            LPSTR lParam)
  891. {
  892.     CL_StringSequence& names = *(CL_StringSequence*) lParam;
  893.     names.Add (lpnlf->lfFaceName);
  894.     return 1;
  895. }
  896.  
  897.  
  898. int CALLBACK GetFonts (LOGFONT FAR* lpnlf, TEXTMETRIC FAR* tm, int type,
  899.                        LPSTR)
  900. {
  901.     UI_Font::_AddFont (lpnlf, tm, type);
  902.     return 1;
  903. }
  904.  
  905.  
  906. void UI_Font::_AddFont (void* p, void* q, int type)
  907. {
  908.     LOGFONT* lpnlf = (LOGFONT*) p;
  909.     TEXTMETRIC FAR* tm = (TEXTMETRIC FAR*) q;
  910.     ulong style =
  911.         (lpnlf->lfWeight == FW_BOLD ? UIFont_BoldFace  : 0) |
  912.         (lpnlf->lfItalic            ? UIFont_Italic    : 0) |
  913.         (lpnlf->lfUnderline         ? UIFont_Underline : 0) |
  914.         (lpnlf->lfStrikeOut         ? UIFont_StrikeOut : 0);
  915.     
  916.     short ptSize = (72*(long) tm->tmHeight) / maxl (1, _ppi);
  917.     UI_FontInfo info (lpnlf->lfFaceName, ptSize, style,
  918.                       type == TRUETYPE_FONTTYPE);
  919.     _allFonts.Add (info);
  920. }
  921.     
  922. const CL_Sequence<UI_FontInfo>& UI_Font::AvailableFonts ()
  923. {
  924.     HDC dc = CreateDC ("DISPLAY", NULL, NULL, NULL);
  925.     if (dc == 0)
  926.         return _allFonts; // Failed
  927.     _ppi =  GetDeviceCaps (dc, LOGPIXELSY);
  928.     CL_StringSequence fontNames;
  929.     EnumFontFamilies (dc, NULL, (FONTENUMPROC) GetFontNames,
  930.                       (LPSTR) &fontNames);
  931.     long n = fontNames.Size();
  932.     for (long i = 0; i < n; i++)
  933.         EnumFontFamilies (dc, fontNames[i].AsPtr(),
  934.                           (FONTENUMPROC) GetFonts, (LPSTR) &_allFonts);
  935.     _allFonts.Sort();
  936.     DeleteDC (dc);
  937.     return _allFonts;
  938. }
  939.  
  940.  
  941. #elif defined (__OS2__)
  942.  
  943. const CL_Sequence<UI_FontInfo>& UI_Font::AvailableFonts ()
  944. {
  945.     HPS hps = WinGetPS (HWND_DESKTOP);
  946.     if (hps == 0)
  947.         return _allFonts; // Failed
  948.     LONG nFonts = 0;
  949.     nFonts = GpiQueryFonts (hps, QF_PUBLIC, NULL, &nFonts, 0, NULL);
  950.     PFONTMETRICS pfm = new FONTMETRICS [nFonts];
  951.     if (!pfm)
  952.         return _allFonts; // No memory
  953.     GpiQueryFonts (hps, QF_PUBLIC, NULL, &nFonts, sizeof (FONTMETRICS), pfm);
  954.     for (long i = 0; i < nFonts; i++) {
  955.         ulong style =
  956.             (pfm[i].fsSelection & FM_SEL_BOLD      ? UIFont_BoldFace  : 0) |
  957.             (pfm[i].fsSelection & FM_SEL_ITALIC    ? UIFont_Italic    : 0) |
  958.             (pfm[i].fsSelection & FM_SEL_STRIKEOUT ? UIFont_StrikeOut : 0) |
  959.             (pfm[i].fsSelection & FM_SEL_UNDERSCORE? UIFont_Underline : 0);
  960.         short ptSize = pfm[i].sNominalPointSize / 10;
  961.         UI_FontInfo info (pfm[i].szFacename, ptSize, style,
  962.                           pfm[i].fsDefn & FM_DEFN_OUTLINE ? TRUE : FALSE);
  963.         _allFonts.Add (info);
  964.     }
  965.     delete [] pfm;
  966.     WinReleasePS (hps);
  967.     _allFonts.Sort();
  968.     return _allFonts;
  969. }
  970.  
  971. #endif
  972.  
  973.  
  974.  
  975.  
  976.  
  977. ///////////////////////////////////////////////////////////////////////////
  978. // FontEntry:
  979. ///////////////////////////////////////////////////////////////////////////
  980.  
  981.  
  982. UI_FontEntry::UI_FontEntry (short pt, const char* tf,
  983.                             UI_NativeFontRep nm, ulong style,
  984.                             bool  sf
  985.                            )
  986. : UI_FontDesc (tf, pt, style)
  987. {
  988.     _nativeName = nm;
  989.     _stockfont  = sf;
  990.     _refcnt     = 0;
  991.     _handle = 0;
  992. }
  993.  
  994.  
  995.  
  996. UI_FontEntry::~UI_FontEntry()
  997. {
  998. #if defined(__MS_WINDOWS__)
  999.     if (_handle && _typeFace.InLowerCase() != "system") {
  1000.         DeleteObject((HANDLE) _handle);
  1001.     }
  1002. #elif defined(__OS2__)
  1003.     if (_handle)
  1004.         _LocalIdSet.Remove (_handle);
  1005. #elif defined(__X_MOTIF__)
  1006.     if (_handle) {
  1007.         Display *dpy = XtDisplay
  1008.             (_TheApplication->Controller().ShellWidget()); 
  1009.         XFreeFont (dpy, _font);
  1010.     }
  1011. #endif
  1012. }
  1013.  
  1014.  
  1015. void UI_FontEntry::FetchFontData (UI_ResourceHandle dev_ctxt)
  1016. {
  1017. #if defined (__MS_WINDOWS__)
  1018.     if (!dev_ctxt)
  1019.         return;
  1020.     
  1021.     TEXTMETRIC tm;
  1022.     HANDLE old_font      = SelectObject (dev_ctxt, _handle);
  1023.     long pixels_per_inch = GetDeviceCaps (dev_ctxt, LOGPIXELSY);
  1024.     
  1025.     if (!pixels_per_inch)
  1026.         return;
  1027.     GetTextMetrics (dev_ctxt, &tm);
  1028.     char faceName [LF_FACESIZE];
  1029.     GetTextFace  (dev_ctxt, LF_FACESIZE-1,faceName);
  1030.     SelectObject (dev_ctxt, old_font);
  1031.     
  1032.     _ptSize    = (72*(long) tm.tmHeight) / ((long) pixels_per_inch);
  1033.     _font      = tm;
  1034.     _typeFace  = faceName;
  1035.     _style     =
  1036.         (_font.tmWeight == FW_BOLD ? UIFont_BoldFace  : 0) |
  1037.         (_font.tmItalic            ? UIFont_Italic    : 0) |
  1038.         (_font.tmStruckOut         ? UIFont_StrikeOut : 0) |
  1039.         (_font.tmUnderlined        ? UIFont_Underline : 0);
  1040.  
  1041. #elif defined(__OS2__)
  1042.     if (!dev_ctxt)
  1043.         return;
  1044.     FONTMETRICS fm;
  1045.     GpiQueryFontMetrics (dev_ctxt, sizeof (FONTMETRICS), &fm);
  1046.     long yRes;
  1047.     HDC hdc = GpiQueryDevice (dev_ctxt) ;
  1048.     DevQueryCaps (hdc, CAPS_VERTICAL_FONT_RES,   1, &yRes) ;
  1049.     _ptSize    = fm.lEmHeight * 72 / maxl (1, yRes);
  1050.     _font      = fm;
  1051.     _typeFace  = fm.szFacename;
  1052.     _style     =
  1053.         (fm.fsSelection & FATTR_SEL_UNDERSCORE ? UIFont_Underline : 0) |
  1054.         (fm.fsSelection & FATTR_SEL_ITALIC     ? UIFont_Italic    : 0) |
  1055.         (fm.fsSelection & FATTR_SEL_STRIKEOUT  ? UIFont_StrikeOut : 0) |
  1056.         (fm.fsSelection & FATTR_SEL_BOLD       ? UIFont_BoldFace  : 0);
  1057. #elif defined (__X_MOTIF__)
  1058.     Display *dpy = XtDisplay (_TheApplication->Controller().ShellWidget());
  1059.     _font  = XQueryFont (dpy, _handle);
  1060. #endif
  1061. }
  1062.  
  1063.  
  1064.  
  1065. bool UI_FontEntry::IsFixed ()
  1066. {
  1067. #if defined (__MS_WINDOWS__)
  1068.     return (_font.tmPitchAndFamily & 0x0f) == FIXED_PITCH;
  1069.     // Check the four low-order bits
  1070. #elif defined(__OS2__)
  1071.     return _font.fsType & FM_TYPE_FIXED ? TRUE : FALSE;
  1072. #elif defined (__X_MOTIF__)    
  1073.     return _typeFace == "fixed" || _nativeName.Field (10, "-") == "m";
  1074. #endif
  1075. }
  1076.  
  1077. short UI_FontEntry::Height () const
  1078. {
  1079. #if defined (__MS_WINDOWS__)
  1080.     return _font.tmHeight;
  1081. #elif defined (__OS2__)
  1082.     return _font.lMaxAscender + _font.lMaxDescender;
  1083. #elif defined (__X_MOTIF__)    
  1084.     return _font ? (_font->max_bounds.ascent + _font->max_bounds.descent)
  1085.         : 0;
  1086. #endif
  1087. }
  1088.  
  1089.  
  1090.  
  1091. short UI_FontEntry::Width () const
  1092. {
  1093. #if defined (__MS_WINDOWS__)
  1094.     return _font.tmAveCharWidth;
  1095. #elif defined (__OS2__)
  1096.     return _font.lAveCharWidth;
  1097. #elif defined (__X_MOTIF__)
  1098.     return _font->max_bounds.rbearing - _font->min_bounds.lbearing;
  1099.  
  1100. #endif
  1101. }
  1102.  
  1103. short UI_FontEntry::Ascent () const
  1104. {
  1105. #if defined (__MS_WINDOWS__)
  1106.     return _font.tmAscent;
  1107. #elif defined(__OS2__)
  1108.     return _font.lMaxAscender;
  1109. #elif defined (__X_MOTIF__)
  1110.     return _font->ascent;
  1111.  
  1112. #endif
  1113. }
  1114.  
  1115.  
  1116. short UI_FontEntry::Descent () const
  1117. {
  1118. #if defined (__MS_WINDOWS__)
  1119.     return _font.tmDescent;
  1120. #elif defined(__OS2__)
  1121.     return _font.lMaxDescender;
  1122. #elif defined (__X_MOTIF__)
  1123.     return _font->descent;
  1124.  
  1125. #endif
  1126. }
  1127.  
  1128.  
  1129. bool UI_FontEntry::IsScalable () const
  1130. {
  1131. #if defined (__MS_WINDOWS__)
  1132.     return (_font.tmPitchAndFamily & TMPF_VECTOR) ? TRUE : FALSE;
  1133. #elif defined (__OS2__)
  1134.     return _font.fsDefn & FM_DEFN_OUTLINE ? TRUE : FALSE;
  1135. #elif defined (__X_MOTIF__)
  1136.     return _nativeName.Field (6, "-") == 0;
  1137.  
  1138. #endif
  1139. }
  1140.  
  1141.  
  1142.