12 #include <X11/Xft/Xft.h>
13 #include <fontconfig/fontconfig.h>
17 char *WMFontPanelFontChangedNotification
= "WMFontPanelFontChangedNotification";
22 typedef struct W_FontPanel
{
49 #define MIN_UPPER_HEIGHT 20
50 #define MIN_LOWER_HEIGHT 140
53 #define MAX_FONTS_TO_RETRIEVE 2000
55 #define BUTTON_SPACE_HEIGHT 40
58 #define MIN_HEIGHT (MIN_UPPER_HEIGHT+MIN_LOWER_HEIGHT+BUTTON_SPACE_HEIGHT)
60 #define DEF_UPPER_HEIGHT 60
61 #define DEF_LOWER_HEIGHT 310
64 #define DEF_HEIGHT (DEF_UPPER_HEIGHT+DEF_LOWER_HEIGHT)
69 static int scalableFontSizes
[] = {
86 static void setFontPanelFontName(FontPanel
*panel
, char *family
, char *style
, double size
);
88 static int isXLFD(char *font
, int *length_ret
);
90 static void arrangeLowerFrame(FontPanel
*panel
);
92 static void familyClick(WMWidget
*, void *);
93 static void typefaceClick(WMWidget
*, void *);
94 static void sizeClick(WMWidget
*, void *);
97 static void listFamilies(WMScreen
*scr
, WMFontPanel
*panel
);
101 splitViewConstrainCallback(WMSplitView
*sPtr
, int indView
, int *min
, int *max
)
104 *min
= MIN_UPPER_HEIGHT
;
106 *min
= MIN_LOWER_HEIGHT
;
110 notificationObserver(void *self
, WMNotification
*notif
)
112 WMFontPanel
*panel
= (WMFontPanel
*)self
;
113 void *object
= WMGetNotificationObject(notif
);
115 if (WMGetNotificationName(notif
) == WMViewSizeDidChangeNotification
) {
116 if (object
== WMWidgetView(panel
->win
)) {
117 int h
= WMWidgetHeight(panel
->win
);
118 int w
= WMWidgetWidth(panel
->win
);
120 WMResizeWidget(panel
->split
, w
, h
-BUTTON_SPACE_HEIGHT
);
122 WMMoveWidget(panel
->setB
, w
-80, h
-(BUTTON_SPACE_HEIGHT
-5));
124 WMMoveWidget(panel
->revertB
, w
-240, h
-(BUTTON_SPACE_HEIGHT
-5));
126 } else if (object
== WMWidgetView(panel
->upperF
)) {
128 if (WMWidgetHeight(panel
->upperF
) < MIN_UPPER_HEIGHT
) {
129 WMResizeWidget(panel
->upperF
, WMWidgetWidth(panel
->upperF
),
132 WMResizeWidget(panel
->sampleT
, WMWidgetWidth(panel
->upperF
)-20,
133 WMWidgetHeight(panel
->upperF
)-10);
136 } else if (object
== WMWidgetView(panel
->lowerF
)) {
138 if (WMWidgetHeight(panel
->lowerF
) < MIN_LOWER_HEIGHT
) {
139 WMResizeWidget(panel
->upperF
, WMWidgetWidth(panel
->upperF
),
142 WMMoveWidget(panel
->lowerF
, 0, WMWidgetHeight(panel
->upperF
)
143 + WMGetSplitViewDividerThickness(panel
->split
));
145 WMResizeWidget(panel
->lowerF
, WMWidgetWidth(panel
->lowerF
),
146 WMWidgetWidth(panel
->split
) - MIN_UPPER_HEIGHT
147 - WMGetSplitViewDividerThickness(panel
->split
));
149 arrangeLowerFrame(panel
);
157 closeWindow(WMWidget
*w
, void *data
)
159 FontPanel
*panel
= (FontPanel
*)data
;
161 WMHideFontPanel(panel
);
168 setClickedAction(WMWidget
*w
, void *data
)
170 FontPanel
*panel
= (FontPanel
*)data
;
173 (*panel
->action
)(panel
, panel
->data
);
178 revertClickedAction(WMWidget
*w
, void *data
)
180 /*FontPanel *panel = (FontPanel*)data;*/
187 WMGetFontPanel(WMScreen
*scr
)
190 WMColor
*dark
, *white
;
194 if (scr
->sharedFontPanel
)
195 return scr
->sharedFontPanel
;
198 panel
= wmalloc(sizeof(FontPanel
));
199 memset(panel
, 0, sizeof(FontPanel
));
201 panel
->win
= WMCreateWindow(scr
, "fontPanel");
202 /* WMSetWidgetBackgroundColor(panel->win, WMWhiteColor(scr));*/
203 WMSetWindowTitle(panel
->win
, _("Font Panel"));
204 WMResizeWidget(panel
->win
, DEF_WIDTH
, DEF_HEIGHT
);
205 WMSetWindowMinSize(panel
->win
, MIN_WIDTH
, MIN_HEIGHT
);
206 WMSetViewNotifySizeChanges(WMWidgetView(panel
->win
), True
);
208 WMSetWindowCloseAction(panel
->win
, closeWindow
, panel
);
210 panel
->split
= WMCreateSplitView(panel
->win
);
211 WMResizeWidget(panel
->split
, DEF_WIDTH
, DEF_HEIGHT
- BUTTON_SPACE_HEIGHT
);
212 WMSetSplitViewConstrainProc(panel
->split
, splitViewConstrainCallback
);
214 divThickness
= WMGetSplitViewDividerThickness(panel
->split
);
216 panel
->upperF
= WMCreateFrame(panel
->win
);
217 WMSetFrameRelief(panel
->upperF
, WRFlat
);
218 WMSetViewNotifySizeChanges(WMWidgetView(panel
->upperF
), True
);
219 panel
->lowerF
= WMCreateFrame(panel
->win
);
220 /* WMSetWidgetBackgroundColor(panel->lowerF, WMBlackColor(scr));*/
221 WMSetFrameRelief(panel
->lowerF
, WRFlat
);
222 WMSetViewNotifySizeChanges(WMWidgetView(panel
->lowerF
), True
);
224 WMAddSplitViewSubview(panel
->split
, W_VIEW(panel
->upperF
));
225 WMAddSplitViewSubview(panel
->split
, W_VIEW(panel
->lowerF
));
227 WMResizeWidget(panel
->upperF
, DEF_WIDTH
, DEF_UPPER_HEIGHT
);
229 WMResizeWidget(panel
->lowerF
, DEF_WIDTH
, DEF_LOWER_HEIGHT
);
231 WMMoveWidget(panel
->lowerF
, 0, 60+divThickness
);
233 white
= WMWhiteColor(scr
);
234 dark
= WMDarkGrayColor(scr
);
236 panel
->sampleT
= WMCreateTextField(panel
->upperF
);
237 WMResizeWidget(panel
->sampleT
, DEF_WIDTH
- 20, 50);
238 WMMoveWidget(panel
->sampleT
, 10, 10);
239 WMSetTextFieldText(panel
->sampleT
, _("The quick brown fox jumps over the lazy dog"));
241 font
= WMBoldSystemFontOfSize(scr
, 12);
243 panel
->famL
= WMCreateLabel(panel
->lowerF
);
244 WMSetWidgetBackgroundColor(panel
->famL
, dark
);
245 WMSetLabelText(panel
->famL
, _("Family"));
246 WMSetLabelFont(panel
->famL
, font
);
247 WMSetLabelTextColor(panel
->famL
, white
);
248 WMSetLabelRelief(panel
->famL
, WRSunken
);
249 WMSetLabelTextAlignment(panel
->famL
, WACenter
);
251 panel
->famLs
= WMCreateList(panel
->lowerF
);
252 WMSetListAction(panel
->famLs
, familyClick
, panel
);
254 panel
->typL
= WMCreateLabel(panel
->lowerF
);
255 WMSetWidgetBackgroundColor(panel
->typL
, dark
);
256 WMSetLabelText(panel
->typL
, _("Typeface"));
257 WMSetLabelFont(panel
->typL
, font
);
258 WMSetLabelTextColor(panel
->typL
, white
);
259 WMSetLabelRelief(panel
->typL
, WRSunken
);
260 WMSetLabelTextAlignment(panel
->typL
, WACenter
);
262 panel
->typLs
= WMCreateList(panel
->lowerF
);
263 WMSetListAction(panel
->typLs
, typefaceClick
, panel
);
265 panel
->sizL
= WMCreateLabel(panel
->lowerF
);
266 WMSetWidgetBackgroundColor(panel
->sizL
, dark
);
267 WMSetLabelText(panel
->sizL
, _("Size"));
268 WMSetLabelFont(panel
->sizL
, font
);
269 WMSetLabelTextColor(panel
->sizL
, white
);
270 WMSetLabelRelief(panel
->sizL
, WRSunken
);
271 WMSetLabelTextAlignment(panel
->sizL
, WACenter
);
273 panel
->sizT
= WMCreateTextField(panel
->lowerF
);
274 /* WMSetTextFieldAlignment(panel->sizT, WARight);*/
276 panel
->sizLs
= WMCreateList(panel
->lowerF
);
277 WMSetListAction(panel
->sizLs
, sizeClick
, panel
);
280 WMReleaseColor(white
);
281 WMReleaseColor(dark
);
283 panel
->setB
= WMCreateCommandButton(panel
->win
);
284 WMResizeWidget(panel
->setB
, 70, 24);
285 WMMoveWidget(panel
->setB
, 240, DEF_HEIGHT
- (BUTTON_SPACE_HEIGHT
-5));
286 WMSetButtonText(panel
->setB
, _("Set"));
287 WMSetButtonAction(panel
->setB
, setClickedAction
, panel
);
289 panel
->revertB
= WMCreateCommandButton(panel
->win
);
290 WMResizeWidget(panel
->revertB
, 70, 24);
291 WMMoveWidget(panel
->revertB
, 80, DEF_HEIGHT
- (BUTTON_SPACE_HEIGHT
-5));
292 WMSetButtonText(panel
->revertB
, _("Revert"));
293 WMSetButtonAction(panel
->revertB
, revertClickedAction
, panel
);
296 WMRealizeWidget(panel
->win
);
298 WMMapSubwidgets(panel
->upperF
);
299 WMMapSubwidgets(panel
->lowerF
);
300 WMMapSubwidgets(panel
->split
);
301 WMMapSubwidgets(panel
->win
);
303 WMUnmapWidget(panel
->revertB
);
305 arrangeLowerFrame(panel
);
307 scr
->sharedFontPanel
= panel
;
310 /* register notification observers */
311 WMAddNotificationObserver(notificationObserver
, panel
,
312 WMViewSizeDidChangeNotification
,
313 WMWidgetView(panel
->win
));
314 WMAddNotificationObserver(notificationObserver
, panel
,
315 WMViewSizeDidChangeNotification
,
316 WMWidgetView(panel
->upperF
));
317 WMAddNotificationObserver(notificationObserver
, panel
,
318 WMViewSizeDidChangeNotification
,
319 WMWidgetView(panel
->lowerF
));
322 listFamilies(scr
, panel
);
330 WMFreeFontPanel(WMFontPanel
*panel
)
332 if (panel
== WMWidgetScreen(panel
->win
)->sharedFontPanel
) {
333 WMWidgetScreen(panel
->win
)->sharedFontPanel
= NULL
;
335 WMRemoveNotificationObserver(panel
);
336 WMUnmapWidget(panel
->win
);
337 WMDestroyWidget(panel
->win
);
343 WMShowFontPanel(WMFontPanel
*panel
)
345 WMMapWidget(panel
->win
);
350 WMHideFontPanel(WMFontPanel
*panel
)
352 WMUnmapWidget(panel
->win
);
357 WMGetFontPanelFont(WMFontPanel
*panel
)
359 return WMGetTextFieldFont(panel
->sampleT
);
364 WMSetFontPanelFont(WMFontPanel
*panel
, char *fontName
)
368 FcChar8
*family
, *style
;
371 if (!isXLFD(fontName
, &fname_len
)) {
372 /* maybe its proper fontconfig and we can parse it */
373 pattern
= FcNameParse((FcChar8
*)fontName
);
375 /* maybe its proper xlfd and we can convert it to an FcPattern */
376 pattern
= XftXlfdParse(fontName
, False
, False
);
377 /*//FcPatternPrint(pattern);*/
383 if (FcPatternGetString(pattern
, FC_FAMILY
, 0, &family
)==FcResultMatch
)
384 if (FcPatternGetString(pattern
, FC_STYLE
, 0, &style
)==FcResultMatch
)
385 if (FcPatternGetDouble(pattern
, "pixelsize", 0, &size
)==FcResultMatch
)
386 setFontPanelFontName(panel
, (char*)family
, (char*)style
, size
);
388 FcPatternDestroy(pattern
);
393 WMSetFontPanelAction(WMFontPanel
*panel
, WMAction2
*action
, void *data
)
395 panel
->action
= action
;
404 arrangeLowerFrame(FontPanel
*panel
)
406 int width
= WMWidgetWidth(panel
->lowerF
) - 55 - 30;
407 int height
= WMWidgetHeight(panel
->split
) - WMWidgetHeight(panel
->upperF
);
410 #define LABEL_HEIGHT 20
412 height
-= WMGetSplitViewDividerThickness(panel
->split
);
415 height
-= LABEL_HEIGHT
+ 8;
417 fw
= (125*width
) / 235;
418 tw
= (110*width
) / 235;
421 WMMoveWidget(panel
->famL
, 10, 0);
422 WMResizeWidget(panel
->famL
, fw
, LABEL_HEIGHT
);
424 WMMoveWidget(panel
->famLs
, 10, 23);
425 WMResizeWidget(panel
->famLs
, fw
, height
);
427 WMMoveWidget(panel
->typL
, 10+fw
+3, 0);
428 WMResizeWidget(panel
->typL
, tw
, LABEL_HEIGHT
);
430 WMMoveWidget(panel
->typLs
, 10+fw
+3, 23);
431 WMResizeWidget(panel
->typLs
, tw
, height
);
433 WMMoveWidget(panel
->sizL
, 10+fw
+3+tw
+3, 0);
434 WMResizeWidget(panel
->sizL
, sw
+4, LABEL_HEIGHT
);
436 WMMoveWidget(panel
->sizT
, 10+fw
+3+tw
+3, 23);
437 WMResizeWidget(panel
->sizT
, sw
+4, 20);
439 WMMoveWidget(panel
->sizLs
, 10+fw
+3+tw
+3, 46);
440 WMResizeWidget(panel
->sizLs
, sw
+4, height
-23);
445 #define NUM_FIELDS 14
449 isXLFD(char *font
, int *length_ret
)
460 return c
==NUM_FIELDS
;
470 char *name
; /* gotta love simplicity */
476 compare_int(const void *a
, const void *b
)
491 addSizeToTypeface(Typeface
*face
, int size
)
496 for (j
= 0; j
< sizeof(scalableFontSizes
)/sizeof(int); j
++) {
497 size
= scalableFontSizes
[j
];
499 if (!WMCountInArray(face
->sizes
, (void*)size
)) {
500 WMAddToArray(face
->sizes
, (void*)size
);
503 WMSortArray(face
->sizes
, compare_int
);
505 if (!WMCountInArray(face
->sizes
, (void*)size
)) {
506 WMAddToArray(face
->sizes
, (void*)size
);
507 WMSortArray(face
->sizes
, compare_int
);
513 addTypefaceToXftFamily(Family
*fam
, char *style
)
519 WM_ITERATE_ARRAY(fam
->typefaces
, face
, i
) {
520 if(strcmp(face
->typeface
, style
) != 0)
521 continue; /* go to next interation */
522 addSizeToTypeface(face
, 0);
526 fam
->typefaces
= WMCreateArray(4);
529 face
= wmalloc(sizeof(Typeface
));
530 memset(face
, 0 , sizeof(Typeface
));
532 face
->typeface
= wstrdup(style
);
533 face
->sizes
= WMCreateArray(4);
534 addSizeToTypeface(face
, 0);
536 WMAddToArray(fam
->typefaces
, face
);
540 * families (same family name) (Hashtable of family -> array)
541 * registries (same family but different registries)
545 addFontToXftFamily(WMHashTable
*families
, char *name
, char *style
)
551 array
= WMHashGet(families
, name
);
553 WM_ITERATE_ARRAY(array
, fam
, i
) {
554 if(strcmp(fam
->name
, name
) == 0 )
555 addTypefaceToXftFamily(fam
, style
);
560 array
= WMCreateArray(8);
562 fam
= wmalloc(sizeof(Family
));
563 memset(fam
, 0, sizeof(Family
));
565 fam
->name
= wstrdup(name
);
567 addTypefaceToXftFamily(fam
, style
);
569 WMAddToArray(array
, fam
);
571 WMHashInsert(families
, fam
->name
, array
);
576 listFamilies(WMScreen
*scr
, WMFontPanel
*panel
)
581 WMHashTable
*families
;
582 WMHashEnumerator enumer
;
586 pat
= FcPatternCreate();
587 os
= FcObjectSetBuild(FC_FAMILY
, FC_STYLE
, 0);
588 fs
= FcFontList(0, pat
, os
);
590 WMRunAlertPanel(scr
, panel
->win
, _("Error"),
591 _("Could not init font config library\n"), _("OK"), NULL
, NULL
);
595 FcPatternDestroy (pat
);
597 families
= WMCreateHashTable(WMStringPointerHashCallbacks
);
600 for (i
= 0; i
< fs
->nfont
; i
++) {
604 if (FcPatternGetString(fs
->fonts
[i
],FC_FAMILY
,0,&family
)==FcResultMatch
)
605 if (FcPatternGetString(fs
->fonts
[i
],FC_STYLE
,0,&style
)==FcResultMatch
)
606 addFontToXftFamily(families
, (char*)family
, (char*)style
);
608 FcFontSetDestroy(fs
);
611 enumer
= WMEnumerateHashTable(families
);
613 while ((array
= WMNextHashEnumeratorItem(&enumer
))) {
619 WM_ITERATE_ARRAY(array
, fam
, i
) {
620 strcpy(buffer
, fam
->name
);
621 item
= WMAddListItem(panel
->famLs
, buffer
);
623 item
->clientData
= fam
;
629 WMSortListItems(panel
->famLs
);
631 WMFreeHashTable(families
);
636 getSelectedFont(FontPanel
*panel
, char buffer
[], int bufsize
)
644 item
= WMGetListSelectedItem(panel
->famLs
);
647 family
= (Family
*)item
->clientData
;
649 item
= WMGetListSelectedItem(panel
->typLs
);
652 face
= (Typeface
*)item
->clientData
;
654 size
= WMGetTextFieldText(panel
->sizT
);
656 snprintf(buffer
, bufsize
, "%s:style=%s:pixelsize=%s",
667 preview(FontPanel
*panel
)
672 getSelectedFont(panel
, buffer
, sizeof(buffer
));
673 font
= WMCreateFont(WMWidgetScreen(panel
->win
), buffer
);
675 WMSetTextFieldFont(panel
->sampleT
, font
);
683 familyClick(WMWidget
*w
, void *data
)
685 WMList
*lPtr
= (WMList
*)w
;
689 FontPanel
*panel
= (FontPanel
*)data
;
691 /* current typeface and size */
697 /* must try to keep the same typeface and size for the new family */
698 item
= WMGetListSelectedItem(panel
->typLs
);
700 oface
= wstrdup(item
->text
);
702 osize
= WMGetTextFieldText(panel
->sizT
);
705 item
= WMGetListSelectedItem(lPtr
);
706 family
= (Family
*)item
->clientData
;
708 WMClearList(panel
->typLs
);
711 WM_ITERATE_ARRAY(family
->typefaces
, face
, i
) {
716 strcpy(buffer
, face
->typeface
);
717 if(strcasecmp(face
->typeface
, "Roman") == 0)
719 if(strcasecmp(face
->typeface
, "Regular") == 0)
722 fitem
= WMInsertListItem(panel
->typLs
, 0, buffer
);
724 fitem
= WMAddListItem(panel
->typLs
, buffer
);
725 fitem
->clientData
= face
;
729 facei
= WMFindRowOfListItemWithTitle(panel
->typLs
, oface
);
735 WMSelectListItem(panel
->typLs
, facei
);
736 typefaceClick(panel
->typLs
, panel
);
739 sizei
= WMFindRowOfListItemWithTitle(panel
->sizLs
, osize
);
742 WMSelectListItem(panel
->sizLs
, sizei
);
743 sizeClick(panel
->sizLs
, panel
);
755 typefaceClick(WMWidget
*w
, void *data
)
757 FontPanel
*panel
= (FontPanel
*)data
;
767 osize
= WMGetTextFieldText(panel
->sizT
);
770 item
= WMGetListSelectedItem(panel
->typLs
);
771 face
= (Typeface
*)item
->clientData
;
773 WMClearList(panel
->sizLs
);
775 WM_ITERATE_ARRAY(face
->sizes
, size
, i
) {
776 if ((int)size
!= 0) {
777 sprintf(buffer
, "%i", (int)size
);
779 WMAddListItem(panel
->sizLs
, buffer
);
784 sizei
= WMFindRowOfListItemWithTitle(panel
->sizLs
, osize
);
787 sizei
= WMFindRowOfListItemWithTitle(panel
->sizLs
, "12");
792 WMSelectListItem(panel
->sizLs
, sizei
);
793 WMSetListPosition(panel
->sizLs
, sizei
);
794 sizeClick(panel
->sizLs
, panel
);
803 sizeClick(WMWidget
*w
, void *data
)
805 FontPanel
*panel
= (FontPanel
*)data
;
808 item
= WMGetListSelectedItem(panel
->sizLs
);
809 WMSetTextFieldText(panel
->sizT
, item
->text
);
811 WMSelectTextFieldRange(panel
->sizT
, wmkrange(0, strlen(item
->text
)));
818 setFontPanelFontName(FontPanel
*panel
, char *family
, char *style
, double size
)
830 famrow
= WMFindRowOfListItemWithTitle(panel
->famLs
, family
);
835 WMSelectListItem(panel
->famLs
, famrow
);
836 WMSetListPosition(panel
->famLs
, famrow
);
838 WMClearList(panel
->typLs
);
840 item
= WMGetListSelectedItem(panel
->famLs
);
842 fam
= (Family
*)item
->clientData
;
843 WM_ITERATE_ARRAY(fam
->typefaces
, face
, i
) {
848 strcpy(buffer
, face
->typeface
);
849 if(strcasecmp(face
->typeface
, "Roman") == 0)
852 fitem
= WMInsertListItem(panel
->typLs
, 0, buffer
);
854 fitem
= WMAddListItem(panel
->typLs
, buffer
);
855 fitem
->clientData
= face
;
859 stlrow
= WMFindRowOfListItemWithTitle(panel
->typLs
, style
);
866 WMSelectListItem(panel
->typLs
, stlrow
);
868 item
= WMGetListSelectedItem(panel
->typLs
);
870 face
= (Typeface
*)item
->clientData
;
872 WMClearList(panel
->sizLs
);
875 WM_ITERATE_ARRAY(face
->sizes
, vsize
, i
) {
877 if ((int)vsize
!= 0) {
878 sprintf(buffer
, "%i", (int)vsize
);
880 WMAddListItem(panel
->sizLs
, buffer
);
884 snprintf(asize
, sizeof(asize
)-1, "%d",(int)(size
+0.5));
886 sz
= WMFindRowOfListItemWithTitle(panel
->sizLs
, asize
);
893 WMSelectListItem(panel
->sizLs
, sz
);
894 sizeClick(panel
->sizLs
, panel
);