1/*
2
3PDF Writer printer driver.
4
5Copyright (c) 2002 OpenBeOS.
6
7Authors:
8	Philippe Houdoin
9	Simon Gauvin
10	Michael Pfeiffer
11
12Permission is hereby granted, free of charge, to any person obtaining a copy of
13this software and associated documentation files (the "Software"), to deal in
14the Software without restriction, including without limitation the rights to
15use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
16of the Software, and to permit persons to whom the Software is furnished to do
17so, subject to the following conditions:
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28THE SOFTWARE.
29
30*/
31
32#include <InterfaceKit.h>
33#include <SupportKit.h>
34#include "BlockingWindow.h"
35#include "FontsWindow.h"
36#include "Fonts.h"
37
38
39class CJKFontItem : public BStringItem
40{
41	font_encoding fEncoding;
42	bool          fActive;
43
44public:
45	CJKFontItem(const char* label, font_encoding encoding, bool active = true);
46	void SetActive(bool active) { fActive = active; }
47	void DrawItem(BView* owner, BRect rect, bool drawEverything);
48
49	bool          Active() const   { return fActive; }
50	font_encoding Encoding() const { return fEncoding; }
51};
52
53CJKFontItem::CJKFontItem(const char* label, font_encoding encoding, bool active)
54	: BStringItem(label)
55	, fEncoding(encoding)
56	, fActive(active)
57{
58}
59
60void
61CJKFontItem::DrawItem(BView* owner, BRect rect, bool drawEverything)
62{
63	BStringItem::DrawItem(owner, rect, drawEverything);
64	if (!fActive) {
65		owner->SetHighColor(0, 0, 0, 0);
66		float y = (rect.top + rect.bottom) / 2;
67		owner->StrokeLine(BPoint(rect.left, y), BPoint(rect.right, y));
68	}
69}
70
71static const char* FontName(font_encoding enc) {
72	switch(enc) {
73		case japanese_encoding:     return "Japanese";
74		case chinese_cns1_encoding: return "Traditional Chinese";
75		case chinese_gb1_encoding:  return "Simplified Chinese";
76		case korean_encoding:       return "Korean";
77		default:                    return "invalid font encoding!";
78	}
79}
80
81
82// #pragma mark -- of DragListView
83
84
85DragListView::DragListView(BRect frame, const char *name,
86		list_view_type type,
87		uint32 resizingMode, uint32 flags)
88	: BListView(frame, name, type, resizingMode, flags)
89{
90}
91
92
93bool
94DragListView::InitiateDrag(BPoint point, int32 index, bool wasSelected)
95{
96	BMessage m;
97	DragMessage(&m, ItemFrame(index), this);
98	return true;
99}
100
101
102/**
103 * Constuctor
104 *
105 * @param
106 * @return
107 */
108FontsWindow::FontsWindow(Fonts *fonts)
109	:	HWindow(BRect(0,0,400,220), "Fonts", B_TITLED_WINDOW_LOOK,
110 			B_MODAL_APP_WINDOW_FEEL, B_NOT_RESIZABLE | B_NOT_MINIMIZABLE |
111 			B_NOT_ZOOMABLE | B_CLOSE_ON_ESCAPE)
112{
113	// ---- Ok, build a default page setup user interface
114	BRect		r, r1;
115	BView		*panel;
116	BButton		*button;
117	float		x, y, w, h;
118	BString 	setting_value;
119	BTabView    *tabView;
120	BTab        *tab;
121
122	AddShortcut('W',B_COMMAND_KEY,new BMessage(B_QUIT_REQUESTED));
123
124	fFonts = fonts;
125
126	r = Bounds();
127	tabView = new BTabView(r, "tab_view");
128
129	// --- Embedding tab ---
130	tab = new BTab();
131
132	// add a *dialog* background
133
134	r.bottom -= tabView->TabHeight();
135	panel = new BView(r, "embedding_panel", B_FOLLOW_ALL,
136					B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP);
137	panel->	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
138
139	r1 = r; r1.OffsetTo(0, 0);
140	// add font list
141#if USE_CLV
142	fList = new BColumnListView(BRect(r.left+5, r.top+5, r.right-5-B_V_SCROLL_BAR_WIDTH, r.bottom-5-B_H_SCROLL_BAR_HEIGHT-30),
143		"fonts_list", B_FOLLOW_ALL, B_WILL_DRAW | B_NAVIGABLE_JUMP);
144	panel->AddChild(fList);
145#else
146	fList = new BListView(BRect(r1.left+5, r1.top+5, r1.right-5-B_V_SCROLL_BAR_WIDTH, r1.bottom-5-B_H_SCROLL_BAR_HEIGHT-30),
147		"fonts_list", B_MULTIPLE_SELECTION_LIST);
148	panel->AddChild(new BScrollView("scroll_list", fList,
149		B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true));
150	fList->SetSelectionMessage(new BMessage(SELECTION_MSG));
151#endif
152	FillFontList();
153
154	// add a "Embed" button, and make it default
155	button 	= new BButton(r1, NULL, "Embed", new BMessage(EMBED_MSG),
156		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
157	button->ResizeToPreferred();
158	button->GetPreferredSize(&w, &h);
159	x = r1.right - w - 8;
160	y = r1.bottom - h - 8;
161	button->MoveTo(x, y);
162	button->SetEnabled(false);
163	panel->AddChild(button);
164	button->MakeDefault(true);
165	fEmbedButton = button;
166
167	// add a "Substitute" button
168	button 	= new BButton(r, NULL, "Substitute", new BMessage(SUBST_MSG),
169		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
170	button->GetPreferredSize(&w, &h);
171	button->ResizeToPreferred();
172	button->MoveTo(x - w - 8, y);
173	button->SetEnabled(false);
174	panel->AddChild(button);
175	fSubstButton = button;
176
177	// add a separator line...
178	BBox * line = new BBox(BRect(r1.left, y - 9, r1.right, y - 8), NULL,
179		B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM );
180	panel->AddChild(line);
181
182	tabView->AddTab(panel, tab);
183	tab->SetLabel("Embedding");
184
185	// --- CJK tab ---
186	tab = new BTab();
187
188	// add a *dialog* background
189	panel = new BView(r, "cjk_panel", B_FOLLOW_ALL,
190					B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP);
191	panel->	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
192
193	BListView* list =
194		new DragListView(BRect(r1.left+5, r1.top+5, r1.right-5-B_V_SCROLL_BAR_WIDTH, r1.bottom-5-B_H_SCROLL_BAR_HEIGHT-30),
195		"cjk", B_MULTIPLE_SELECTION_LIST);
196	panel->AddChild(new BScrollView("cjk_scroll_list", list,
197		B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true));
198
199	font_encoding enc; bool active;
200	for (int i = 0; fFonts->GetCJKOrder(i, enc, active); i++) {
201		list->AddItem(new CJKFontItem(FontName(enc), enc, active));
202	}
203	list->SetSelectionMessage(new BMessage(CJK_SELECTION_MSG));
204	fCJKList = list;
205
206	// add a "Embed" button
207	button 	= new BButton(r, NULL, "Enable", new BMessage(ENABLE_MSG),
208		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
209	button->ResizeToPreferred();
210	button->GetPreferredSize(&w, &h);
211	x = r1.right - w - 8;
212	y = r1.bottom - h - 8;
213	button->MoveTo(x, y);
214	button->SetEnabled(false);
215	panel->AddChild(button);
216	fEnableButton = button;
217
218	// add a "Disable" button
219	button 	= new BButton(r, NULL, "Disable", new BMessage(DISABLE_MSG),
220		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
221	button->GetPreferredSize(&w, &h);
222	button->ResizeToPreferred();
223	x -= w + 8;
224	button->MoveTo(x, y);
225	button->SetEnabled(false);
226	panel->AddChild(button);
227	fDisableButton = button;
228
229	// add a "Down" button
230	button 	= new BButton(r, NULL, "Down", new BMessage(DOWN_MSG),
231		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
232	button->GetPreferredSize(&w, &h);
233	button->ResizeToPreferred();
234	x -= w + 8;
235	button->MoveTo(x, y);
236	button->SetEnabled(false);
237	panel->AddChild(button);
238	fDownButton = button;
239
240	// add a "Up" button
241	button 	= new BButton(r, NULL, "Up", new BMessage(UP_MSG),
242		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
243	button->GetPreferredSize(&w, &h);
244	button->ResizeToPreferred();
245	x -= w + 8;
246	button->MoveTo(x, y);
247	button->SetEnabled(false);
248	panel->AddChild(button);
249	fUpButton = button;
250
251	// add a separator line...
252	line = new BBox(BRect(r1.left, y - 9, r1.right, y - 8), NULL,
253		B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM );
254	panel->AddChild(line);
255
256
257	tabView->AddTab(panel, tab);
258	tab->SetLabel("CJK");
259
260	// add the tabView to the window
261	AddChild(tabView);
262
263	MoveTo(320, 320);
264}
265
266
267// --------------------------------------------------
268FontsWindow::~FontsWindow()
269{
270}
271
272
273// --------------------------------------------------
274bool
275FontsWindow::QuitRequested()
276{
277	return true;
278}
279
280
281// --------------------------------------------------
282void
283FontsWindow::Quit()
284{
285	inherited::Quit();
286}
287
288
289class ListIterator
290{
291	virtual bool DoItem(BListItem* item) = 0;
292public:
293	static bool DoIt(BListItem* item, void* data);
294	virtual ~ListIterator() {}
295};
296
297
298bool
299ListIterator::DoIt(BListItem* item, void* data)
300{
301	if (item->IsSelected()) {
302		ListIterator* e = (ListIterator*)data;
303		return e->DoItem(item);
304	}
305	return false;
306}
307
308class CountItems : public ListIterator
309{
310	BListView* fList;
311	Fonts*     fFonts;
312	int        fNumEmbed;
313	int        fNumSubst;
314
315	bool DoItem(BListItem* item);
316
317public:
318	CountItems(BListView* list, Fonts* fonts);
319	int GetNumEmbed() { return fNumEmbed; }
320	int GetNumSubst() { return fNumSubst; }
321};
322
323CountItems::CountItems(BListView* list, Fonts* fonts)
324	: fList(list)
325	, fFonts(fonts)
326	, fNumEmbed(0)
327	, fNumSubst(0)
328{ }
329
330bool CountItems::DoItem(BListItem* item)
331{
332	int32 i = fList->IndexOf(item);
333	if (0 <= i && i < fFonts->Length()) {
334		if (fFonts->At(i)->Embed()) {
335			fNumEmbed ++;
336		} else {
337			fNumSubst ++;
338		}
339	}
340	return false;
341}
342
343class EmbedFont : public ListIterator
344{
345	FontsWindow* fWindow;
346	BListView*   fList;
347	Fonts*       fFonts;
348	bool         fEmbed;
349
350	bool DoItem(BListItem* item);
351public:
352	EmbedFont(FontsWindow* window, BListView* list, Fonts* fonts, bool embed);
353};
354
355EmbedFont::EmbedFont(FontsWindow* window, BListView* list, Fonts* fonts, bool embed)
356	: fWindow(window)
357	, fList(list)
358	, fFonts(fonts)
359	, fEmbed(embed)
360{
361}
362
363bool
364EmbedFont::DoItem(BListItem* item)
365{
366	int32 i = fList->IndexOf(item);
367	if (0 <= i && i < fFonts->Length()) {
368		fFonts->At(i)->SetEmbed(fEmbed);
369		fWindow->SetItemText((BStringItem*)item, fFonts->At(i));
370	}
371	return false;
372}
373
374// move selected item in list one position up or down
375void
376FontsWindow::MoveItemInList(BListView* list, bool up)
377{
378	int32 from = list->CurrentSelection(0);
379	if (from >= 0) {
380		int32 to;
381		if (up) {
382			if (from == 0) return; // at top of list
383			to = from - 1;
384		} else {
385			if (from == list->CountItems() -1) return; // at bottom of list
386			to = from + 1;
387		}
388		list->SwapItems(from, to);
389
390		font_encoding enc;
391		bool          active;
392		fFonts->GetCJKOrder(from, enc, active);
393
394		font_encoding enc1;
395		bool          active1;
396		fFonts->GetCJKOrder(to, enc1, active1);
397		fFonts->SetCJKOrder(to, enc,  active);
398		fFonts->SetCJKOrder(from, enc1, active1);
399	}
400}
401
402
403void
404FontsWindow::EnableItemInList(BListView* list, bool enable)
405{
406	int32 i = list->CurrentSelection(0);
407	if (i >= 0) {
408		BListItem* item0 = list->ItemAt(i);
409		CJKFontItem* item = dynamic_cast<CJKFontItem*>(item0);
410		if (item) {
411			item->SetActive(enable);
412			list->Invalidate();
413			font_encoding enc;
414			bool          active;
415			fFonts->GetCJKOrder(i, enc, active);
416			fFonts->SetCJKOrder(i, enc, enable);
417		}
418	}
419}
420
421// --------------------------------------------------
422void
423FontsWindow::MessageReceived(BMessage *msg)
424{
425	switch (msg->what){
426		case OK_MSG: Quit();
427			break;
428
429		case CANCEL_MSG: Quit();
430			break;
431
432		case EMBED_MSG:
433			{
434			#if USE_CLV
435			#else
436			EmbedFont e(this, fList, fFonts, true);
437			fList->DoForEach(EmbedFont::DoIt, (void*)&e);
438			}
439			PostMessage(SELECTION_MSG);
440			fList->Invalidate();
441			#endif
442			break;
443
444		case SUBST_MSG:
445			{
446			#if USE_CLV
447			#else
448			EmbedFont e(this, fList, fFonts, false);
449			fList->DoForEach(EmbedFont::DoIt, (void*)&e);
450			}
451			PostMessage(SELECTION_MSG);
452			fList->Invalidate();
453			#endif
454			break;
455
456		case SELECTION_MSG:
457			{
458				CountItems count(fList, fFonts);
459				fList->DoForEach(CountItems::DoIt, (void*)&count);
460				fEmbedButton->SetEnabled(count.GetNumSubst() > 0);
461				fSubstButton->SetEnabled(count.GetNumEmbed() > 0);
462			}
463			break;
464
465		case UP_MSG:
466		case DOWN_MSG:
467			MoveItemInList(fCJKList, msg->what == UP_MSG);
468			PostMessage(CJK_SELECTION_MSG);
469			break;
470
471		case ENABLE_MSG:
472		case DISABLE_MSG:
473			EnableItemInList(fCJKList, msg->what == ENABLE_MSG);
474			PostMessage(CJK_SELECTION_MSG);
475			break;
476
477		case CJK_SELECTION_MSG:
478			{
479				int32 i = fCJKList->CurrentSelection(0);
480				if (i >= 0) {
481					BListItem* item0 = fCJKList->ItemAt(i);
482					CJKFontItem* item = dynamic_cast<CJKFontItem*>(item0);
483					if (item) {
484						fUpButton->SetEnabled(i != 0);
485						fDownButton->SetEnabled(i != fCJKList->CountItems()-1);
486						fEnableButton->SetEnabled(!item->Active());
487						fDisableButton->SetEnabled(item->Active());
488					}
489				}
490			}
491			break;
492
493		default:
494			inherited::MessageReceived(msg);
495			break;
496	}
497}
498
499void
500FontsWindow::SetItemText(BStringItem* i, FontFile* f)
501{
502	const int64 KB = 1024;
503	const int64 MB = KB * KB;
504	char buffer[40];
505	BString s;
506	s << f->Name() << ": ";
507	if (f->Type() == true_type_type) s << "TrueType";
508	else s << "Type 1";
509	s << " (";
510	if (f->Size() >= MB) {
511		sprintf(buffer, "%d MB", (int)(f->Size()/MB));
512	} else if (f->Size() >= KB) {
513		sprintf(buffer, "%d KB", (int)(f->Size()/KB));
514	} else {
515		sprintf(buffer, "%d B", (int)(f->Size()));
516	}
517	s << buffer;
518	s << ") ";
519	s << (f->Embed() ? "embed" : "substitute");
520	i->SetText(s.String());
521}
522
523void
524FontsWindow::FillFontList()
525{
526	const int n = fFonts->Length();
527	for (int i = 0; i < n; i++) {
528#if USE_CLV
529#else
530		BStringItem* s;
531		FontFile* f = fFonts->At(i);
532		fList->AddItem(s = new BStringItem(""));
533		SetItemText(s, f);
534#endif
535	}
536}
537
538void
539FontsWindow::EmptyFontList()
540{
541#if USE_CLV
542#else
543	const int n = fList->CountItems();
544	for (int i = 0; i < n; i++) {
545		BListItem* item = fList->ItemAt(i);
546		delete item;
547	}
548	fList->MakeEmpty();
549#endif
550}
551