2 * Copyright 2016, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
6 * Augustin Cavalier <waddlesplash>
10 #include <AboutWindow.h>
11 #include <Application.h>
15 #include <LayoutBuilder.h>
21 #include "FractalEngine.h"
23 #undef B_TRANSLATION_CONTEXT
24 #define B_TRANSLATION_CONTEXT "MandelbrotWindow"
27 // #pragma mark - FractalView
30 class FractalView
: public BView
{
35 virtual void AttachedToWindow();
36 virtual void FrameResized(float, float);
39 virtual void MouseDown(BPoint where
);
40 virtual void MouseMoved(BPoint where
, uint32 mode
, const BMessage
*);
41 virtual void MouseUp(BPoint where
);
43 virtual void MessageReceived(BMessage
* msg
);
44 virtual void Draw(BRect updateRect
);
48 FractalEngine
* fFractalEngine
;
61 BBitmap
* fDisplayBitmap
;
69 FractalView::FractalView()
71 BView(NULL
, B_WILL_DRAW
| B_FRAME_EVENTS
| B_PULSE_NEEDED
),
81 SetHighColor(make_color(255, 255, 255, 255));
85 FractalView::~FractalView()
88 delete fDisplayBitmap
;
92 void FractalView::ResetPosition()
100 void FractalView::AttachedToWindow()
102 fFractalEngine
= new FractalEngine(this, Window());
103 fFractalEngine
->Run();
104 BMessage
msg(FractalEngine::MSG_RESIZE
);
105 msg
.AddUInt16("width", 641);
106 msg
.AddUInt16("height", 462);
107 fFractalEngine
->PostMessage(&msg
);
112 void FractalView::FrameResized(float, float)
118 void FractalView::Pulse()
122 BMessage
msg(FractalEngine::MSG_RESIZE
);
123 msg
.AddUInt16("width", (uint16
)Frame().Width() + 1);
124 msg
.AddUInt16("height", (uint16
)Frame().Height() + 1);
125 fFractalEngine
->PostMessage(&msg
);
126 // The renderer will create new bitmaps, so we own the bitmap now
128 fSizeChanged
= false;
133 BRect
FractalView::GetDragFrame()
135 BRect dragZone
= BRect(std::min(fSelectStart
.x
, fSelectEnd
.x
),
136 std::min(fSelectStart
.y
, fSelectEnd
.y
),
137 std::max(fSelectStart
.x
, fSelectEnd
.x
),
138 std::max(fSelectStart
.y
, fSelectEnd
.y
)),
140 float width
= dragZone
.Width(),
141 height
= width
* (frame
.Height() / frame
.Width());
143 float x1
= fSelectStart
.x
, y1
= fSelectStart
.y
, x2
, y2
;
144 if (fSelectStart
.x
< fSelectEnd
.x
)
148 if (fSelectStart
.y
< fSelectEnd
.y
)
152 return BRect(x1
, y1
, x2
, y2
);
156 void FractalView::MouseDown(BPoint where
)
159 fSelectStart
= where
;
161 Window()->CurrentMessage()->FindInt32("buttons", (int32
*)&fMouseButtons
);
165 void FractalView::MouseMoved(BPoint where
, uint32 mode
, const BMessage
*)
174 void FractalView::MouseUp(BPoint where
)
176 BRect frame
= Frame();
178 if (fabs(fSelectStart
.x
- where
.x
) > 4) {
180 BRect dragFrame
= GetDragFrame();
181 BPoint lt
= dragFrame
.LeftTop();
182 float centerX
= lt
.x
+ dragFrame
.Width() / 2,
183 centerY
= lt
.y
+ dragFrame
.Height() / 2;
184 fLocationX
= ((centerX
- frame
.Width() / 2) * fSize
+ fLocationX
);
185 fLocationY
= ((centerY
- frame
.Height() / 2) * -fSize
+ fLocationY
);
187 fSize
= (dragFrame
.Width() * fSize
) / frame
.Width();
189 fLocationX
= ((where
.x
- frame
.Width() / 2) * fSize
+ fLocationX
);
190 fLocationY
= ((where
.y
- frame
.Height() / 2) * -fSize
+ fLocationY
);
191 if (fMouseButtons
& B_PRIMARY_MOUSE_BUTTON
)
200 void FractalView::MessageReceived(BMessage
* msg
)
203 case B_MOUSE_WHEEL_CHANGED
: {
204 float change
= msg
->FindFloat("be:wheel_delta_y");
206 GetMouse(&where
, NULL
);
207 BRect frame
= Frame();
208 fLocationX
= ((where
.x
- frame
.Width() / 2) * fSize
+ fLocationX
);
209 fLocationY
= ((where
.y
- frame
.Height() / 2) * -fSize
+ fLocationY
);
218 case FractalEngine::MSG_RENDER_COMPLETE
:
221 delete fDisplayBitmap
;
223 fDisplayBitmap
= NULL
; // In case the following line fails
224 msg
->FindPointer("bitmap", (void**)&fDisplayBitmap
);
229 BView::MessageReceived(msg
);
235 void FractalView::RedrawFractal()
237 BMessage
message(FractalEngine::MSG_RENDER
);
238 message
.AddDouble("locationX", fLocationX
);
239 message
.AddDouble("locationY", fLocationY
);
240 message
.AddDouble("size", fSize
);
241 fFractalEngine
->PostMessage(&message
);
245 void FractalView::Draw(BRect updateRect
)
247 DrawBitmap(fDisplayBitmap
, updateRect
, updateRect
);
250 StrokeRect(GetDragFrame());
255 // #pragma mark - MandelbrotWindow
258 class MandelbrotWindow
: public BWindow
262 MSG_MANDELBROT_SET
= 'MndW',
270 MSG_DEEPFROST_PALETTE
,
273 MSG_MIDNIGHT_PALETTE
,
274 MSG_GRASSLAND_PALETTE
,
275 MSG_LIGHTNING_PALETTE
,
277 MSG_HIGHCONTRAST_PALETTE
,
287 MandelbrotWindow(BRect frame
);
288 ~MandelbrotWindow() {}
290 virtual void MessageReceived(BMessage
* msg
);
291 virtual bool QuitRequested();
294 FractalView
* fFractalView
;
298 MandelbrotWindow::MandelbrotWindow(BRect frame
)
300 BWindow(frame
, B_TRANSLATE_SYSTEM_NAME("Mandelbrot"), B_TITLED_WINDOW_LOOK
,
301 B_NORMAL_WINDOW_FEEL
, 0L),
302 fFractalView(new FractalView
)
304 SetPulseRate(250000); // pulse twice per second
306 BMenuBar
* menuBar
= new BMenuBar("MenuBar");
310 BLayoutBuilder::Menu
<>(menuBar
)
311 .AddMenu(B_TRANSLATE("File"))
312 .AddItem(B_TRANSLATE("About"), B_ABOUT_REQUESTED
)
313 .AddItem(B_TRANSLATE("Quit"), B_QUIT_REQUESTED
, 'Q')
315 .AddMenu(B_TRANSLATE("Set"))
317 .AddItem(B_TRANSLATE("Mandelbrot"), MSG_MANDELBROT_SET
)
318 .AddItem(B_TRANSLATE("Burning Ship"), MSG_BURNINGSHIP_SET
)
319 .AddItem(B_TRANSLATE("Tricorn"), MSG_TRICORN_SET
)
320 .AddItem(B_TRANSLATE("Julia"), MSG_JULIA_SET
)
321 .AddItem(B_TRANSLATE("Orbit Trap"), MSG_ORBITTRAP_SET
)
322 .AddItem(B_TRANSLATE("Multibrot"), MSG_MULTIBROT_SET
)
324 .AddMenu(B_TRANSLATE("Palette"))
325 .GetMenu(paletteMenu
)
326 .AddItem(B_TRANSLATE("Royal"), MSG_ROYAL_PALETTE
)
327 .AddItem(B_TRANSLATE("Deepfrost"), MSG_DEEPFROST_PALETTE
)
328 .AddItem(B_TRANSLATE("Frost"), MSG_FROST_PALETTE
)
329 .AddItem(B_TRANSLATE("Fire"), MSG_FIRE_PALETTE
)
330 .AddItem(B_TRANSLATE("Midnight"), MSG_MIDNIGHT_PALETTE
)
331 .AddItem(B_TRANSLATE("Grassland"), MSG_GRASSLAND_PALETTE
)
332 .AddItem(B_TRANSLATE("Lightning"), MSG_LIGHTNING_PALETTE
)
333 .AddItem(B_TRANSLATE("Spring"), MSG_SPRING_PALETTE
)
334 .AddItem(B_TRANSLATE("High contrast"), MSG_HIGHCONTRAST_PALETTE
)
336 .AddMenu(B_TRANSLATE("Iterations"))
338 .AddItem("128", MSG_ITER_128
)
339 .AddItem("512", MSG_ITER_512
)
340 .AddItem("1024", MSG_ITER_1024
)
341 .AddItem("4096", MSG_ITER_4096
)
342 .AddItem("8192", MSG_ITER_8192
)
343 .AddItem("12288", MSG_ITER_12288
)
344 .AddItem("16384", MSG_ITER_16384
)
347 setMenu
->SetRadioMode(true);
348 setMenu
->FindItem(MSG_MANDELBROT_SET
)->SetMarked(true);
349 paletteMenu
->SetRadioMode(true);
350 paletteMenu
->FindItem(MSG_ROYAL_PALETTE
)->SetMarked(true);
351 iterMenu
->SetRadioMode(true);
352 iterMenu
->FindItem(MSG_ITER_1024
)->SetMarked(true);
354 BLayoutBuilder::Group
<>(this, B_VERTICAL
, 0)
362 #define HANDLE_SET(uiwhat, id) \
364 BMessage msg(FractalEngine::MSG_CHANGE_SET); \
365 msg.AddUInt8("set", id); \
366 fFractalView->fFractalEngine->PostMessage(&msg); \
367 fFractalView->ResetPosition(); \
368 fFractalView->RedrawFractal(); \
371 #define HANDLE_PALETTE(uiwhat, id) \
373 BMessage msg(FractalEngine::MSG_SET_PALETTE); \
374 msg.AddUInt8("palette", id); \
375 fFractalView->fFractalEngine->PostMessage(&msg); \
376 fFractalView->RedrawFractal(); \
379 #define HANDLE_ITER(uiwhat, id) \
381 BMessage msg(FractalEngine::MSG_SET_ITERATIONS); \
382 msg.AddUInt16("iterations", id); \
383 fFractalView->fFractalEngine->PostMessage(&msg); \
384 fFractalView->RedrawFractal(); \
388 MandelbrotWindow::MessageReceived(BMessage
* msg
)
391 HANDLE_SET(MSG_MANDELBROT_SET
, 0)
392 HANDLE_SET(MSG_BURNINGSHIP_SET
, 1)
393 HANDLE_SET(MSG_TRICORN_SET
, 2)
394 HANDLE_SET(MSG_JULIA_SET
, 3)
395 HANDLE_SET(MSG_ORBITTRAP_SET
, 4)
396 HANDLE_SET(MSG_MULTIBROT_SET
, 5)
398 HANDLE_PALETTE(MSG_ROYAL_PALETTE
, 0)
399 HANDLE_PALETTE(MSG_DEEPFROST_PALETTE
, 1)
400 HANDLE_PALETTE(MSG_FROST_PALETTE
, 2)
401 HANDLE_PALETTE(MSG_FIRE_PALETTE
, 3)
402 HANDLE_PALETTE(MSG_MIDNIGHT_PALETTE
, 4)
403 HANDLE_PALETTE(MSG_GRASSLAND_PALETTE
, 5)
404 HANDLE_PALETTE(MSG_LIGHTNING_PALETTE
, 6)
405 HANDLE_PALETTE(MSG_SPRING_PALETTE
, 7)
406 HANDLE_PALETTE(MSG_HIGHCONTRAST_PALETTE
, 8)
408 HANDLE_ITER(MSG_ITER_128
, 128)
409 HANDLE_ITER(MSG_ITER_512
, 512)
410 HANDLE_ITER(MSG_ITER_1024
, 1024)
411 HANDLE_ITER(MSG_ITER_4096
, 4096)
412 HANDLE_ITER(MSG_ITER_8192
, 8192)
413 HANDLE_ITER(MSG_ITER_12288
, 12288)
414 HANDLE_ITER(MSG_ITER_16384
, 16384)
416 case B_ABOUT_REQUESTED
: {
417 BAboutWindow
* wind
= new BAboutWindow("Mandelbrot", "application/x-vnd.Haiku-Mandelbrot");
418 const char* authors
[] = {
419 "Augustin Cavalier <waddlesplash>",
420 B_TRANSLATE("kerwizzy (original FractalEngine author)"),
423 wind
->AddCopyright(2016, "Haiku, Inc.");
424 wind
->AddAuthors(authors
);
430 BWindow::MessageReceived(msg
);
435 #undef HANDLE_PALETTE
440 MandelbrotWindow::QuitRequested()
442 if (BWindow::QuitRequested()) {
443 be_app
->PostMessage(B_QUIT_REQUESTED
);
450 // #pragma mark - MandelbrotApp
453 class MandelbrotApp
: public BApplication
457 : BApplication("application/x-vnd.Haiku-Mandelbrot") {}
460 bool QuitRequested() { return true; }
465 MandelbrotApp::ReadyToRun()
467 MandelbrotWindow
* wind
= new MandelbrotWindow(BRect(0, 0, 640, 480));
468 wind
->CenterOnScreen();
474 main(int argc
, char* argv
[])
476 MandelbrotApp().Run();