changed default fonts
[wmaker-crm.git] / WPrefs.app / FontSimple.c
blobbd74417b059625407826d0433fd506ad2ecf4bd6
1 /* FontSimple.c- simplified font configuration panel
2 *
3 * WPrefs - Window Maker Preferences Program
4 *
5 * Copyright (c) 1998-2004 Alfredo K. Kojima
6 *
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,
20 * USA.
24 #include "WPrefs.h"
25 #include <unistd.h>
26 #include <fontconfig/fontconfig.h>
28 #define SAMPLE_TEXT "The Lazy Fox Jumped Ipsum Foobar 1234 - 56789"
31 typedef struct {
32 int weight;
33 int width;
34 int slant;
35 } FontStyle;
37 typedef struct {
38 char *name;
39 int stylen;
40 FontStyle *styles;
41 } FontFamily;
44 typedef struct {
45 int familyn;
46 FontFamily *families;
47 } FontList;
50 typedef struct _Panel {
51 WMBox *box;
52 char *sectionName;
54 char *description;
56 CallbackRec callbacks;
58 WMWidget *parent;
60 WMPopUpButton *optionP;
62 WMList *familyL;
63 WMList *styleL;
65 WMList *sizeL;
67 WMTextField *sampleT;
69 FontList *fonts;
70 } _Panel;
73 #define ICON_FILE "fonts"
76 static struct {
77 char *option;
78 char *label;
79 } fontOptions[]= {
80 {"WindowTitleFont", N_("Window Title")},
81 {"MenuTitleFont", N_("Menu Title")},
82 {"MenuTextFont", N_("Menu Text")},
83 {"IconTitleFont", N_("Icon Title")},
84 {"ClipTitleFont", N_("Clip Title")},
85 {"LargeDisplayFont", N_("Desktop Caption")},
86 {NULL, NULL},
90 static char *standardSizes[]= {
91 "6",
92 "8",
93 "9",
94 "10",
95 "11",
96 "12",
97 "13",
98 "14",
99 "15",
100 "16",
101 "18",
102 "20",
103 "22",
104 "24",
105 "28",
106 "32",
107 "36",
108 "48",
109 "64",
110 "72",
111 NULL
115 static struct {
116 int weight;
117 char *name;
118 } fontWeights[]= {
119 {FC_WEIGHT_THIN, "Thin"},
120 {FC_WEIGHT_EXTRALIGHT, "ExtraLight"},
121 {FC_WEIGHT_LIGHT, "Light"},
122 {FC_WEIGHT_NORMAL, "Normal"},
123 {FC_WEIGHT_MEDIUM, ""}, /*"medium"},*/
124 {FC_WEIGHT_DEMIBOLD, "DemiBold"},
125 {FC_WEIGHT_BOLD, "Bold"},
126 {FC_WEIGHT_EXTRABOLD, "ExtraBold"},
127 {FC_WEIGHT_BLACK, "Black"},
128 {0, NULL}
131 static struct {
132 int slant;
133 char *name;
134 } fontSlants[]= {
135 {FC_SLANT_ROMAN, ""}, /*"Roman"},*/
136 {FC_SLANT_ITALIC, "Italic"},
137 {FC_SLANT_OBLIQUE, "Oblique"},
138 {0, NULL}
141 static struct {
142 int width;
143 char *name;
144 } fontWidths[]= {
145 {FC_WIDTH_ULTRACONDENSED, "UltraCondensed"},
146 {FC_WIDTH_EXTRACONDENSED, "ExtraCondensed"},
147 {FC_WIDTH_CONDENSED, "Condensed"},
148 {FC_WIDTH_SEMICONDENSED, "SemiCondensed"},
149 {FC_WIDTH_NORMAL, ""}, /*"normal"},*/
150 {FC_WIDTH_SEMIEXPANDED, "SemiExpanded"},
151 {FC_WIDTH_EXPANDED, "Expanded"},
152 {FC_WIDTH_EXTRAEXPANDED, "ExtraExpanded"},
153 {FC_WIDTH_ULTRAEXPANDED, "UltraExpanded"},
154 {0, NULL}
161 static int compare_family(const void *a, const void *b)
163 FontFamily *fa= (FontFamily*)a;
164 FontFamily *fb= (FontFamily*)b;
165 return strcasecmp(fa->name, fb->name);
169 static void
170 lookup_available_fonts(_Panel *panel)
172 FcPattern *pat = FcPatternCreate();
173 FcObjectSet *os;
174 FcFontSet *fonts;
175 FontFamily *family;
177 os = FcObjectSetBuild(FC_FAMILY, FC_WEIGHT, FC_WIDTH, FC_SLANT, NULL);
179 fonts = FcFontList(0, pat, os);
181 if (fonts)
183 int i;
185 panel->fonts= wmalloc(sizeof(FontList));
186 panel->fonts->familyn= 0;
187 panel->fonts->families= wmalloc(sizeof(FontFamily)*fonts->nfont);
189 for (i= 0; i < fonts->nfont; i++)
191 FcChar8 *name;
192 int weight, slant, width;
193 int j, found;
195 if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &name) != FcResultMatch)
196 continue;
198 if (FcPatternGetInteger(fonts->fonts[i], FC_WEIGHT, 0, &weight) != FcResultMatch)
199 weight= FC_WEIGHT_MEDIUM;
201 if (FcPatternGetInteger(fonts->fonts[i], FC_WIDTH, 0, &width) != FcResultMatch)
202 width= FC_WIDTH_NORMAL;
204 if (FcPatternGetInteger(fonts->fonts[i], FC_SLANT, 0, &slant) != FcResultMatch)
205 slant= FC_SLANT_ROMAN;
207 found = -1;
208 for (j = 0; j < panel->fonts->familyn && found<0; j++)
209 if (strcasecmp(panel->fonts->families[j].name, name)==0)
210 found= j;
212 if (found < 0)
214 panel->fonts->families[panel->fonts->familyn++].name= wstrdup(name);
215 family= panel->fonts->families + panel->fonts->familyn-1;
216 family->stylen= 0;
217 family->styles= NULL;
219 else
220 family= panel->fonts->families+found;
222 family->stylen++;
223 family->styles= wrealloc(family->styles, sizeof(FontStyle)*family->stylen);
224 family->styles[family->stylen-1].weight= weight;
225 family->styles[family->stylen-1].slant= slant;
226 family->styles[family->stylen-1].width= width;
228 qsort(panel->fonts->families, panel->fonts->familyn, sizeof(FontFamily),
229 compare_family);
231 FcFontSetDestroy(fonts);
233 if (os)
234 FcObjectSetDestroy(os);
235 if (pat)
236 FcPatternDestroy(pat);
238 panel->fonts->families[panel->fonts->familyn++].name= wstrdup("sans");
239 family= panel->fonts->families + panel->fonts->familyn-1;
240 family->styles= wmalloc(sizeof(FontStyle)*2);
241 family->stylen= 2;
242 family->styles[0].weight= FC_WEIGHT_MEDIUM;
243 family->styles[0].slant= FC_SLANT_ROMAN;
244 family->styles[0].width= FC_WIDTH_NORMAL;
245 family->styles[1].weight= FC_WEIGHT_BOLD;
246 family->styles[1].slant= FC_SLANT_ROMAN;
247 family->styles[1].width= FC_WIDTH_NORMAL;
249 panel->fonts->families[panel->fonts->familyn++].name= wstrdup("serif");
250 family= panel->fonts->families + panel->fonts->familyn-1;
251 family->styles= wmalloc(sizeof(FontStyle)*2);
252 family->stylen= 2;
253 family->styles[0].weight= FC_WEIGHT_MEDIUM;
254 family->styles[0].slant= FC_SLANT_ROMAN;
255 family->styles[0].width= FC_WIDTH_NORMAL;
256 family->styles[1].weight= FC_WEIGHT_BOLD;
257 family->styles[1].slant= FC_SLANT_ROMAN;
258 family->styles[1].width= FC_WIDTH_NORMAL;
262 static char*
263 getSelectedFont(_Panel *panel, char *curfont)
265 WMListItem *item;
266 FcPattern *pat= FcNameParse(curfont);
267 char *name;
269 item= WMGetListSelectedItem(panel->familyL);
270 if (item)
272 FcPatternDel(pat, FC_FAMILY);
273 FcPatternAddString(pat, FC_FAMILY, item->text);
276 item= WMGetListSelectedItem(panel->styleL);
277 if (item)
279 FontStyle *style= (FontStyle*)item->clientData;
281 FcPatternDel(pat, FC_WEIGHT);
282 FcPatternAddInteger(pat, FC_WEIGHT, style->weight);
284 FcPatternDel(pat, FC_WIDTH);
285 FcPatternAddInteger(pat, FC_WIDTH, style->width);
287 FcPatternDel(pat, FC_SLANT);
288 FcPatternAddInteger(pat, FC_SLANT, style->slant);
291 item= WMGetListSelectedItem(panel->sizeL);
292 if (item)
294 FcPatternDel(pat, FC_PIXEL_SIZE);
295 FcPatternAddDouble(pat, FC_PIXEL_SIZE, atoi(item->text));
298 name= FcNameUnparse(pat);
299 FcPatternDestroy(pat);
301 return name;
306 static void
307 updateSampleFont(_Panel *panel)
309 WMMenuItem *item= WMGetPopUpButtonMenuItem(panel->optionP,
310 WMGetPopUpButtonSelectedItem(panel->optionP));
311 char *fn= WMGetMenuItemRepresentedObject(item);
312 WMFont *font= WMCreateFont(WMWidgetScreen(panel->box), fn);
314 if (font)
316 WMSetTextFieldFont(panel->sampleT, font);
317 WMReleaseFont(font);
324 static void
325 selectedFamily(WMWidget *w, void *data)
327 _Panel *panel= (_Panel*)data;
328 WMListItem *item;
329 FontStyle *oldStyle= NULL;
330 char buffer[1024];
332 item= WMGetListSelectedItem(panel->styleL);
333 if (item)
334 oldStyle= (FontStyle*)item->clientData;
336 item= WMGetListSelectedItem(panel->familyL);
338 if (item)
340 FontFamily *family= (FontFamily*)item->clientData;
341 int i, oldi= 0, oldscore= 0;
343 WMClearList(panel->styleL);
344 for (i = 0; i < family->stylen; i++)
346 int j;
347 char *weight= "", *slant= "", *width= "";
348 WMListItem *item;
350 for (j= 0; fontWeights[j].name; j++)
351 if (fontWeights[j].weight == family->styles[i].weight)
353 weight= fontWeights[j].name;
354 break;
356 for (j= 0; fontWidths[j].name; j++)
357 if (fontWidths[j].width == family->styles[i].width)
359 width= fontWidths[j].name;
360 break;
362 for (j= 0; fontSlants[j].name; j++)
363 if (fontSlants[j].slant == family->styles[i].slant)
365 slant= fontSlants[j].name;
366 break;
368 sprintf(buffer, "%s%s%s%s%s",
369 weight, *weight?" ":"",
370 slant, (*slant || *weight)?" ":"",
371 width);
372 if (!buffer[0])
373 strcpy(buffer, "Roman");
375 item= WMAddListItem(panel->styleL, buffer);
376 item->clientData= family->styles+i;
378 if (oldStyle) {
379 int score= 0;
381 if (oldStyle->width == family->styles[i].width)
382 score |= 1;
383 if (oldStyle->weight == family->styles[i].weight)
384 score |= 2;
385 if (oldStyle->slant == family->styles[i].slant)
386 score |= 4;
388 if (score > oldscore)
390 oldi= i;
391 oldscore= score;
395 WMSelectListItem(panel->styleL, oldi);
398 int index= WMGetPopUpButtonSelectedItem(panel->optionP);
399 WMMenuItem *item= WMGetPopUpButtonMenuItem(panel->optionP, index);
400 char *ofont, *nfont;
402 ofont= (char*)WMGetMenuItemRepresentedObject(item);
404 nfont= getSelectedFont(panel, ofont);
405 free(ofont);
406 WMSetMenuItemRepresentedObject(item, nfont);
408 updateSampleFont(panel);
413 static void
414 selected(WMWidget *w, void *data)
416 _Panel *panel= (_Panel*)data;
417 int index= WMGetPopUpButtonSelectedItem(panel->optionP);
418 WMMenuItem *item= WMGetPopUpButtonMenuItem(panel->optionP, index);
419 char *ofont, *nfont;
421 ofont= (char*)WMGetMenuItemRepresentedObject(item);
423 nfont= getSelectedFont(panel, ofont);
424 free(ofont);
425 WMSetMenuItemRepresentedObject(item, nfont);
427 updateSampleFont(panel);
431 static void
432 selectedOption(WMWidget *w, void *data)
434 _Panel *panel= (_Panel*)data;
435 int index = WMGetPopUpButtonSelectedItem(panel->optionP);
436 WMMenuItem *item= WMGetPopUpButtonMenuItem(panel->optionP, index);
437 char *font;
439 font= (char*)WMGetMenuItemRepresentedObject(item);
440 if (font)
442 FcPattern *pat;
444 pat= FcNameParse(font);
445 if (pat)
447 FcChar8 *name;
448 int weight, slant, width;
449 double size;
450 int i;
451 int found;
453 FcDefaultSubstitute(pat);
455 if (FcPatternGetString(pat, FC_FAMILY, 0, &name) != FcResultMatch)
456 name= "sans";
458 found= 0;
459 // select family
460 for (i= 0; i < WMGetListNumberOfRows(panel->familyL); i++)
462 WMListItem *item= WMGetListItem(panel->familyL, i);
463 FontFamily *family= (FontFamily*)item->clientData;
465 if (strcasecmp(family->name, name)==0)
467 found= 1;
468 WMSelectListItem(panel->familyL, i);
469 WMSetListPosition(panel->familyL, i);
470 break;
473 if (!found)
474 WMSelectListItem(panel->familyL, -1);
475 selectedFamily(panel->familyL, panel);
477 // select style
478 if (FcPatternGetInteger(pat, FC_WEIGHT, 0, &weight) != FcResultMatch)
479 weight= FC_WEIGHT_NORMAL;
480 if (FcPatternGetInteger(pat, FC_WIDTH, 0, &width) != FcResultMatch)
481 width= FC_WIDTH_NORMAL;
482 if (FcPatternGetInteger(pat, FC_SLANT, 0, &slant) != FcResultMatch)
483 slant= FC_SLANT_ROMAN;
485 if (FcPatternGetDouble(pat, FC_PIXEL_SIZE, 0, &size) != FcResultMatch)
486 size= 10.0;
488 found= 0;
489 for (i= 0; i < WMGetListNumberOfRows(panel->styleL); i++)
491 WMListItem *item= WMGetListItem(panel->styleL, i);
492 FontStyle *style= (FontStyle*)item->clientData;
493 if (style->weight == weight
494 && style->width == width
495 && style->slant == slant)
497 found= 1;
498 WMSelectListItem(panel->styleL, i);
499 WMSetListPosition(panel->styleL, i);
500 break;
503 if (!found)
504 WMSelectListItem(panel->styleL, -1);
506 found= 0;
508 int closest= 100000, index= -1;
510 for (i= 0; i < WMGetListNumberOfRows(panel->sizeL); i++)
512 WMListItem *item= WMGetListItem(panel->sizeL, i);
513 int tmp;
515 tmp= atoi(item->text);
516 if (abs(tmp-size) < abs(tmp-closest))
518 closest= tmp;
519 index= i;
522 WMSelectListItem(panel->sizeL, index);
523 WMSetListPosition(panel->sizeL, index);
526 selected(NULL, panel);
528 else
529 wwarning("Can't parse font '%s'", font);
532 updateSampleFont(panel);
536 static WMLabel *
537 createListLabel(WMScreen *scr, WMWidget *parent, char *text)
539 WMLabel *label;
540 WMColor *color;
541 WMFont *boldFont= WMBoldSystemFontOfSize(scr, 12);
543 label = WMCreateLabel(parent);
544 WMSetLabelFont(label, boldFont);
545 WMSetLabelText(label, text);
546 WMSetLabelRelief(label, WRSunken);
547 WMSetLabelTextAlignment(label, WACenter);
548 color = WMDarkGrayColor(scr);
549 WMSetWidgetBackgroundColor(label, color);
550 WMReleaseColor(color);
551 color = WMWhiteColor(scr);
552 WMSetLabelTextColor(label, color);
553 WMReleaseColor(color);
555 WMReleaseFont(boldFont);
557 return label;
561 static void
562 showData(_Panel *panel)
564 int i;
565 WMMenuItem *item;
567 for (i= 0; i < WMGetPopUpButtonNumberOfItems(panel->optionP); i++)
569 char *ofont, *font;
571 item= WMGetPopUpButtonMenuItem(panel->optionP, i);
573 ofont= WMGetMenuItemRepresentedObject(item);
574 if (ofont)
575 wfree(ofont);
577 font= GetStringForKey(fontOptions[i].option);
578 if (font)
579 font= wstrdup(font);
580 WMSetMenuItemRepresentedObject(item, font);
583 WMSetPopUpButtonSelectedItem(panel->optionP, 0);
584 selectedOption(panel->optionP, panel);
588 static void
589 storeData(_Panel *panel)
591 int i;
592 WMMenuItem *item;
593 for (i= 0; i < WMGetPopUpButtonNumberOfItems(panel->optionP); i++)
595 char *font;
597 item= WMGetPopUpButtonMenuItem(panel->optionP, i);
599 font= WMGetMenuItemRepresentedObject(item);
600 if (font && *font)
602 SetStringForKey(font, fontOptions[i].option);
608 static void
609 createPanel(Panel *p)
611 _Panel *panel = (_Panel*)p;
612 WMScreen *scr = WMWidgetScreen(panel->parent);
613 WMLabel *label;
614 WMBox *hbox, *vbox;
615 int i;
617 lookup_available_fonts(panel);
619 panel->box = WMCreateBox(panel->parent);
620 WMSetViewExpandsToParent(WMWidgetView(panel->box), 5, 8, 5, 8);
621 WMSetBoxHorizontal(panel->box, False);
622 WMSetBoxBorderWidth(panel->box, 8);
623 WMMapWidget(panel->box);
625 hbox = WMCreateBox(panel->box);
626 WMSetBoxHorizontal(hbox, True);
627 WMAddBoxSubview(panel->box, WMWidgetView(hbox), False, True, 22, 22, 8);
629 label = WMCreateLabel(hbox);
630 WMAddBoxSubview(hbox, WMWidgetView(label), False, True, 150, 0, 10);
631 WMSetLabelText(label, _("Choose Font For"));
632 WMSetLabelTextAlignment(label, WARight);
634 panel->optionP = WMCreatePopUpButton(hbox);
635 WMAddBoxSubview(hbox, WMWidgetView(panel->optionP), False, True, 200, 0, 10);
636 for (i= 0; fontOptions[i].option; i++)
638 WMAddPopUpButtonItem(panel->optionP, _(fontOptions[i].label));
640 WMSetPopUpButtonAction(panel->optionP, selectedOption, panel);
642 hbox = WMCreateBox(panel->box);
643 WMSetBoxHorizontal(hbox, True);
644 WMAddBoxSubview(panel->box, WMWidgetView(hbox), False, True, 100, 0, 2);
648 vbox = WMCreateBox(hbox);
649 WMSetBoxHorizontal(vbox, False);
650 WMAddBoxSubview(hbox, WMWidgetView(vbox), False, True, 240, 20, 2);
652 label = createListLabel(scr, vbox, _("Family"));
653 WMAddBoxSubview(vbox, WMWidgetView(label), False, True, 20, 0, 2);
655 // family
656 panel->familyL = WMCreateList(vbox);
657 WMAddBoxSubview(vbox, WMWidgetView(panel->familyL), True, True, 0, 0, 0);
658 if (panel->fonts)
660 WMListItem *item;
661 for (i= 0; i < panel->fonts->familyn; i++)
663 item = WMAddListItem(panel->familyL, panel->fonts->families[i].name);
664 item->clientData= panel->fonts->families+i;
667 else
668 WMAddListItem(panel->familyL, "sans");
670 WMSetListAction(panel->familyL, selectedFamily, panel);
673 vbox = WMCreateBox(hbox);
674 WMSetBoxHorizontal(vbox, False);
675 WMAddBoxSubview(hbox, WMWidgetView(vbox), True, True, 60, 0, 2);
677 label = createListLabel(scr, vbox, _("Style"));
678 WMAddBoxSubview(vbox, WMWidgetView(label), False, True, 20, 0, 2);
680 panel->styleL = WMCreateList(vbox);
681 WMAddBoxSubview(vbox, WMWidgetView(panel->styleL), True, True, 0, 0, 0);
682 WMSetListAction(panel->styleL, selected, panel);
686 vbox = WMCreateBox(hbox);
687 WMSetBoxHorizontal(vbox, False);
688 WMAddBoxSubview(hbox, WMWidgetView(vbox), False, True, 70, 0, 0);
690 label = createListLabel(scr, vbox, _("Size"));
691 WMAddBoxSubview(vbox, WMWidgetView(label), False, True, 20, 0, 2);
693 // size
694 panel->sizeL = WMCreateList(vbox);
695 WMAddBoxSubview(vbox, WMWidgetView(panel->sizeL), True, True, 0, 0, 0);
696 for (i= 0; standardSizes[i]; i++)
698 WMAddListItem(panel->sizeL, standardSizes[i]);
700 WMSetListAction(panel->sizeL, selected, panel);
703 WMFrame *frame= WMCreateFrame(panel->box);
704 WMSetFrameTitle(frame, _("Sample"));
706 WMAddBoxSubview(panel->box, WMWidgetView(frame), True, True, 50, 0, 0);
708 panel->sampleT= WMCreateTextField(frame);
709 WMSetViewExpandsToParent(WMWidgetView(panel->sampleT), 10, 18, 10, 10);
710 WMSetTextFieldText(panel->sampleT, SAMPLE_TEXT);
714 WMMapSubwidgets(panel->box);
715 WMMapWidget(panel->box);
716 WMRealizeWidget(panel->box);
718 showData(panel);
723 Panel*
724 InitFontSimple(WMScreen *scr, WMWidget *parent)
726 _Panel *panel;
728 panel = wmalloc(sizeof(_Panel));
729 memset(panel, 0, sizeof(_Panel));
731 panel->sectionName = _("Font Configuration");
733 panel->description = _("Configure fonts for Window Maker titlebars, menus etc.");
735 panel->parent = parent;
737 panel->callbacks.createWidgets = createPanel;
738 panel->callbacks.updateDomain = storeData;
740 AddSection(panel, ICON_FILE);
742 return panel;