13 #include <X11/Xft/Xft.h>
14 #include <fontconfig/fontconfig.h>
18 char *WMFontPanelFontChangedNotification
= "WMFontPanelFontChangedNotification";
23 typedef struct W_FontPanel
{
50 #define MIN_UPPER_HEIGHT 20
51 #define MIN_LOWER_HEIGHT 140
54 #define MAX_FONTS_TO_RETRIEVE 2000
56 #define BUTTON_SPACE_HEIGHT 40
59 #define MIN_HEIGHT (MIN_UPPER_HEIGHT+MIN_LOWER_HEIGHT+BUTTON_SPACE_HEIGHT)
61 #define DEF_UPPER_HEIGHT 60
62 #define DEF_LOWER_HEIGHT 310
65 #define DEF_HEIGHT (DEF_UPPER_HEIGHT+DEF_LOWER_HEIGHT)
70 static int scalableFontSizes
[] = {
87 static void setFontPanelFontName(FontPanel
*panel
, char *family
, char *style
, double size
);
89 static int isXLFD(char *font
, int *length_ret
);
91 static void arrangeLowerFrame(FontPanel
*panel
);
93 static void familyClick(WMWidget
*, void *);
94 static void typefaceClick(WMWidget
*, void *);
95 static void sizeClick(WMWidget
*, void *);
98 static void listFamilies(WMScreen
*scr
, WMFontPanel
*panel
);
102 splitViewConstrainCallback(WMSplitView
*sPtr
, int indView
, int *min
, int *max
)
105 *min
= MIN_UPPER_HEIGHT
;
107 *min
= MIN_LOWER_HEIGHT
;
111 notificationObserver(void *self
, WMNotification
*notif
)
113 WMFontPanel
*panel
= (WMFontPanel
*)self
;
114 void *object
= WMGetNotificationObject(notif
);
116 if (WMGetNotificationName(notif
) == WMViewSizeDidChangeNotification
) {
117 if (object
== WMWidgetView(panel
->win
)) {
118 int h
= WMWidgetHeight(panel
->win
);
119 int w
= WMWidgetWidth(panel
->win
);
121 WMResizeWidget(panel
->split
, w
, h
-BUTTON_SPACE_HEIGHT
);
123 WMMoveWidget(panel
->setB
, w
-80, h
-(BUTTON_SPACE_HEIGHT
-5));
125 WMMoveWidget(panel
->revertB
, w
-240, h
-(BUTTON_SPACE_HEIGHT
-5));
127 } else if (object
== WMWidgetView(panel
->upperF
)) {
129 if (WMWidgetHeight(panel
->upperF
) < MIN_UPPER_HEIGHT
) {
130 WMResizeWidget(panel
->upperF
, WMWidgetWidth(panel
->upperF
),
133 WMResizeWidget(panel
->sampleT
, WMWidgetWidth(panel
->upperF
)-20,
134 WMWidgetHeight(panel
->upperF
)-10);
137 } else if (object
== WMWidgetView(panel
->lowerF
)) {
139 if (WMWidgetHeight(panel
->lowerF
) < MIN_LOWER_HEIGHT
) {
140 WMResizeWidget(panel
->upperF
, WMWidgetWidth(panel
->upperF
),
143 WMMoveWidget(panel
->lowerF
, 0, WMWidgetHeight(panel
->upperF
)
144 + WMGetSplitViewDividerThickness(panel
->split
));
146 WMResizeWidget(panel
->lowerF
, WMWidgetWidth(panel
->lowerF
),
147 WMWidgetWidth(panel
->split
) - MIN_UPPER_HEIGHT
148 - WMGetSplitViewDividerThickness(panel
->split
));
150 arrangeLowerFrame(panel
);
158 closeWindow(WMWidget
*w
, void *data
)
160 FontPanel
*panel
= (FontPanel
*)data
;
162 WMHideFontPanel(panel
);
169 setClickedAction(WMWidget
*w
, void *data
)
171 FontPanel
*panel
= (FontPanel
*)data
;
174 (*panel
->action
)(panel
, panel
->data
);
179 revertClickedAction(WMWidget
*w
, void *data
)
181 /*FontPanel *panel = (FontPanel*)data;*/
188 WMGetFontPanel(WMScreen
*scr
)
191 WMColor
*dark
, *white
;
195 if (scr
->sharedFontPanel
)
196 return scr
->sharedFontPanel
;
199 panel
= wmalloc(sizeof(FontPanel
));
200 memset(panel
, 0, sizeof(FontPanel
));
202 panel
->win
= WMCreateWindow(scr
, "fontPanel");
203 /* WMSetWidgetBackgroundColor(panel->win, WMWhiteColor(scr));*/
204 WMSetWindowTitle(panel
->win
, _("Font Panel"));
205 WMResizeWidget(panel
->win
, DEF_WIDTH
, DEF_HEIGHT
);
206 WMSetWindowMinSize(panel
->win
, MIN_WIDTH
, MIN_HEIGHT
);
207 WMSetViewNotifySizeChanges(WMWidgetView(panel
->win
), True
);
209 WMSetWindowCloseAction(panel
->win
, closeWindow
, panel
);
211 panel
->split
= WMCreateSplitView(panel
->win
);
212 WMResizeWidget(panel
->split
, DEF_WIDTH
, DEF_HEIGHT
- BUTTON_SPACE_HEIGHT
);
213 WMSetSplitViewConstrainProc(panel
->split
, splitViewConstrainCallback
);
215 divThickness
= WMGetSplitViewDividerThickness(panel
->split
);
217 panel
->upperF
= WMCreateFrame(panel
->win
);
218 WMSetFrameRelief(panel
->upperF
, WRFlat
);
219 WMSetViewNotifySizeChanges(WMWidgetView(panel
->upperF
), True
);
220 panel
->lowerF
= WMCreateFrame(panel
->win
);
221 /* WMSetWidgetBackgroundColor(panel->lowerF, WMBlackColor(scr));*/
222 WMSetFrameRelief(panel
->lowerF
, WRFlat
);
223 WMSetViewNotifySizeChanges(WMWidgetView(panel
->lowerF
), True
);
225 WMAddSplitViewSubview(panel
->split
, W_VIEW(panel
->upperF
));
226 WMAddSplitViewSubview(panel
->split
, W_VIEW(panel
->lowerF
));
228 WMResizeWidget(panel
->upperF
, DEF_WIDTH
, DEF_UPPER_HEIGHT
);
230 WMResizeWidget(panel
->lowerF
, DEF_WIDTH
, DEF_LOWER_HEIGHT
);
232 WMMoveWidget(panel
->lowerF
, 0, 60+divThickness
);
234 white
= WMWhiteColor(scr
);
235 dark
= WMDarkGrayColor(scr
);
237 panel
->sampleT
= WMCreateTextField(panel
->upperF
);
238 WMResizeWidget(panel
->sampleT
, DEF_WIDTH
- 20, 50);
239 WMMoveWidget(panel
->sampleT
, 10, 10);
240 WMSetTextFieldText(panel
->sampleT
, _("The quick brown fox jumps over the lazy dog"));
242 font
= WMBoldSystemFontOfSize(scr
, 12);
244 panel
->famL
= WMCreateLabel(panel
->lowerF
);
245 WMSetWidgetBackgroundColor(panel
->famL
, dark
);
246 WMSetLabelText(panel
->famL
, _("Family"));
247 WMSetLabelFont(panel
->famL
, font
);
248 WMSetLabelTextColor(panel
->famL
, white
);
249 WMSetLabelRelief(panel
->famL
, WRSunken
);
250 WMSetLabelTextAlignment(panel
->famL
, WACenter
);
252 panel
->famLs
= WMCreateList(panel
->lowerF
);
253 WMSetListAction(panel
->famLs
, familyClick
, panel
);
255 panel
->typL
= WMCreateLabel(panel
->lowerF
);
256 WMSetWidgetBackgroundColor(panel
->typL
, dark
);
257 WMSetLabelText(panel
->typL
, _("Typeface"));
258 WMSetLabelFont(panel
->typL
, font
);
259 WMSetLabelTextColor(panel
->typL
, white
);
260 WMSetLabelRelief(panel
->typL
, WRSunken
);
261 WMSetLabelTextAlignment(panel
->typL
, WACenter
);
263 panel
->typLs
= WMCreateList(panel
->lowerF
);
264 WMSetListAction(panel
->typLs
, typefaceClick
, panel
);
266 panel
->sizL
= WMCreateLabel(panel
->lowerF
);
267 WMSetWidgetBackgroundColor(panel
->sizL
, dark
);
268 WMSetLabelText(panel
->sizL
, _("Size"));
269 WMSetLabelFont(panel
->sizL
, font
);
270 WMSetLabelTextColor(panel
->sizL
, white
);
271 WMSetLabelRelief(panel
->sizL
, WRSunken
);
272 WMSetLabelTextAlignment(panel
->sizL
, WACenter
);
274 panel
->sizT
= WMCreateTextField(panel
->lowerF
);
275 /* WMSetTextFieldAlignment(panel->sizT, WARight);*/
277 panel
->sizLs
= WMCreateList(panel
->lowerF
);
278 WMSetListAction(panel
->sizLs
, sizeClick
, panel
);
281 WMReleaseColor(white
);
282 WMReleaseColor(dark
);
284 panel
->setB
= WMCreateCommandButton(panel
->win
);
285 WMResizeWidget(panel
->setB
, 70, 24);
286 WMMoveWidget(panel
->setB
, 240, DEF_HEIGHT
- (BUTTON_SPACE_HEIGHT
-5));
287 WMSetButtonText(panel
->setB
, _("Set"));
288 WMSetButtonAction(panel
->setB
, setClickedAction
, panel
);
290 panel
->revertB
= WMCreateCommandButton(panel
->win
);
291 WMResizeWidget(panel
->revertB
, 70, 24);
292 WMMoveWidget(panel
->revertB
, 80, DEF_HEIGHT
- (BUTTON_SPACE_HEIGHT
-5));
293 WMSetButtonText(panel
->revertB
, _("Revert"));
294 WMSetButtonAction(panel
->revertB
, revertClickedAction
, panel
);
297 WMRealizeWidget(panel
->win
);
299 WMMapSubwidgets(panel
->upperF
);
300 WMMapSubwidgets(panel
->lowerF
);
301 WMMapSubwidgets(panel
->split
);
302 WMMapSubwidgets(panel
->win
);
304 WMUnmapWidget(panel
->revertB
);
306 arrangeLowerFrame(panel
);
308 scr
->sharedFontPanel
= panel
;
311 /* register notification observers */
312 WMAddNotificationObserver(notificationObserver
, panel
,
313 WMViewSizeDidChangeNotification
,
314 WMWidgetView(panel
->win
));
315 WMAddNotificationObserver(notificationObserver
, panel
,
316 WMViewSizeDidChangeNotification
,
317 WMWidgetView(panel
->upperF
));
318 WMAddNotificationObserver(notificationObserver
, panel
,
319 WMViewSizeDidChangeNotification
,
320 WMWidgetView(panel
->lowerF
));
323 listFamilies(scr
, panel
);
331 WMFreeFontPanel(WMFontPanel
*panel
)
333 if (panel
== WMWidgetScreen(panel
->win
)->sharedFontPanel
) {
334 WMWidgetScreen(panel
->win
)->sharedFontPanel
= NULL
;
336 WMRemoveNotificationObserver(panel
);
337 WMUnmapWidget(panel
->win
);
338 WMDestroyWidget(panel
->win
);
344 WMShowFontPanel(WMFontPanel
*panel
)
346 WMMapWidget(panel
->win
);
351 WMHideFontPanel(WMFontPanel
*panel
)
353 WMUnmapWidget(panel
->win
);
358 WMGetFontPanelFont(WMFontPanel
*panel
)
360 return WMGetTextFieldFont(panel
->sampleT
);
365 WMSetFontPanelFont(WMFontPanel
*panel
, char *fontName
)
369 FcChar8
*family
, *style
;
372 if (!isXLFD(fontName
, &fname_len
)) {
373 /* maybe its proper fontconfig and we can parse it */
374 pattern
= FcNameParse((FcChar8
*)fontName
);
376 /* maybe its proper xlfd and we can convert it to an FcPattern */
377 pattern
= XftXlfdParse(fontName
, False
, False
);
378 /*//FcPatternPrint(pattern);*/
384 if (FcPatternGetString(pattern
, FC_FAMILY
, 0, &family
)==FcResultMatch
)
385 if (FcPatternGetString(pattern
, FC_STYLE
, 0, &style
)==FcResultMatch
)
386 if (FcPatternGetDouble(pattern
, "pixelsize", 0, &size
)==FcResultMatch
)
387 setFontPanelFontName(panel
, (char*)family
, (char*)style
, size
);
389 FcPatternDestroy(pattern
);
394 WMSetFontPanelAction(WMFontPanel
*panel
, WMAction2
*action
, void *data
)
396 panel
->action
= action
;
405 arrangeLowerFrame(FontPanel
*panel
)
407 int width
= WMWidgetWidth(panel
->lowerF
) - 55 - 30;
408 int height
= WMWidgetHeight(panel
->split
) - WMWidgetHeight(panel
->upperF
);
411 #define LABEL_HEIGHT 20
413 height
-= WMGetSplitViewDividerThickness(panel
->split
);
416 height
-= LABEL_HEIGHT
+ 8;
418 fw
= (125*width
) / 235;
419 tw
= (110*width
) / 235;
422 WMMoveWidget(panel
->famL
, 10, 0);
423 WMResizeWidget(panel
->famL
, fw
, LABEL_HEIGHT
);
425 WMMoveWidget(panel
->famLs
, 10, 23);
426 WMResizeWidget(panel
->famLs
, fw
, height
);
428 WMMoveWidget(panel
->typL
, 10+fw
+3, 0);
429 WMResizeWidget(panel
->typL
, tw
, LABEL_HEIGHT
);
431 WMMoveWidget(panel
->typLs
, 10+fw
+3, 23);
432 WMResizeWidget(panel
->typLs
, tw
, height
);
434 WMMoveWidget(panel
->sizL
, 10+fw
+3+tw
+3, 0);
435 WMResizeWidget(panel
->sizL
, sw
+4, LABEL_HEIGHT
);
437 WMMoveWidget(panel
->sizT
, 10+fw
+3+tw
+3, 23);
438 WMResizeWidget(panel
->sizT
, sw
+4, 20);
440 WMMoveWidget(panel
->sizLs
, 10+fw
+3+tw
+3, 46);
441 WMResizeWidget(panel
->sizLs
, sw
+4, height
-23);
446 #define NUM_FIELDS 14
450 isXLFD(char *font
, int *length_ret
)
461 return c
==NUM_FIELDS
;
471 char *name
; /* gotta love simplicity */
477 compare_int(const void *a
, const void *b
)
492 addSizeToTypeface(Typeface
*face
, int size
)
497 for (j
= 0; j
< sizeof(scalableFontSizes
)/sizeof(int); j
++) {
498 size
= scalableFontSizes
[j
];
500 if (!WMCountInArray(face
->sizes
, (void*)(uintptr_t)size
)) {
501 WMAddToArray(face
->sizes
, (void*)(uintptr_t)size
);
504 WMSortArray(face
->sizes
, compare_int
);
506 if (!WMCountInArray(face
->sizes
, (void*)(uintptr_t)size
)) {
507 WMAddToArray(face
->sizes
, (void*)(uintptr_t)size
);
508 WMSortArray(face
->sizes
, compare_int
);
514 addTypefaceToXftFamily(Family
*fam
, char *style
)
520 WM_ITERATE_ARRAY(fam
->typefaces
, face
, i
) {
521 if(strcmp(face
->typeface
, style
) != 0)
522 continue; /* go to next interation */
523 addSizeToTypeface(face
, 0);
527 fam
->typefaces
= WMCreateArray(4);
530 face
= wmalloc(sizeof(Typeface
));
531 memset(face
, 0 , sizeof(Typeface
));
533 face
->typeface
= wstrdup(style
);
534 face
->sizes
= WMCreateArray(4);
535 addSizeToTypeface(face
, 0);
537 WMAddToArray(fam
->typefaces
, face
);
541 * families (same family name) (Hashtable of family -> array)
542 * registries (same family but different registries)
546 addFontToXftFamily(WMHashTable
*families
, char *name
, char *style
)
552 array
= WMHashGet(families
, name
);
554 WM_ITERATE_ARRAY(array
, fam
, i
) {
555 if(strcmp(fam
->name
, name
) == 0 )
556 addTypefaceToXftFamily(fam
, style
);
561 array
= WMCreateArray(8);
563 fam
= wmalloc(sizeof(Family
));
564 memset(fam
, 0, sizeof(Family
));
566 fam
->name
= wstrdup(name
);
568 addTypefaceToXftFamily(fam
, style
);
570 WMAddToArray(array
, fam
);
572 WMHashInsert(families
, fam
->name
, array
);
577 listFamilies(WMScreen
*scr
, WMFontPanel
*panel
)
582 WMHashTable
*families
;
583 WMHashEnumerator enumer
;
587 pat
= FcPatternCreate();
588 os
= FcObjectSetBuild(FC_FAMILY
, FC_STYLE
, NULL
);
589 fs
= FcFontList(0, pat
, os
);
591 WMRunAlertPanel(scr
, panel
->win
, _("Error"),
592 _("Could not init font config library\n"), _("OK"), NULL
, NULL
);
596 FcPatternDestroy (pat
);
598 families
= WMCreateHashTable(WMStringPointerHashCallbacks
);
601 for (i
= 0; i
< fs
->nfont
; i
++) {
605 if (FcPatternGetString(fs
->fonts
[i
],FC_FAMILY
,0,&family
)==FcResultMatch
)
606 if (FcPatternGetString(fs
->fonts
[i
],FC_STYLE
,0,&style
)==FcResultMatch
)
607 addFontToXftFamily(families
, (char*)family
, (char*)style
);
609 FcFontSetDestroy(fs
);
612 enumer
= WMEnumerateHashTable(families
);
614 while ((array
= WMNextHashEnumeratorItem(&enumer
))) {
620 WM_ITERATE_ARRAY(array
, fam
, i
) {
621 strcpy(buffer
, fam
->name
);
622 item
= WMAddListItem(panel
->famLs
, buffer
);
624 item
->clientData
= fam
;
630 WMSortListItems(panel
->famLs
);
632 WMFreeHashTable(families
);
637 getSelectedFont(FontPanel
*panel
, char buffer
[], int bufsize
)
645 item
= WMGetListSelectedItem(panel
->famLs
);
648 family
= (Family
*)item
->clientData
;
650 item
= WMGetListSelectedItem(panel
->typLs
);
653 face
= (Typeface
*)item
->clientData
;
655 size
= WMGetTextFieldText(panel
->sizT
);
657 snprintf(buffer
, bufsize
, "%s:style=%s:pixelsize=%s",
668 preview(FontPanel
*panel
)
673 getSelectedFont(panel
, buffer
, sizeof(buffer
));
674 font
= WMCreateFont(WMWidgetScreen(panel
->win
), buffer
);
676 WMSetTextFieldFont(panel
->sampleT
, font
);
684 familyClick(WMWidget
*w
, void *data
)
686 WMList
*lPtr
= (WMList
*)w
;
690 FontPanel
*panel
= (FontPanel
*)data
;
692 /* current typeface and size */
698 /* must try to keep the same typeface and size for the new family */
699 item
= WMGetListSelectedItem(panel
->typLs
);
701 oface
= wstrdup(item
->text
);
703 osize
= WMGetTextFieldText(panel
->sizT
);
706 item
= WMGetListSelectedItem(lPtr
);
707 family
= (Family
*)item
->clientData
;
709 WMClearList(panel
->typLs
);
712 WM_ITERATE_ARRAY(family
->typefaces
, face
, i
) {
717 strcpy(buffer
, face
->typeface
);
718 if(strcasecmp(face
->typeface
, "Roman") == 0)
720 if(strcasecmp(face
->typeface
, "Regular") == 0)
723 fitem
= WMInsertListItem(panel
->typLs
, 0, buffer
);
725 fitem
= WMAddListItem(panel
->typLs
, buffer
);
726 fitem
->clientData
= face
;
730 facei
= WMFindRowOfListItemWithTitle(panel
->typLs
, oface
);
736 WMSelectListItem(panel
->typLs
, facei
);
737 typefaceClick(panel
->typLs
, panel
);
740 sizei
= WMFindRowOfListItemWithTitle(panel
->sizLs
, osize
);
743 WMSelectListItem(panel
->sizLs
, sizei
);
744 sizeClick(panel
->sizLs
, panel
);
756 typefaceClick(WMWidget
*w
, void *data
)
758 FontPanel
*panel
= (FontPanel
*)data
;
768 osize
= WMGetTextFieldText(panel
->sizT
);
771 item
= WMGetListSelectedItem(panel
->typLs
);
772 face
= (Typeface
*)item
->clientData
;
774 WMClearList(panel
->sizLs
);
776 WM_ITERATE_ARRAY(face
->sizes
, size
, i
) {
777 if ((int)(uintptr_t)size
!= 0) {
778 sprintf(buffer
, "%i", (int)(uintptr_t)size
);
780 WMAddListItem(panel
->sizLs
, buffer
);
785 sizei
= WMFindRowOfListItemWithTitle(panel
->sizLs
, osize
);
788 sizei
= WMFindRowOfListItemWithTitle(panel
->sizLs
, "12");
793 WMSelectListItem(panel
->sizLs
, sizei
);
794 WMSetListPosition(panel
->sizLs
, sizei
);
795 sizeClick(panel
->sizLs
, panel
);
804 sizeClick(WMWidget
*w
, void *data
)
806 FontPanel
*panel
= (FontPanel
*)data
;
809 item
= WMGetListSelectedItem(panel
->sizLs
);
810 WMSetTextFieldText(panel
->sizT
, item
->text
);
812 WMSelectTextFieldRange(panel
->sizT
, wmkrange(0, strlen(item
->text
)));
819 setFontPanelFontName(FontPanel
*panel
, char *family
, char *style
, double size
)
831 famrow
= WMFindRowOfListItemWithTitle(panel
->famLs
, family
);
836 WMSelectListItem(panel
->famLs
, famrow
);
837 WMSetListPosition(panel
->famLs
, famrow
);
839 WMClearList(panel
->typLs
);
841 item
= WMGetListSelectedItem(panel
->famLs
);
843 fam
= (Family
*)item
->clientData
;
844 WM_ITERATE_ARRAY(fam
->typefaces
, face
, i
) {
849 strcpy(buffer
, face
->typeface
);
850 if(strcasecmp(face
->typeface
, "Roman") == 0)
853 fitem
= WMInsertListItem(panel
->typLs
, 0, buffer
);
855 fitem
= WMAddListItem(panel
->typLs
, buffer
);
856 fitem
->clientData
= face
;
860 stlrow
= WMFindRowOfListItemWithTitle(panel
->typLs
, style
);
867 WMSelectListItem(panel
->typLs
, stlrow
);
869 item
= WMGetListSelectedItem(panel
->typLs
);
871 face
= (Typeface
*)item
->clientData
;
873 WMClearList(panel
->sizLs
);
876 WM_ITERATE_ARRAY(face
->sizes
, vsize
, i
) {
878 if ((int)(uintptr_t)vsize
!= 0) {
879 sprintf(buffer
, "%i", (int)(uintptr_t)vsize
);
881 WMAddListItem(panel
->sizLs
, buffer
);
885 snprintf(asize
, sizeof(asize
)-1, "%d",(int)(size
+0.5));
887 sz
= WMFindRowOfListItemWithTitle(panel
->sizLs
, asize
);
894 WMSelectListItem(panel
->sizLs
, sz
);
895 sizeClick(panel
->sizLs
, panel
);