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
35 static const uint32 kMsgLossless = 'losl';
36 static const uint32 kMsgPixelFormat = 'pfmt';
37 static const uint32 kMsgQuality = 'qlty';
38 static const uint32 kMsgSpeed = 'sped';
39 static const uint32 kMsgTilesHorizontal = 'tilh';
40 static const uint32 kMsgTilesVertical = 'tilv';
41
42
ConfigView(TranslatorSettings * settings)43 ConfigView::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
~ConfigView()177 ConfigView::~ConfigView()
178 {
179 fSettings->Release();
180 }
181
182
183 void
AttachedToWindow()184 ConfigView::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
201 void
MessageReceived(BMessage * message)202 ConfigView::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