Initial revision
[wmaker-crm.git] / WINGs / wfontpanel.c
blob734d213424048c002ef5f773da77496eceb2b7cc
5 #include "WINGsP.h"
7 #include <strings.h>
10 typedef struct W_FontPanel {
11 WMWindow *win;
13 WMFrame *upperF;
14 WMLabel *sampleL;
16 WMSplitView *split;
18 WMFrame *lowerF;
19 WMLabel *famL;
20 WMList *famLs;
21 WMLabel *typL;
22 WMList *typLs;
23 WMLabel *sizL;
24 WMTextField *sizT;
25 WMList *sizLs;
27 WMFrame *xlfdF;
28 WMTextField *xlfdT;
30 WMFrame *encF;
31 WMPopUpButton *encP;
33 WMButton *revertB;
34 WMButton *previewB;
35 WMButton *setB;
37 proplist_t fdb;
38 } FontPanel;
41 #define MIN_UPPER_HEIGHT 20
42 #define MIN_LOWER_HEIGHT 140
45 #define MAX_FONTS_TO_RETRIEVE 2000
48 #define MIN_WIDTH 250
49 #define MIN_HEIGHT MIN_UPPER_HEIGHT+MIN_LOWER_HEIGHT+70
52 static char *scalableFontSizes[] = {
53 "8",
54 "10",
55 "11",
56 "12",
57 "14",
58 "16",
59 "18",
60 "20",
61 "24",
62 "36",
63 "48",
64 "64"
66 */
71 static void arrangeLowerFrame(FontPanel *panel);
73 static proplist_t createFontDatabase(WMScreen *scr);
75 static void listFamilies(proplist_t fdb, WMList *list);
77 static void
78 splitViewConstrainCallback(WMSplitView *sPtr, int divIndex, int *min, int *max)
80 *min = MIN_UPPER_HEIGHT;
81 *max = WMWidgetHeight(sPtr)-WMGetSplitViewDividerThickness(sPtr)-MIN_LOWER_HEIGHT;
85 static void
86 notificationObserver(void *self, WMNotification *notif)
88 WMFontPanel *panel = (WMFontPanel*)self;
89 void *object = WMGetNotificationObject(notif);
91 if (WMGetNotificationName(notif) == WMViewSizeDidChangeNotification) {
92 if (object == WMWidgetView(panel->win)) {
93 int h = WMWidgetHeight(panel->win);
94 int w = WMWidgetWidth(panel->win);
96 WMResizeWidget(panel->split, w, h-40);
98 WMMoveWidget(panel->setB, w-80, h-35);
99 WMMoveWidget(panel->previewB, w-160, h-35);
100 WMMoveWidget(panel->revertB, w-240, h-35);
101 } else if (object == WMWidgetView(panel->upperF)) {
102 WMResizeWidget(panel->sampleL, WMWidgetWidth(panel->upperF)-20,
103 WMWidgetHeight(panel->upperF)-10);
104 } else if (object == WMWidgetView(panel->lowerF)) {
106 if (WMWidgetHeight(panel->lowerF) < MIN_LOWER_HEIGHT) {
107 int h;
109 h = WMWidgetHeight(panel->split)-MIN_LOWER_HEIGHT
110 - WMGetSplitViewDividerThickness(panel->split);
112 WMResizeWidget(panel->upperF, WMWidgetWidth(panel->upperF), h);
114 WMMoveWidget(panel->lowerF, 0, WMWidgetHeight(panel->upperF)
115 + WMGetSplitViewDividerThickness(panel->split));
116 WMResizeWidget(panel->lowerF, WMWidgetWidth(panel->lowerF),
117 MIN_LOWER_HEIGHT);
118 } else {
119 arrangeLowerFrame(panel);
127 static void
128 familyClick(WMWidget *w, void *data)
130 WMList *lPtr = (WMList*)w;
131 FontPanel *panel = (FontPanel*)data;
138 WMFontPanel*
139 WMGetFontPanel(WMScreen *scr)
141 FontPanel *panel;
142 WMColor *dark, *white;
143 WMFont *font;
144 int divThickness;
146 if (scr->sharedFontPanel)
147 return scr->sharedFontPanel;
150 panel = wmalloc(sizeof(FontPanel));
151 memset(panel, 0, sizeof(FontPanel));
153 panel->win = WMCreateWindow(scr, "fontPanel");
154 WMResizeWidget(panel->win, 320, 370);
155 WMSetWindowMinSize(panel->win, MIN_WIDTH, MIN_HEIGHT);
156 WMSetViewNotifySizeChanges(WMWidgetView(panel->win), True);
158 panel->split = WMCreateSplitView(panel->win);
159 WMResizeWidget(panel->split, 320, 330);
160 WMSetSplitViewConstrainProc(panel->split, splitViewConstrainCallback);
162 divThickness = WMGetSplitViewDividerThickness(panel->split);
164 panel->upperF = WMCreateFrame(panel->win);
165 WMSetFrameRelief(panel->upperF, WRFlat);
166 WMSetViewNotifySizeChanges(WMWidgetView(panel->upperF), True);
167 panel->lowerF = WMCreateFrame(panel->win);
168 WMSetFrameRelief(panel->lowerF, WRFlat);
169 WMSetViewNotifySizeChanges(WMWidgetView(panel->lowerF), True);
171 WMAddSplitViewSubview(panel->split, W_VIEW(panel->upperF));
172 WMAddSplitViewSubview(panel->split, W_VIEW(panel->lowerF));
174 WMResizeWidget(panel->upperF, 320, 60);
175 WMResizeWidget(panel->lowerF, 320, 330-60-divThickness);
176 WMMoveWidget(panel->lowerF, 0, 60+divThickness);
178 white = WMWhiteColor(scr);
179 dark = WMDarkGrayColor(scr);
181 panel->sampleL = WMCreateLabel(panel->upperF);
182 WMResizeWidget(panel->sampleL, 300, 50);
183 WMMoveWidget(panel->sampleL, 10, 10);
184 WMSetWidgetBackgroundColor(panel->sampleL, white);
185 WMSetLabelRelief(panel->sampleL, WRSunken);
186 WMSetLabelText(panel->sampleL, "It is not yet completed!!!");
188 font = WMBoldSystemFontOfSize(scr, 12);
190 panel->famL = WMCreateLabel(panel->lowerF);
191 WMSetWidgetBackgroundColor(panel->famL, dark);
192 WMSetLabelText(panel->famL, "Family");
193 WMSetLabelFont(panel->famL, font);
194 WMSetLabelTextColor(panel->famL, white);
195 WMSetLabelRelief(panel->famL, WRSunken);
196 WMSetLabelTextAlignment(panel->famL, WACenter);
198 panel->famLs = WMCreateList(panel->lowerF);
200 panel->typL = WMCreateLabel(panel->lowerF);
201 WMSetWidgetBackgroundColor(panel->typL, dark);
202 WMSetLabelText(panel->typL, "Typeface");
203 WMSetLabelFont(panel->typL, font);
204 WMSetLabelTextColor(panel->typL, white);
205 WMSetLabelRelief(panel->typL, WRSunken);
206 WMSetLabelTextAlignment(panel->typL, WACenter);
208 panel->typLs = WMCreateList(panel->lowerF);
210 panel->sizL = WMCreateLabel(panel->lowerF);
211 WMSetWidgetBackgroundColor(panel->sizL, dark);
212 WMSetLabelText(panel->sizL, "Size");
213 WMSetLabelFont(panel->sizL, font);
214 WMSetLabelTextColor(panel->sizL, white);
215 WMSetLabelRelief(panel->sizL, WRSunken);
216 WMSetLabelTextAlignment(panel->sizL, WACenter);
218 panel->sizT = WMCreateTextField(panel->lowerF);
220 panel->sizLs = WMCreateList(panel->lowerF);
222 WMReleaseFont(font);
223 WMReleaseColor(white);
224 WMReleaseColor(dark);
226 panel->encF = WMCreateFrame(panel->lowerF);
227 WMSetFrameTitle(panel->encF, "Encoding");
228 WMResizeWidget(panel->encF, 130, 50);
230 panel->encP = WMCreatePopUpButton(panel->encF);
231 WMMoveWidget(panel->encP, 10, 20);
232 WMResizeWidget(panel->encP, 112, 20);
234 WMMapSubwidgets(panel->encF);
236 panel->xlfdF = WMCreateFrame(panel->lowerF);
237 WMSetFrameTitle(panel->xlfdF, "Xtra Long Font Description");
239 panel->xlfdT = WMCreateTextField(panel->xlfdF);
240 WMMoveWidget(panel->xlfdT, 10, 20);
242 WMMapSubwidgets(panel->xlfdF);
244 arrangeLowerFrame(panel);
246 panel->setB = WMCreateCommandButton(panel->win);
247 WMResizeWidget(panel->setB, 70, 24);
248 WMMoveWidget(panel->setB, 240, 335);
249 WMSetButtonText(panel->setB, "Set");
251 panel->previewB = WMCreateCommandButton(panel->win);
252 WMResizeWidget(panel->previewB, 70, 24);
253 WMMoveWidget(panel->previewB, 160, 335);
254 WMSetButtonText(panel->previewB, "Preview");
256 panel->revertB = WMCreateCommandButton(panel->win);
257 WMResizeWidget(panel->revertB, 70, 24);
258 WMMoveWidget(panel->revertB, 80, 335);
259 WMSetButtonText(panel->revertB, "Revert");
261 WMRealizeWidget(panel->win);
263 WMMapSubwidgets(panel->upperF);
264 WMMapSubwidgets(panel->lowerF);
265 WMMapSubwidgets(panel->split);
266 WMMapSubwidgets(panel->win);
268 scr->sharedFontPanel = panel;
271 /* register notification observers */
272 WMAddNotificationObserver(notificationObserver, panel,
273 WMViewSizeDidChangeNotification,
274 WMWidgetView(panel->win));
275 WMAddNotificationObserver(notificationObserver, panel,
276 WMViewSizeDidChangeNotification,
277 WMWidgetView(panel->upperF));
278 WMAddNotificationObserver(notificationObserver, panel,
279 WMViewSizeDidChangeNotification,
280 WMWidgetView(panel->lowerF));
282 panel->fdb = createFontDatabase(scr);
283 listFamilies(panel->fdb, panel->famLs);
285 return panel;
289 void
290 WMFreeFontPanel(WMFontPanel *panel)
292 if (panel == WMWidgetScreen(panel->win)->sharedFontPanel) {
293 WMWidgetScreen(panel->win)->sharedFontPanel = NULL;
295 WMRemoveNotificationObserver(panel);
296 WMUnmapWidget(panel->win);
297 WMDestroyWidget(panel->win);
298 free(panel);
302 void
303 WMShowFontPanel(WMFontPanel *panel)
305 WMMapWidget(panel->win);
308 void
309 WMHideFontPanel(WMFontPanel *panel)
311 WMUnmapWidget(panel->win);
315 void
316 WMSetFontPanelFont(WMFontPanel *panel, WMFont *font)
321 WMFont*
322 WMGetFontPanelFont(WMFontPanel *panel)
324 return NULL;
328 char*
329 WMGetFontPanelFontName(WMFontPanel *panel)
331 return NULL;
337 static void
338 arrangeLowerFrame(FontPanel *panel)
340 int width = WMWidgetWidth(panel->lowerF) - 55 - 30;
341 int height = WMWidgetHeight(panel->lowerF);
342 int oheight = 330-60-WMGetSplitViewDividerThickness(panel->split);
343 int fw, tw, sw;
344 int h;
346 height -= 20 + 3 + 10 + 50;
347 oheight -= 20 + 3 + 10 + 50;
349 fw = (125*width) / 235;
350 tw = (110*width) / 235;
351 sw = 55;
353 h = (174*height) / oheight;
355 WMMoveWidget(panel->famL, 10, 0);
356 WMResizeWidget(panel->famL, fw, 20);
358 WMMoveWidget(panel->famLs, 10, 23);
359 WMResizeWidget(panel->famLs, fw, h);
361 WMMoveWidget(panel->typL, 10+fw+3, 0);
362 WMResizeWidget(panel->typL, tw, 20);
364 WMMoveWidget(panel->typLs, 10+fw+3, 23);
365 WMResizeWidget(panel->typLs, tw, h);
367 WMMoveWidget(panel->sizL, 10+fw+3+tw+3, 0);
368 WMResizeWidget(panel->sizL, sw+4, 20);
370 WMMoveWidget(panel->sizT, 10+fw+3+tw+3, 23);
371 WMResizeWidget(panel->sizT, sw+4, 20);
373 WMMoveWidget(panel->sizLs, 10+fw+3+tw+3, 46);
374 WMResizeWidget(panel->sizLs, sw+4, h-22);
376 WMMoveWidget(panel->encF, 10, WMWidgetHeight(panel->lowerF)-55);
378 WMMoveWidget(panel->xlfdF, 145, WMWidgetHeight(panel->lowerF)-55);
379 WMResizeWidget(panel->xlfdF, WMWidgetWidth(panel->lowerF)-155, 50);
381 WMResizeWidget(panel->xlfdT, WMWidgetWidth(panel->lowerF)-155-20, 20);
387 #define ALL_FONTS_MASK "-*-*-*-*-*-*-*-*-*-*-*-*-*-*"
389 #define FOUNDRY 0
390 #define FAMILY 1
391 #define WEIGHT 2
392 #define SLANT 3
393 #define SETWIDTH 4
394 #define ADD_STYLE 5
395 #define PIXEL_SIZE 6
396 #define POINT_SIZE 7
397 #define RES_X 8
398 #define RES_Y 9
399 #define SPACING 10
400 #define AV_WIDTH 11
401 #define REGISTRY 12
402 #define ENCODING 13
404 #define NUM_FIELDS 14
407 static Bool
408 parseFont(char *font, char **values)
410 char *ptr;
411 int part;
412 char buffer[256], *bptr;
414 part = FOUNDRY;
415 ptr = font;
416 ptr++; /* skip first - */
417 bptr = buffer;
418 while (*ptr) {
419 if (*ptr == '-') {
420 *bptr = 0;
421 values[part]=wstrdup(buffer);
422 bptr = buffer;
423 part++;
424 } else {
425 *bptr++ = *ptr;
427 ptr++;
429 *bptr = 0;
430 values[part]=wstrdup(buffer);
432 return True;
437 static int
438 isXLFD(char *font, int *length_ret)
440 int c = 0;
442 *length_ret = 0;
443 while (*font) {
444 (*length_ret)++;
445 if (*font++ == '-')
446 c++;
449 return c==NUM_FIELDS;
455 static proplist_t foundryKey = NULL;
456 static proplist_t typeKey = NULL;
457 static proplist_t sizeKey, encKey, xlfdKey;
460 static void
461 addSizeToEnc(proplist_t enc, char **fields)
463 proplist_t sizel;
465 sizel = PLGetDictionaryEntry(enc, sizeKey);
466 if (!sizel) {
467 sizel = PLMakeArrayFromElements(PLMakeString(fields[PIXEL_SIZE]),NULL);
468 PLInsertDictionaryEntry(enc, sizeKey, sizel);
469 } else {
470 PLAppendArrayElement(sizel, PLMakeString(fields[PIXEL_SIZE]));
475 static proplist_t
476 addTypefaceToFont(proplist_t font, char **fields)
478 proplist_t face, encod, facedic, encodic;
479 char buffer[256];
481 strcpy(buffer, fields[WEIGHT]);
483 if (strcasecmp(fields[SLANT], "R")==0)
484 strcat(buffer, " Roman ");
485 else if (strcasecmp(fields[SLANT], "I")==0)
486 strcat(buffer, " Italic ");
487 else if (strcasecmp(fields[SLANT], "O")==0)
488 strcat(buffer, " Oblique ");
489 else if (strcasecmp(fields[SLANT], "RI")==0)
490 strcat(buffer, " Reverse Italic ");
491 else if (strcasecmp(fields[SLANT], "RO")==0)
492 strcat(buffer, " Reverse Oblique ");
493 else if (strcasecmp(fields[SLANT], "OT")==0)
494 strcat(buffer, " ? ");
495 /* else
496 * polymorphic fonts
498 strcat(buffer, fields[SETWIDTH]);
499 strcat(buffer, " ");
500 strcat(buffer, fields[ADD_STYLE]);
502 face = PLMakeString(buffer);
504 facedic = PLGetDictionaryEntry(font, face);
505 if (!facedic) {
506 facedic = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
507 PLInsertDictionaryEntry(font, face, facedic);
508 PLRelease(facedic);
510 PLRelease(face);
512 strcpy(buffer, fields[REGISTRY]);
513 strcat(buffer, "-");
514 strcat(buffer, fields[ENCODING]);
515 encod = PLMakeString(buffer);
517 encodic = PLGetDictionaryEntry(facedic, encod);
518 if (!encodic) {
519 proplist_t tmp;
520 sprintf(buffer, "-%s-%s-%s-%s-%s-%s-%%d-0-%s-%s-%s-%s-%s-%s",
521 fields[FOUNDRY], fields[FAMILY], fields[WEIGHT],
522 fields[SLANT], fields[SETWIDTH], fields[ADD_STYLE],
523 fields[RES_X], fields[RES_Y], fields[SPACING],
524 fields[AV_WIDTH], fields[REGISTRY], fields[ENCODING]);
525 tmp = PLMakeString(buffer);
527 encodic = PLMakeDictionaryFromEntries(xlfdKey, tmp, NULL);
528 PLRelease(tmp);
529 PLInsertDictionaryEntry(facedic, encod, encodic);
530 PLRelease(encodic);
532 addSizeToEnc(encodic, fields);
533 return font;
537 static proplist_t
538 makeFontEntry(char **fields)
540 proplist_t font;
541 proplist_t value;
542 proplist_t tmp;
543 value = PLMakeString(fields[FOUNDRY]);
545 tmp = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
547 font = PLMakeDictionaryFromEntries(foundryKey, value,
548 typeKey, tmp,
549 NULL);
550 PLRelease(value);
551 PLRelease(tmp);
553 addTypefaceToFont(font, fields);
555 return font;
559 static proplist_t
560 createFontDatabase(WMScreen *scr)
562 char **fontList;
563 int count;
564 char *fields[NUM_FIELDS];
565 int font_name_length;
566 char buffer[256];
567 int i;
568 proplist_t fdb;
569 proplist_t font;
570 proplist_t family;
571 proplist_t foundry;
572 proplist_t tmp;
574 if (!foundryKey) {
575 foundryKey = PLMakeString("Foundry");
576 typeKey = PLMakeString("Typeface");
577 encKey = PLMakeString("Encoding");
578 sizeKey = PLMakeString("Sizes");
579 xlfdKey = PLMakeString("XLFD");
582 /* retrieve a complete listing of the available fonts */
583 fontList = XListFonts(scr->display, ALL_FONTS_MASK, MAX_FONTS_TO_RETRIEVE,
584 &count);
585 if (!fontList) {
586 wwarning("could not retrieve font list");
587 return NULL;
590 fdb = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
592 for (i=0; i<count; i++) {
593 if (!isXLFD(fontList[i], &font_name_length)) {
594 continue;
596 /* the XLFD specs limit the size of a font description in 255 chars */
597 assert(font_name_length < 256);
599 if (parseFont(fontList[i], fields)) {
600 family = PLMakeString(fields[FAMILY]);
601 font = PLGetDictionaryEntry(fdb, family);
602 if (font) {
603 foundry = PLGetDictionaryEntry(font, foundryKey);
604 if (strcmp(PLGetString(foundry), fields[FOUNDRY])==0) {
605 /* already a font with the same family */
606 addTypefaceToFont(font, fields);
607 } else {
608 /* same font family by different foundries */
609 sprintf(buffer, "%s (%s)", fields[FAMILY],
610 fields[FOUNDRY]);
611 PLRelease(family);
612 family = PLMakeString(buffer);
614 font = PLGetDictionaryEntry(fdb, family);
615 if (font) {
616 /* already a font with the same family */
617 addTypefaceToFont(font, fields);
618 } else {
619 tmp = makeFontEntry(fields);
620 PLInsertDictionaryEntry(fdb, family, tmp);
621 PLRelease(tmp);
624 } else {
625 tmp = makeFontEntry(fields);
626 PLInsertDictionaryEntry(fdb, family, tmp);
627 PLRelease(tmp);
629 PLRelease(family);
632 XFreeFontNames(fontList);
634 return fdb;
642 static void
643 listFamilies(proplist_t fdb, WMList *list)
645 proplist_t arr;
646 proplist_t fam;
647 int i;
649 arr = PLGetAllDictionaryKeys(fdb);
650 for (i = 0; i<PLGetNumberOfElements(arr); i++) {
651 fam = PLGetArrayElement(arr, i);
652 WMAddSortedListItem(list, PLGetString(fam));