8 #include <Application.h>
12 #include <MessageRunner.h>
13 #include <Messenger.h>
26 // random_number_between
28 random_number_between(float v1
, float v2
)
31 return v1
+ fmod(rand() / 1000.0, (v2
- v1
));
33 return v2
+ fmod(rand() / 1000.0, (v1
- v2
));
38 class TestView
: public BView
{
41 TestView(BRect frame
, const char* name
,
42 uint32 resizeFlags
, uint32 flags
);
44 virtual void AttachedToWindow();
45 virtual void MessageReceived(BMessage
* message
);
47 virtual void Draw(BRect updateRect
);
49 virtual void MouseDown(BPoint where
);
50 virtual void MouseUp(BPoint where
);
51 virtual void MouseMoved(BPoint where
, uint32 transit
,
52 const BMessage
* dragMessage
);
56 void _InvalidateBitmapRect(BRect r
);
57 void _DrawCross(BPoint where
, rgb_color c
);
72 void _FillBitmap(point
* polygon
);
73 void _InitPolygon(const BRect
& b
, point
* polygon
) const;
74 void _InitColor(color_cycle
* color
) const;
75 void _MorphPolygon(const BRect
& b
, point
* polygon
);
76 void _MorphColor(color_cycle
* color
);
79 BView
* fOffscreenView
;
80 BMessageRunner
* fTicker
;
94 TRACKING_RIGHT_BOTTOM
,
100 BPoint fLastMousePos
;
103 color_cycle fColor
[3];
107 TestView::TestView(BRect frame
, const char* name
,
108 uint32 resizeFlags
, uint32 flags
)
109 : BView(frame
, name
, resizeFlags
, flags
),
110 // fBitmap(new BBitmap(BRect(0, 0, kBitmapWidth - 1, kBitmapHeight -1), 0, kBitmapFormat)),
111 // fBitmap(new BBitmap(BRect(0, 0, 32 - 1, 8 - 1), 0, B_CMAP8)),
112 // fBitmap(new BBitmap(BRect(0, 0, 32 - 1, 8 - 1), 0, B_GRAY8)),
113 fBitmap(new BBitmap(BRect(0, 0, 199, 99), B_RGB32
, true)),
114 // fBitmap(new BBitmap(BRect(0, 0, 639, 479), B_RGB32, true)),
115 // fBitmap(new BBitmap(BRect(0, 0, 639, 479), B_CMAP8, true)),
116 // fBitmap(new BBitmap(BRect(0, 0, 199, 99), B_CMAP8, true)),
117 // fBitmap(new BBitmap(BRect(0, 0, 199, 99), B_GRAY8, true)),
118 fOffscreenView(new BView(fBitmap
->Bounds(), "Offscreen view",
119 B_FOLLOW_ALL
, B_WILL_DRAW
| B_SUBPIXEL_PRECISE
)),
122 fTracking(TRACKING_NONE
),
123 fLastMousePos(-1.0, -1.0)
125 SetViewColor(B_TRANSPARENT_COLOR
);
126 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR
));
127 // uint32 size = min_c((uint32)fBitmap->BitsLength(), sizeof(kBitmapBits));
128 // memcpy(fBitmap->Bits(), kBitmapBits, size);
129 /* uint8* bits = (uint8*)fBitmap->Bits();
130 uint32 width = fBitmap->Bounds().IntegerWidth() + 1;
131 uint32 height = fBitmap->Bounds().IntegerHeight() + 1;
132 uint32 bpr = fBitmap->BytesPerRow();
133 printf("width: %ld, height: %ld, bpr: %ld\n", width, height, bpr);
135 for (uint32 y = 0; y < height; y++) {
137 for (uint32 x = 0; x < width; x++) {
143 BRect a(0.0, 10.0, 20.0, 10.0);
144 BRect b(0.0, 10.0, 10.0, 30.0);
145 printf("Intersects: %d\n", a.Intersects(b));*/
146 if (fBitmap
->Lock()) {
147 fBitmap
->AddChild(fOffscreenView
);
148 fOffscreenView
->SetBlendingMode(B_CONSTANT_ALPHA
, B_ALPHA_COMPOSITE
);
152 srand((long int)system_time());
153 _InitPolygon(fBitmap
->Bounds(), fPolygon
);
161 TestView::AttachedToWindow()
163 BMessenger
mess(this, Window());
164 BMessage
msg(MSG_TICK
);
165 fTicker
= new BMessageRunner(mess
, &msg
, 40000LL);
170 TestView::MessageReceived(BMessage
* message
)
172 switch (message
->what
) {
174 BRect old
= fBitmapRect
;
176 _InvalidateBitmapRect(old
| fBitmapRect
);
180 _MorphPolygon(fBitmap
->Bounds(), fPolygon
);
182 _FillBitmap(fPolygon
);
183 Invalidate(fBitmapRect
);
186 BView::MessageReceived(message
);
193 TestView::Draw(BRect updateRect
)
195 SetDrawingMode(B_OP_ALPHA
);
196 DrawBitmap(fBitmap
, fBitmap
->Bounds(), fBitmapRect
);
198 SetDrawingMode(B_OP_COPY
);
199 // background arround bitmap
200 BRect
topOfBitmap(updateRect
.left
, updateRect
.top
, updateRect
.right
, fBitmapRect
.top
- 1);
201 if (topOfBitmap
.IsValid())
202 FillRect(topOfBitmap
, B_SOLID_LOW
);
204 BRect
leftOfBitmap(updateRect
.left
, fBitmapRect
.top
, fBitmapRect
.left
- 1, fBitmapRect
.bottom
);
205 if (leftOfBitmap
.IsValid())
206 FillRect(leftOfBitmap
, B_SOLID_LOW
);
208 BRect
rightOfBitmap(fBitmapRect
.right
+ 1, fBitmapRect
.top
, updateRect
.right
, fBitmapRect
.bottom
);
209 if (rightOfBitmap
.IsValid())
210 FillRect(rightOfBitmap
, B_SOLID_LOW
);
212 BRect
bottomOfBitmap(updateRect
.left
, fBitmapRect
.bottom
+ 1, updateRect
.right
, updateRect
.bottom
);
213 if (bottomOfBitmap
.IsValid())
214 FillRect(bottomOfBitmap
, B_SOLID_LOW
);
216 // indicate the frame to see any errors in the drawing code
217 rgb_color red
= (rgb_color
){ 255, 0, 0, 255 };
218 _DrawCross(fBitmapRect
.LeftTop() + BPoint(-1.0, -1.0), red
);
219 _DrawCross(fBitmapRect
.RightTop() + BPoint(1.0, -1.0), red
);
220 _DrawCross(fBitmapRect
.LeftBottom() + BPoint(-1.0, 1.0), red
);
221 _DrawCross(fBitmapRect
.RightBottom() + BPoint(1.0, 1.0), red
);
224 SetDrawingMode(B_OP_ALPHA
);
225 const char* message
= "Click and drag to move and resize the bitmap!";
226 BPoint
textPos(20.0, 30.0);
227 SetHighColor(255, 255, 255, 180);
228 DrawString(message
, textPos
);
229 SetHighColor(0, 0, 0, 180);
230 DrawString(message
, textPos
+ BPoint(-1.0, -1.0));
235 hit_test(BPoint where
, BPoint p
)
238 r
.InsetBy(-5.0, -5.0);
239 return r
.Contains(where
);
244 hit_test(BPoint where
, BPoint a
, BPoint b
)
248 r
.InsetBy(-3.0, 0.0);
250 r
.InsetBy(0.0, -3.0);
251 return r
.Contains(where
);
256 TestView::MouseDown(BPoint where
)
258 fTracking
= TRACKING_NONE
;
260 // check if we hit a corner
261 if (hit_test(where
, fBitmapRect
.LeftTop()))
262 fTracking
= TRACKING_LEFT_TOP
;
263 else if (hit_test(where
, fBitmapRect
.RightTop()))
264 fTracking
= TRACKING_RIGHT_TOP
;
265 else if (hit_test(where
, fBitmapRect
.LeftBottom()))
266 fTracking
= TRACKING_LEFT_BOTTOM
;
267 else if (hit_test(where
, fBitmapRect
.RightBottom()))
268 fTracking
= TRACKING_RIGHT_BOTTOM
;
269 // check if we hit a side
270 else if (hit_test(where
, fBitmapRect
.LeftTop(), fBitmapRect
.RightTop()))
271 fTracking
= TRACKING_TOP
;
272 else if (hit_test(where
, fBitmapRect
.LeftTop(), fBitmapRect
.LeftBottom()))
273 fTracking
= TRACKING_LEFT
;
274 else if (hit_test(where
, fBitmapRect
.RightTop(), fBitmapRect
.RightBottom()))
275 fTracking
= TRACKING_RIGHT
;
276 else if (hit_test(where
, fBitmapRect
.LeftBottom(), fBitmapRect
.RightBottom()))
277 fTracking
= TRACKING_BOTTOM
;
278 // check if we hit inside the rect
279 else if (fBitmapRect
.Contains(where
))
280 fTracking
= TRACKING_ALL
;
282 fLastMousePos
= where
;
287 TestView::MouseUp(BPoint where
)
289 fTracking
= TRACKING_NONE
;
294 TestView::MouseMoved(BPoint where
, uint32 transit
,
295 const BMessage
* dragMessage
)
297 if (fTracking
> TRACKING_NONE
) {
298 BRect old
= fBitmapRect
;
299 BPoint offset
= where
- fLastMousePos
;
301 case TRACKING_LEFT_TOP
:
302 fBitmapRect
.Set(fBitmapRect
.left
+ offset
.x
,
303 fBitmapRect
.top
+ offset
.y
,
307 case TRACKING_RIGHT_BOTTOM
:
308 fBitmapRect
.Set(fBitmapRect
.left
,
310 fBitmapRect
.right
+ offset
.x
,
311 fBitmapRect
.bottom
+ offset
.y
);
313 case TRACKING_LEFT_BOTTOM
:
314 fBitmapRect
.Set(fBitmapRect
.left
+ offset
.x
,
317 fBitmapRect
.bottom
+ offset
.y
);
319 case TRACKING_RIGHT_TOP
:
320 fBitmapRect
.Set(fBitmapRect
.left
,
321 fBitmapRect
.top
+ offset
.y
,
322 fBitmapRect
.right
+ offset
.x
,
326 fBitmapRect
.Set(fBitmapRect
.left
+ offset
.x
,
332 fBitmapRect
.Set(fBitmapRect
.left
,
333 fBitmapRect
.top
+ offset
.y
,
338 fBitmapRect
.Set(fBitmapRect
.left
,
340 fBitmapRect
.right
+ offset
.x
,
343 case TRACKING_BOTTOM
:
344 fBitmapRect
.Set(fBitmapRect
.left
,
347 fBitmapRect
.bottom
+ offset
.y
);
351 fBitmapRect
.OffsetBy(offset
);
354 fLastMousePos
= where
;
355 if (old
!= fBitmapRect
)
356 _InvalidateBitmapRect(old
| fBitmapRect
);
362 TestView::_ResetRect()
364 fBitmapRect
= fBitmap
->Bounds();
365 fBitmapRect
.OffsetBy(floorf((Bounds().Width() - fBitmapRect
.Width()) / 2.0 + 0.5),
366 floorf((Bounds().Height() - fBitmapRect
.Height()) / 2.0 + 0.5));
369 // _InvalidateBitmapRect
371 TestView::_InvalidateBitmapRect(BRect r
)
373 r
.InsetBy(-4.0, -4.0);
379 TestView::_DrawCross(BPoint where
, rgb_color c
)
382 AddLine(BPoint(where
.x
, where
.y
- 3),
383 BPoint(where
.x
, where
.y
- 1), c
);
384 AddLine(BPoint(where
.x
, where
.y
+ 1),
385 BPoint(where
.x
, where
.y
+ 3), c
);
386 AddLine(BPoint(where
.x
- 3, where
.y
),
387 BPoint(where
.x
- 1, where
.y
), c
);
388 AddLine(BPoint(where
.x
+ 1, where
.y
),
389 BPoint(where
.x
+ 3, where
.y
), c
);
395 TestView::_FillBitmap(point
* polygon
)
397 if (fBitmap
->Lock()) {
398 fOffscreenView
->SetDrawingMode(B_OP_COPY
);
399 fOffscreenView
->SetHighColor(0, 0, 0, 30);
400 fOffscreenView
->FillRect(fOffscreenView
->Bounds());
402 fOffscreenView
->SetDrawingMode(B_OP_ALPHA
);
403 fOffscreenView
->SetHighColor(fColor
[0].value
,
407 fOffscreenView
->SetPenSize(4);
408 fOffscreenView
->SetLineMode(B_BUTT_CAP
, B_ROUND_JOIN
);
411 pointList
[0].x
= polygon
[0].x
;
412 pointList
[0].y
= polygon
[0].y
;
413 pointList
[1].x
= polygon
[1].x
;
414 pointList
[1].y
= polygon
[1].y
;
415 pointList
[2].x
= polygon
[2].x
;
416 pointList
[2].y
= polygon
[2].y
;
417 pointList
[3].x
= polygon
[3].x
;
418 pointList
[3].y
= polygon
[3].y
;
420 fOffscreenView
->StrokePolygon(pointList
, 4);
422 fOffscreenView
->Sync();
429 TestView::_InitPolygon(const BRect
& b
, point
* polygon
) const
431 polygon
[0].x
= b
.left
;
432 polygon
[0].y
= b
.top
;
433 polygon
[0].direction_x
= random_number_between(-SPEED
, SPEED
);
434 polygon
[0].direction_y
= random_number_between(-SPEED
, SPEED
);
435 polygon
[0].velocity_x
= 0.0;
436 polygon
[0].velocity_y
= 0.0;
437 polygon
[1].x
= b
.right
;
438 polygon
[1].y
= b
.top
;
439 polygon
[1].direction_x
= random_number_between(-SPEED
, SPEED
);
440 polygon
[1].direction_y
= random_number_between(-SPEED
, SPEED
);
441 polygon
[1].velocity_x
= 0.0;
442 polygon
[1].velocity_y
= 0.0;
443 polygon
[2].x
= b
.right
;
444 polygon
[2].y
= b
.bottom
;
445 polygon
[2].direction_x
= random_number_between(-SPEED
, SPEED
);
446 polygon
[2].direction_y
= random_number_between(-SPEED
, SPEED
);
447 polygon
[2].velocity_x
= 0.0;
448 polygon
[2].velocity_y
= 0.0;
449 polygon
[3].x
= b
.left
;
450 polygon
[3].y
= b
.bottom
;
451 polygon
[3].direction_x
= random_number_between(-SPEED
, SPEED
);
452 polygon
[3].direction_y
= random_number_between(-SPEED
, SPEED
);
453 polygon
[3].velocity_x
= 0.0;
454 polygon
[3].velocity_y
= 0.0;
459 TestView::_InitColor(color_cycle
* color
) const
462 color
[0].direction
= random_number_between(-SPEED
* 4, SPEED
* 4);
464 color
[1].direction
= random_number_between(-SPEED
* 4, SPEED
* 4);
466 color
[2].direction
= random_number_between(-SPEED
* 4, SPEED
* 4);
471 morph(double* value
, double* direction
, double* velocity
, double min
, double max
)
475 // flip direction if necessary
476 if (*value
< min
&& *direction
< 0.0) {
477 *direction
= -*direction
;
478 } else if (*value
> max
&& *direction
> 0.0) {
479 *direction
= -*direction
;
482 // accelerate velocity
483 if (*direction
< 0.0) {
484 if (*velocity
> *direction
)
485 *velocity
+= *direction
/ 10.0;
487 if (*velocity
< *direction
)
488 *velocity
= *direction
;
490 if (*velocity
< *direction
)
491 *velocity
+= *direction
/ 10.0;
493 if (*velocity
> *direction
)
494 *velocity
= *direction
;
500 morph(uint8
* value
, double* direction
)
502 int32 v
= (int32
)(*value
+ *direction
);
505 *direction
= -*direction
;
506 } else if (v
> 255) {
508 *direction
= -*direction
;
515 TestView::_MorphPolygon(const BRect
& b
, point
* polygon
)
517 morph(&polygon
[0].x
, &polygon
[0].direction_x
, &polygon
[0].velocity_x
, b
.left
, b
.right
);
518 morph(&polygon
[1].x
, &polygon
[1].direction_x
, &polygon
[1].velocity_x
, b
.left
, b
.right
);
519 morph(&polygon
[2].x
, &polygon
[2].direction_x
, &polygon
[2].velocity_x
, b
.left
, b
.right
);
520 morph(&polygon
[3].x
, &polygon
[3].direction_x
, &polygon
[3].velocity_x
, b
.left
, b
.right
);
521 morph(&polygon
[0].y
, &polygon
[0].direction_y
, &polygon
[0].velocity_y
, b
.top
, b
.bottom
);
522 morph(&polygon
[1].y
, &polygon
[1].direction_y
, &polygon
[1].velocity_y
, b
.top
, b
.bottom
);
523 morph(&polygon
[2].y
, &polygon
[2].direction_y
, &polygon
[2].velocity_y
, b
.top
, b
.bottom
);
524 morph(&polygon
[3].y
, &polygon
[3].direction_y
, &polygon
[3].velocity_y
, b
.top
, b
.bottom
);
529 TestView::_MorphColor(color_cycle
* color
)
531 morph(&color
[0].value
, &color
[0].direction
);
532 morph(&color
[1].value
, &color
[1].direction
);
533 morph(&color
[2].value
, &color
[2].direction
);
538 show_window(BRect frame
, const char* name
)
540 BWindow
* window
= new BWindow(frame
, name
,
542 B_ASYNCHRONOUS_CONTROLS
| B_QUIT_ON_WINDOW_CLOSE
);
544 BView
* view
= new TestView(window
->Bounds(), "test", B_FOLLOW_ALL
,
545 B_WILL_DRAW
/* | B_FULL_UPDATE_ON_RESIZE*/);
547 window
->AddChild(view
);
548 BRect
b(0.0, 0.0, 60.0, 15.0);
549 b
.OffsetTo(5.0, view
->Bounds().bottom
- (b
.Height() + 15.0));
550 BButton
* control
= new BButton(b
, "button", "Reset", new BMessage(MSG_RESET
),
551 B_FOLLOW_LEFT
| B_FOLLOW_BOTTOM
);
552 view
->AddChild(control
);
553 control
->SetTarget(view
);
554 control
->SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
561 main(int argc
, char** argv
)
563 BApplication
* app
= new BApplication("application/x.vnd-Haiku.BitmapDrawing");
565 // BRect frame(10.0, 30.0, 790.0, 590.0);
566 BRect
frame(10.0, 30.0, 330.0, 220.0);
567 show_window(frame
, "BitmapDrawing");