1/*
2 * Copyright 2021, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Emmanuel Gil Peyrot
7 */
8
9
10#include "ConfigView.h"
11
12#include <stdio.h>
13#include <string.h>
14
15#include <Catalog.h>
16#include <CheckBox.h>
17#include <LayoutBuilder.h>
18#include <MenuField.h>
19#include <MenuItem.h>
20#include <Message.h>
21#include <PopUpMenu.h>
22#include <Slider.h>
23#include <StringView.h>
24
25#include "avif/avif.h"
26
27#include "TranslatorSettings.h"
28#include "AVIFTranslator.h"
29
30
31#undef B_TRANSLATION_CONTEXT
32#define B_TRANSLATION_CONTEXT "ConfigView"
33
34
35static const uint32 kMsgLossless = 'losl';
36static const uint32 kMsgPixelFormat = 'pfmt';
37static const uint32 kMsgQuality	= 'qlty';
38static const uint32 kMsgSpeed = 'sped';
39static const uint32 kMsgTilesHorizontal = 'tilh';
40static const uint32 kMsgTilesVertical = 'tilv';
41
42
43ConfigView::ConfigView(TranslatorSettings* settings)
44	:
45	BGroupView(B_TRANSLATE("AVIFTranslator Settings"), B_VERTICAL),
46	fSettings(settings)
47{
48	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
49
50	BStringView* title = new BStringView("title",
51		B_TRANSLATE("AVIF image translator"));
52	title->SetFont(be_bold_font);
53
54	char versionString[256];
55	sprintf(versionString, "v%d.%d.%d, %s",
56		static_cast<int>(B_TRANSLATION_MAJOR_VERSION(AVIF_TRANSLATOR_VERSION)),
57		static_cast<int>(B_TRANSLATION_MINOR_VERSION(AVIF_TRANSLATOR_VERSION)),
58		static_cast<int>(B_TRANSLATION_REVISION_VERSION(
59			AVIF_TRANSLATOR_VERSION)),
60		__DATE__);
61
62	BStringView* version = new BStringView("version", versionString);
63
64	BString copyrightsText;
65	BStringView *copyrightView = new BStringView("Copyright",
66		B_TRANSLATE(B_UTF8_COPYRIGHT "2021 Emmanuel Gil Peyrot"));
67
68	BString libavifInfo = B_TRANSLATE(
69		"Based on libavif %version%");
70	libavifInfo.ReplaceAll("%version%", avifVersion());
71
72	BStringView *copyright2View = new BStringView("Copyright2",
73		libavifInfo.String());
74	BStringView *copyright3View = new BStringView("Copyright3",
75		B_TRANSLATE(B_UTF8_COPYRIGHT "2019 Joe Drago. All rights reserved."));
76
77	// output parameters
78
79	fLosslessCheckBox = new BCheckBox("lossless",
80		B_TRANSLATE("Lossless"), new BMessage(kMsgLossless));
81	bool lossless;
82	fSettings->SetGetBool(AVIF_SETTING_LOSSLESS, &lossless);
83	if (lossless)
84		fLosslessCheckBox->SetValue(B_CONTROL_ON);
85
86	fPixelFormatMenu = new BPopUpMenu(B_TRANSLATE("Pixel format"));
87
88	static const avifPixelFormat pixelFormats[4] = {
89		AVIF_PIXEL_FORMAT_YUV444,
90		AVIF_PIXEL_FORMAT_YUV420,
91		AVIF_PIXEL_FORMAT_YUV400,
92		AVIF_PIXEL_FORMAT_YUV422,
93	};
94	for (size_t i = 0; i < 4; ++i) {
95		BMessage* msg = new BMessage(kMsgPixelFormat);
96		msg->AddInt32("value", pixelFormats[i]);
97
98		BMenuItem* item = new BMenuItem(
99			avifPixelFormatToString(pixelFormats[i]), msg);
100		if (fSettings->SetGetInt32(AVIF_SETTING_PIXEL_FORMAT) == pixelFormats[i])
101			item->SetMarked(true);
102		fPixelFormatMenu->AddItem(item);
103	}
104
105	BMenuField* pixelFormatField = new BMenuField(B_TRANSLATE("Pixel format:"),
106		fPixelFormatMenu);
107
108	rgb_color barColor = { 0, 0, 229, 255 };
109
110	fQualitySlider = new BSlider("quality", B_TRANSLATE("Output quality:"),
111		new BMessage(kMsgQuality), AVIF_QUANTIZER_BEST_QUALITY,
112		AVIF_QUANTIZER_WORST_QUALITY, B_HORIZONTAL, B_BLOCK_THUMB);
113	fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
114	fQualitySlider->SetHashMarkCount(8);
115	fQualitySlider->SetLimitLabels(B_TRANSLATE("Best"), B_TRANSLATE("Worst"));
116	fQualitySlider->UseFillColor(true, &barColor);
117	fQualitySlider->SetValue(fSettings->SetGetInt32(AVIF_SETTING_QUALITY));
118	fQualitySlider->SetEnabled(!lossless);
119
120	fSpeedSlider = new BSlider("speed", B_TRANSLATE("Compression speed:"),
121		new BMessage(kMsgSpeed), AVIF_SPEED_SLOWEST,
122		AVIF_SPEED_FASTEST, B_HORIZONTAL, B_BLOCK_THUMB);
123	fSpeedSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
124	fSpeedSlider->SetHashMarkCount(11);
125	fSpeedSlider->SetLimitLabels(B_TRANSLATE("Slow"),
126		B_TRANSLATE("Faster but worse quality"));
127	fSpeedSlider->UseFillColor(true, &barColor);
128	fSpeedSlider->SetValue(fSettings->SetGetInt32(AVIF_SETTING_SPEED));
129
130	fHTilesSlider = new BSlider("htiles", B_TRANSLATE("Horizontal tiles:"),
131		new BMessage(kMsgTilesHorizontal), 1, 6, B_HORIZONTAL,
132		B_BLOCK_THUMB);
133	fHTilesSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
134	fHTilesSlider->SetHashMarkCount(6);
135	fHTilesSlider->SetLimitLabels(B_TRANSLATE("1"),
136		B_TRANSLATE("2���"));
137	fHTilesSlider->UseFillColor(true, &barColor);
138	fHTilesSlider->SetValue(
139		fSettings->SetGetInt32(AVIF_SETTING_TILES_HORIZONTAL));
140
141	fVTilesSlider = new BSlider("vtiles", B_TRANSLATE("Vertical tiles:"),
142		new BMessage(kMsgTilesVertical), 1, 6, B_HORIZONTAL,
143		B_BLOCK_THUMB);
144	fVTilesSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
145	fVTilesSlider->SetHashMarkCount(6);
146	fVTilesSlider->SetLimitLabels(B_TRANSLATE("1"),
147		B_TRANSLATE("2���"));
148	fVTilesSlider->UseFillColor(true, &barColor);
149	fVTilesSlider->SetValue(
150		fSettings->SetGetInt32(AVIF_SETTING_TILES_VERTICAL));
151
152	// Build the layout
153	BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
154		.SetInsets(B_USE_DEFAULT_SPACING)
155		.Add(title)
156		.Add(version)
157		.Add(copyrightView)
158		.AddGlue()
159		.Add(fLosslessCheckBox)
160		.AddGrid(B_USE_DEFAULT_SPACING, B_USE_SMALL_SPACING)
161		        .Add(pixelFormatField->CreateLabelLayoutItem(), 0, 0)
162			.AddGroup(B_HORIZONTAL, 0.0f, 1, 0)
163				.Add(pixelFormatField->CreateMenuBarLayoutItem(), 0.0f)
164				.AddGlue()
165				.End()
166			.End()
167		.Add(fQualitySlider)
168		.Add(fSpeedSlider)
169		.Add(fHTilesSlider)
170		.Add(fVTilesSlider)
171		.AddGlue()
172		.Add(copyright2View)
173		.Add(copyright3View);
174}
175
176
177ConfigView::~ConfigView()
178{
179	fSettings->Release();
180}
181
182
183void
184ConfigView::AttachedToWindow()
185{
186	BGroupView::AttachedToWindow();
187
188	fQualitySlider->SetTarget(this);
189	fSpeedSlider->SetTarget(this);
190	fHTilesSlider->SetTarget(this);
191	fVTilesSlider->SetTarget(this);
192
193	if (Parent() == NULL && Window()->GetLayout() == NULL) {
194		Window()->SetLayout(new BGroupLayout(B_VERTICAL));
195		Window()->ResizeTo(PreferredSize().Width(),
196			PreferredSize().Height());
197	}
198}
199
200
201void
202ConfigView::MessageReceived(BMessage* message)
203{
204	struct {
205		const char*		name;
206		uint32			what;
207		TranSettingType	type;
208	} maps[] = {
209		{ AVIF_SETTING_LOSSLESS, kMsgLossless, TRAN_SETTING_BOOL },
210		{ AVIF_SETTING_PIXEL_FORMAT, kMsgPixelFormat,
211			TRAN_SETTING_INT32 },
212		{ AVIF_SETTING_QUALITY, kMsgQuality, TRAN_SETTING_INT32 },
213		{ AVIF_SETTING_SPEED, kMsgSpeed, TRAN_SETTING_INT32 },
214		{ AVIF_SETTING_TILES_HORIZONTAL, kMsgTilesHorizontal,
215			TRAN_SETTING_INT32 },
216		{ AVIF_SETTING_TILES_VERTICAL, kMsgTilesVertical,
217			TRAN_SETTING_INT32 },
218		{ NULL }
219	};
220
221	int i;
222	for (i = 0; maps[i].name != NULL; i++) {
223		if (maps[i].what == message->what)
224			break;
225	}
226
227	if (maps[i].name == NULL) {
228		BGroupView::MessageReceived(message);
229		return;
230	}
231
232	int32 value;
233	if (message->FindInt32("value", &value) == B_OK
234		|| message->FindInt32("be:value", &value) == B_OK) {
235		switch(maps[i].type) {
236			case TRAN_SETTING_BOOL:
237			{
238				bool boolValue = value;
239				fSettings->SetGetBool(maps[i].name, &boolValue);
240				if (maps[i].what == kMsgLossless)
241					fSpeedSlider->SetEnabled(!boolValue);
242				break;
243			}
244			case TRAN_SETTING_INT32:
245				fSettings->SetGetInt32(maps[i].name, &value);
246				break;
247		}
248		fSettings->SaveSettings();
249	}
250}
251