1 /* FontSimple.c- simplified font configuration panel
3 * WPrefs - Window Maker Preferences Program
5 * Copyright (c) 1998-2004 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
26 #include <fontconfig/fontconfig.h>
29 /* workaround for older fontconfig, that doesn't define these constants */
30 #ifndef FC_WEIGHT_NORMAL
32 # define FC_WEIGHT_THIN 10
33 # define FC_WEIGHT_EXTRALIGHT 40
34 # define FC_WEIGHT_ULTRALIGHT FC_WEIGHT_EXTRALIGHT
35 # define FC_WEIGHT_REGULAR 80
36 # define FC_WEIGHT_NORMAL FC_WEIGHT_REGULAR
37 # define FC_WEIGHT_SEMIBOLD FC_WEIGHT_DEMIBOLD
38 # define FC_WEIGHT_EXTRABOLD 205
39 # define FC_WEIGHT_ULTRABOLD FC_WEIGHT_EXTRABOLD
40 # define FC_WEIGHT_HEAVY FC_WEIGHT_BLACK
42 # define FC_WIDTH "width"
43 # define FC_WIDTH_ULTRACONDENSED 50
44 # define FC_WIDTH_EXTRACONDENSED 63
45 # define FC_WIDTH_CONDENSED 75
46 # define FC_WIDTH_SEMICONDENSED 87
47 # define FC_WIDTH_NORMAL 100
48 # define FC_WIDTH_SEMIEXPANDED 113
49 # define FC_WIDTH_EXPANDED 125
50 # define FC_WIDTH_EXTRAEXPANDED 150
51 # define FC_WIDTH_ULTRAEXPANDED 200
55 #define SAMPLE_TEXT "The Lazy Fox Jumped Ipsum Foobar 1234 - 56789"
77 typedef struct _Panel
{
83 CallbackRec callbacks
;
87 WMPopUpButton
*optionP
;
100 #define ICON_FILE "fonts"
107 {"WindowTitleFont", N_("Window Title")},
108 {"MenuTitleFont", N_("Menu Title")},
109 {"MenuTextFont", N_("Menu Text")},
110 {"IconTitleFont", N_("Icon Title")},
111 {"ClipTitleFont", N_("Clip Title")},
112 {"LargeDisplayFont", N_("Desktop Caption")},
117 static char *standardSizes
[]= {
146 {FC_WEIGHT_THIN
, "Thin"},
147 {FC_WEIGHT_EXTRALIGHT
, "ExtraLight"},
148 {FC_WEIGHT_LIGHT
, "Light"},
149 {FC_WEIGHT_NORMAL
, "Normal"},
150 {FC_WEIGHT_MEDIUM
, ""}, /*"medium"},*/
151 {FC_WEIGHT_DEMIBOLD
, "DemiBold"},
152 {FC_WEIGHT_BOLD
, "Bold"},
153 {FC_WEIGHT_EXTRABOLD
, "ExtraBold"},
154 {FC_WEIGHT_BLACK
, "Black"},
162 {FC_SLANT_ROMAN
, ""}, /*"Roman"},*/
163 {FC_SLANT_ITALIC
, "Italic"},
164 {FC_SLANT_OBLIQUE
, "Oblique"},
172 {FC_WIDTH_ULTRACONDENSED
, "UltraCondensed"},
173 {FC_WIDTH_EXTRACONDENSED
, "ExtraCondensed"},
174 {FC_WIDTH_CONDENSED
, "Condensed"},
175 {FC_WIDTH_SEMICONDENSED
, "SemiCondensed"},
176 {FC_WIDTH_NORMAL
, ""}, /*"normal"},*/
177 {FC_WIDTH_SEMIEXPANDED
, "SemiExpanded"},
178 {FC_WIDTH_EXPANDED
, "Expanded"},
179 {FC_WIDTH_EXTRAEXPANDED
, "ExtraExpanded"},
180 {FC_WIDTH_ULTRAEXPANDED
, "UltraExpanded"},
188 static int compare_family(const void *a
, const void *b
)
190 FontFamily
*fa
= (FontFamily
*)a
;
191 FontFamily
*fb
= (FontFamily
*)b
;
192 return strcmp(fa
->name
, fb
->name
);
196 static int compare_styles(const void *a
, const void *b
)
198 FontStyle
*sa
= (FontStyle
*)a
;
199 FontStyle
*sb
= (FontStyle
*)b
;
202 compare
= sa
->weight
- sb
->weight
;
205 compare
= sa
->slant
- sb
->slant
;
208 return (sa
->width
- sb
->width
);
213 lookup_available_fonts(_Panel
*panel
)
215 FcPattern
*pat
= FcPatternCreate();
220 os
= FcObjectSetBuild(FC_FAMILY
, FC_WEIGHT
, FC_WIDTH
, FC_SLANT
, NULL
);
222 fonts
= FcFontList(0, pat
, os
);
228 panel
->fonts
= wmalloc(sizeof(FontList
));
229 panel
->fonts
->familyn
= 0;
230 panel
->fonts
->families
= wmalloc(sizeof(FontFamily
)*fonts
->nfont
);
232 for (i
= 0; i
< fonts
->nfont
; i
++)
235 int weight
, slant
, width
;
238 if (FcPatternGetString(fonts
->fonts
[i
], FC_FAMILY
, 0, (FcChar8
**)&name
) != FcResultMatch
)
241 if (FcPatternGetInteger(fonts
->fonts
[i
], FC_WEIGHT
, 0, &weight
) != FcResultMatch
)
242 weight
= FC_WEIGHT_MEDIUM
;
244 if (FcPatternGetInteger(fonts
->fonts
[i
], FC_WIDTH
, 0, &width
) != FcResultMatch
)
245 width
= FC_WIDTH_NORMAL
;
247 if (FcPatternGetInteger(fonts
->fonts
[i
], FC_SLANT
, 0, &slant
) != FcResultMatch
)
248 slant
= FC_SLANT_ROMAN
;
251 for (j
= 0; j
< panel
->fonts
->familyn
&& found
<0; j
++)
252 if (strcasecmp(panel
->fonts
->families
[j
].name
, name
)==0)
257 panel
->fonts
->families
[panel
->fonts
->familyn
++].name
= wstrdup(name
);
258 family
= panel
->fonts
->families
+ panel
->fonts
->familyn
-1;
260 family
->styles
= NULL
;
263 family
= panel
->fonts
->families
+found
;
266 family
->styles
= wrealloc(family
->styles
, sizeof(FontStyle
)*family
->stylen
);
267 family
->styles
[family
->stylen
-1].weight
= weight
;
268 family
->styles
[family
->stylen
-1].slant
= slant
;
269 family
->styles
[family
->stylen
-1].width
= width
;
271 qsort(panel
->fonts
->families
, panel
->fonts
->familyn
, sizeof(FontFamily
),
274 for (i
=0; i
< panel
->fonts
->familyn
; i
++)
276 qsort(panel
->fonts
->families
[i
].styles
, panel
->fonts
->families
[i
].stylen
,
277 sizeof(FontStyle
), compare_styles
);
280 FcFontSetDestroy(fonts
);
283 FcObjectSetDestroy(os
);
285 FcPatternDestroy(pat
);
287 panel
->fonts
->families
[panel
->fonts
->familyn
++].name
= wstrdup("sans serif");
288 family
= panel
->fonts
->families
+ panel
->fonts
->familyn
-1;
289 family
->styles
= wmalloc(sizeof(FontStyle
)*2);
291 family
->styles
[0].weight
= FC_WEIGHT_MEDIUM
;
292 family
->styles
[0].slant
= FC_SLANT_ROMAN
;
293 family
->styles
[0].width
= FC_WIDTH_NORMAL
;
294 family
->styles
[1].weight
= FC_WEIGHT_BOLD
;
295 family
->styles
[1].slant
= FC_SLANT_ROMAN
;
296 family
->styles
[1].width
= FC_WIDTH_NORMAL
;
298 panel
->fonts
->families
[panel
->fonts
->familyn
++].name
= wstrdup("serif");
299 family
= panel
->fonts
->families
+ panel
->fonts
->familyn
-1;
300 family
->styles
= wmalloc(sizeof(FontStyle
)*2);
302 family
->styles
[0].weight
= FC_WEIGHT_MEDIUM
;
303 family
->styles
[0].slant
= FC_SLANT_ROMAN
;
304 family
->styles
[0].width
= FC_WIDTH_NORMAL
;
305 family
->styles
[1].weight
= FC_WEIGHT_BOLD
;
306 family
->styles
[1].slant
= FC_SLANT_ROMAN
;
307 family
->styles
[1].width
= FC_WIDTH_NORMAL
;
312 getSelectedFont(_Panel
*panel
, FcChar8
*curfont
)
319 pat
= FcNameParse(curfont
);
321 pat
= FcPatternCreate();
323 item
= WMGetListSelectedItem(panel
->familyL
);
326 FcPatternDel(pat
, FC_FAMILY
);
327 FcPatternAddString(pat
, FC_FAMILY
, (FcChar8
*)item
->text
);
330 item
= WMGetListSelectedItem(panel
->styleL
);
333 FontStyle
*style
= (FontStyle
*)item
->clientData
;
335 FcPatternDel(pat
, FC_WEIGHT
);
336 FcPatternAddInteger(pat
, FC_WEIGHT
, style
->weight
);
338 FcPatternDel(pat
, FC_WIDTH
);
339 FcPatternAddInteger(pat
, FC_WIDTH
, style
->width
);
341 FcPatternDel(pat
, FC_SLANT
);
342 FcPatternAddInteger(pat
, FC_SLANT
, style
->slant
);
345 item
= WMGetListSelectedItem(panel
->sizeL
);
348 FcPatternDel(pat
, FC_PIXEL_SIZE
);
349 FcPatternAddDouble(pat
, FC_PIXEL_SIZE
, atoi(item
->text
));
352 name
= (char*)FcNameUnparse(pat
);
353 FcPatternDestroy(pat
);
361 updateSampleFont(_Panel
*panel
)
363 WMMenuItem
*item
= WMGetPopUpButtonMenuItem(panel
->optionP
,
364 WMGetPopUpButtonSelectedItem(panel
->optionP
));
365 char *fn
= WMGetMenuItemRepresentedObject(item
);
368 WMFont
*font
= WMCreateFont(WMWidgetScreen(panel
->box
), fn
);
370 WMSetTextFieldFont(panel
->sampleT
, font
);
380 selectedFamily(WMWidget
*w
, void *data
)
382 _Panel
*panel
= (_Panel
*)data
;
384 FontStyle
*oldStyle
= NULL
;
387 item
= WMGetListSelectedItem(panel
->styleL
);
389 oldStyle
= (FontStyle
*)item
->clientData
;
391 item
= WMGetListSelectedItem(panel
->familyL
);
395 FontFamily
*family
= (FontFamily
*)item
->clientData
;
396 int i
, oldi
= 0, oldscore
= 0;
398 WMClearList(panel
->styleL
);
399 for (i
= 0; i
< family
->stylen
; i
++)
402 char *weight
= "", *slant
= "", *width
= "";
405 for (j
= 0; fontWeights
[j
].name
; j
++)
406 if (fontWeights
[j
].weight
== family
->styles
[i
].weight
)
408 weight
= fontWeights
[j
].name
;
411 for (j
= 0; fontWidths
[j
].name
; j
++)
412 if (fontWidths
[j
].width
== family
->styles
[i
].width
)
414 width
= fontWidths
[j
].name
;
417 for (j
= 0; fontSlants
[j
].name
; j
++)
418 if (fontSlants
[j
].slant
== family
->styles
[i
].slant
)
420 slant
= fontSlants
[j
].name
;
423 sprintf(buffer
, "%s%s%s%s%s",
424 weight
, *weight
?" ":"",
425 slant
, (*slant
|| *weight
)?" ":"",
428 strcpy(buffer
, "Roman");
430 item
= WMAddListItem(panel
->styleL
, buffer
);
431 item
->clientData
= family
->styles
+i
;
436 if (oldStyle
->width
== family
->styles
[i
].width
)
438 if (oldStyle
->weight
== family
->styles
[i
].weight
)
440 if (oldStyle
->slant
== family
->styles
[i
].slant
)
443 if (score
> oldscore
)
450 WMSelectListItem(panel
->styleL
, oldi
);
453 int index
= WMGetPopUpButtonSelectedItem(panel
->optionP
);
454 WMMenuItem
*item
= WMGetPopUpButtonMenuItem(panel
->optionP
, index
);
458 ofont
= (FcChar8
*)WMGetMenuItemRepresentedObject(item
);
459 nfont
= getSelectedFont(panel
, ofont
);
462 WMSetMenuItemRepresentedObject(item
, nfont
);
464 updateSampleFont(panel
);
470 selected(WMWidget
*w
, void *data
)
472 _Panel
*panel
= (_Panel
*)data
;
473 int index
= WMGetPopUpButtonSelectedItem(panel
->optionP
);
474 WMMenuItem
*item
= WMGetPopUpButtonMenuItem(panel
->optionP
, index
);
478 ofont
= (FcChar8
*)WMGetMenuItemRepresentedObject(item
);
479 nfont
= getSelectedFont(panel
, ofont
);
483 WMSetMenuItemRepresentedObject(item
, nfont
);
485 updateSampleFont(panel
);
490 selectedOption(WMWidget
*w
, void *data
)
492 _Panel
*panel
= (_Panel
*)data
;
493 int index
= WMGetPopUpButtonSelectedItem(panel
->optionP
);
494 WMMenuItem
*item
= WMGetPopUpButtonMenuItem(panel
->optionP
, index
);
497 font
= (char*)WMGetMenuItemRepresentedObject(item
);
502 pat
= FcNameParse((FcChar8
*)font
);
506 int weight
, slant
, width
;
508 int distance
, closest
, found
;
511 FcDefaultSubstitute(pat
);
513 if (FcPatternGetString(pat
, FC_FAMILY
, 0, (FcChar8
**)&name
) != FcResultMatch
)
518 for (i
= 0; i
< WMGetListNumberOfRows(panel
->familyL
); i
++)
520 WMListItem
*item
= WMGetListItem(panel
->familyL
, i
);
521 FontFamily
*family
= (FontFamily
*)item
->clientData
;
523 if (strcasecmp(family
->name
, name
)==0)
526 WMSelectListItem(panel
->familyL
, i
);
527 WMSetListPosition(panel
->familyL
, i
);
532 WMSelectListItem(panel
->familyL
, -1);
533 selectedFamily(panel
->familyL
, panel
);
536 if (FcPatternGetInteger(pat
, FC_WEIGHT
, 0, &weight
) != FcResultMatch
)
537 weight
= FC_WEIGHT_NORMAL
;
538 if (FcPatternGetInteger(pat
, FC_WIDTH
, 0, &width
) != FcResultMatch
)
539 width
= FC_WIDTH_NORMAL
;
540 if (FcPatternGetInteger(pat
, FC_SLANT
, 0, &slant
) != FcResultMatch
)
541 slant
= FC_SLANT_ROMAN
;
543 if (FcPatternGetDouble(pat
, FC_PIXEL_SIZE
, 0, &size
) != FcResultMatch
)
546 for (i
=0, found
=0, closest
=0; i
< WMGetListNumberOfRows(panel
->styleL
); i
++)
548 WMListItem
*item
= WMGetListItem(panel
->styleL
, i
);
549 FontStyle
*style
= (FontStyle
*)item
->clientData
;
551 distance
= ((abs(style
->weight
- weight
) << 16) +
552 (abs(style
->slant
- slant
) << 8) +
553 (abs(style
->width
- width
)));
555 if (i
==0 || distance
< closest
) {
559 break; /* perfect match */
563 WMSelectListItem(panel
->styleL
, found
);
564 WMSetListPosition(panel
->styleL
, found
);
566 for (i
=0, found
=0, closest
=0; i
< WMGetListNumberOfRows(panel
->sizeL
); i
++)
568 WMListItem
*item
= WMGetListItem(panel
->sizeL
, i
);
571 distance
= abs(size
- atoi(item
->text
));
573 if (i
==0 || distance
< closest
) {
577 break; /* perfect match */
581 WMSelectListItem(panel
->sizeL
, found
);
582 WMSetListPosition(panel
->sizeL
, found
);
584 selected(NULL
, panel
);
587 wwarning("Can't parse font '%s'", font
);
590 updateSampleFont(panel
);
595 createListLabel(WMScreen
*scr
, WMWidget
*parent
, char *text
)
599 WMFont
*boldFont
= WMBoldSystemFontOfSize(scr
, 12);
601 label
= WMCreateLabel(parent
);
602 WMSetLabelFont(label
, boldFont
);
603 WMSetLabelText(label
, text
);
604 WMSetLabelRelief(label
, WRSunken
);
605 WMSetLabelTextAlignment(label
, WACenter
);
606 color
= WMDarkGrayColor(scr
);
607 WMSetWidgetBackgroundColor(label
, color
);
608 WMReleaseColor(color
);
609 color
= WMWhiteColor(scr
);
610 WMSetLabelTextColor(label
, color
);
611 WMReleaseColor(color
);
613 WMReleaseFont(boldFont
);
620 showData(_Panel
*panel
)
625 for (i
= 0; i
< WMGetPopUpButtonNumberOfItems(panel
->optionP
); i
++)
629 item
= WMGetPopUpButtonMenuItem(panel
->optionP
, i
);
631 ofont
= WMGetMenuItemRepresentedObject(item
);
635 font
= GetStringForKey(fontOptions
[i
].option
);
638 WMSetMenuItemRepresentedObject(item
, font
);
641 WMSetPopUpButtonSelectedItem(panel
->optionP
, 0);
642 selectedOption(panel
->optionP
, panel
);
647 storeData(_Panel
*panel
)
651 for (i
= 0; i
< WMGetPopUpButtonNumberOfItems(panel
->optionP
); i
++)
655 item
= WMGetPopUpButtonMenuItem(panel
->optionP
, i
);
657 font
= WMGetMenuItemRepresentedObject(item
);
660 SetStringForKey(font
, fontOptions
[i
].option
);
667 createPanel(Panel
*p
)
669 _Panel
*panel
= (_Panel
*)p
;
670 WMScreen
*scr
= WMWidgetScreen(panel
->parent
);
675 lookup_available_fonts(panel
);
677 panel
->box
= WMCreateBox(panel
->parent
);
678 WMSetViewExpandsToParent(WMWidgetView(panel
->box
), 5, 2, 5, 5);
679 WMSetBoxHorizontal(panel
->box
, False
);
680 WMSetBoxBorderWidth(panel
->box
, 8);
681 WMMapWidget(panel
->box
);
683 hbox
= WMCreateBox(panel
->box
);
684 WMSetBoxHorizontal(hbox
, True
);
685 WMAddBoxSubview(panel
->box
, WMWidgetView(hbox
), False
, True
, 40, 22, 8);
687 vbox
= WMCreateBox(hbox
);
688 WMAddBoxSubview(hbox
, WMWidgetView(vbox
), False
, True
, 130, 0, 10);
689 WMSetBoxHorizontal(vbox
, False
);
690 panel
->optionP
= WMCreatePopUpButton(vbox
);
691 WMAddBoxSubviewAtEnd(vbox
, WMWidgetView(panel
->optionP
), False
, True
, 20, 0, 8);
692 for (i
= 0; fontOptions
[i
].option
; i
++)
694 WMAddPopUpButtonItem(panel
->optionP
, _(fontOptions
[i
].label
));
696 WMSetPopUpButtonAction(panel
->optionP
, selectedOption
, panel
);
698 label
= WMCreateLabel(hbox
);
699 WMSetLabelText(label
, _("Sample Text"));
700 WMSetLabelTextAlignment(label
, WARight
);
701 WMAddBoxSubview(hbox
, WMWidgetView(label
), False
, True
, 80, 0, 2);
703 panel
->sampleT
= WMCreateTextField(hbox
);
704 WMSetViewExpandsToParent(WMWidgetView(panel
->sampleT
), 10, 18, 10, 10);
705 WMSetTextFieldText(panel
->sampleT
, SAMPLE_TEXT
);
706 WMAddBoxSubview(hbox
, WMWidgetView(panel
->sampleT
), True
, True
, 60, 0, 0);
709 hbox
= WMCreateBox(panel
->box
);
710 WMSetBoxHorizontal(hbox
, True
);
711 WMAddBoxSubview(panel
->box
, WMWidgetView(hbox
), True
, True
, 100, 0, 2);
713 vbox
= WMCreateBox(hbox
);
714 WMSetBoxHorizontal(vbox
, False
);
715 WMAddBoxSubview(hbox
, WMWidgetView(vbox
), False
, True
, 240, 20, 4);
717 label
= createListLabel(scr
, vbox
, _("Family"));
718 WMAddBoxSubview(vbox
, WMWidgetView(label
), False
, True
, 20, 0, 2);
721 panel
->familyL
= WMCreateList(vbox
);
722 WMAddBoxSubview(vbox
, WMWidgetView(panel
->familyL
), True
, True
, 0, 0, 0);
726 for (i
= 0; i
< panel
->fonts
->familyn
; i
++)
728 item
= WMAddListItem(panel
->familyL
, panel
->fonts
->families
[i
].name
);
729 item
->clientData
= panel
->fonts
->families
+i
;
733 WMAddListItem(panel
->familyL
, "sans serif");
735 WMSetListAction(panel
->familyL
, selectedFamily
, panel
);
737 vbox
= WMCreateBox(hbox
);
738 WMSetBoxHorizontal(vbox
, False
);
739 WMAddBoxSubview(hbox
, WMWidgetView(vbox
), True
, True
, 10, 0, 0);
742 WMBox
*box
= WMCreateBox(vbox
);
743 WMSetBoxHorizontal(box
, True
);
744 WMAddBoxSubview(vbox
, WMWidgetView(box
), False
, True
, 20, 0, 2);
746 label
= createListLabel(scr
, box
, _("Style"));
747 WMAddBoxSubview(box
, WMWidgetView(label
), True
, True
, 20, 0, 4);
749 label
= createListLabel(scr
, box
, _("Size"));
750 WMAddBoxSubview(box
, WMWidgetView(label
), False
, True
, 60, 0, 0);
752 box
= WMCreateBox(vbox
);
753 WMSetBoxHorizontal(box
, True
);
754 WMAddBoxSubview(vbox
, WMWidgetView(box
), True
, True
, 20, 0, 0);
756 panel
->styleL
= WMCreateList(box
);
757 WMAddBoxSubview(box
, WMWidgetView(panel
->styleL
), True
, True
, 0, 0, 4);
758 WMSetListAction(panel
->styleL
, selected
, panel
);
760 panel
->sizeL
= WMCreateList(box
);
761 WMAddBoxSubview(box
, WMWidgetView(panel
->sizeL
), False
, True
, 60, 0, 0);
762 for (i
= 0; standardSizes
[i
]; i
++)
764 WMAddListItem(panel
->sizeL
, standardSizes
[i
]);
766 WMSetListAction(panel
->sizeL
, selected
, panel
);
770 WMMapSubwidgets(panel
->box
);
771 WMMapWidget(panel
->box
);
772 WMRealizeWidget(panel
->box
);
780 InitFontSimple(WMScreen
*scr
, WMWidget
*parent
)
784 panel
= wmalloc(sizeof(_Panel
));
785 memset(panel
, 0, sizeof(_Panel
));
787 panel
->sectionName
= _("Font Configuration");
789 panel
->description
= _("Configure fonts for Window Maker titlebars, menus etc.");
791 panel
->parent
= parent
;
793 panel
->callbacks
.createWidgets
= createPanel
;
794 panel
->callbacks
.updateDomain
= storeData
;
796 AddSection(panel
, ICON_FILE
);