CatDog: Help the user debug their programs

This adds helpful speech bubbles to CatDog. CatDog just wants to
help, that's all.
This commit is contained in:
Gunnar Beutner 2021-05-09 12:13:51 +02:00 committed by Andreas Kling
parent da5923bc54
commit e0fe38ea25
Notes: sideshowbarker 2024-07-18 18:27:30 +09:00
6 changed files with 132 additions and 0 deletions

View file

@ -1,5 +1,6 @@
set(SOURCES
CatDog.cpp
SpeechBubble.cpp
main.cpp
)

View file

@ -11,6 +11,8 @@
void CatDog::timer_event(Core::TimerEvent&)
{
if (!m_roaming)
return;
if (m_temp_pos.x() > 48) {
m_left = false;
m_right = true;
@ -105,6 +107,8 @@ void CatDog::paint_event(GUI::PaintEvent& event)
void CatDog::mousemove_event(GUI::MouseEvent& event)
{
if (!m_roaming)
return;
if (m_temp_pos == event.position())
return;
m_temp_pos = event.position();
@ -115,6 +119,15 @@ void CatDog::mousemove_event(GUI::MouseEvent& event)
}
m_sleeping = false;
}
void CatDog::mousedown_event(GUI::MouseEvent& event)
{
if (event.button() != GUI::MouseButton::Left)
return;
if (on_click)
on_click();
}
void CatDog::track_cursor_globally()
{
VERIFY(window());

View file

@ -18,16 +18,32 @@ public:
virtual void timer_event(Core::TimerEvent&) override;
virtual void paint_event(GUI::PaintEvent& event) override;
virtual void mousemove_event(GUI::MouseEvent& event) override;
virtual void mousedown_event(GUI::MouseEvent& event) override;
void track_cursor_globally();
void start_the_timer() { m_timer.start(); }
Function<void()> on_click;
bool roaming() const { return m_roaming; }
void set_roaming(bool roaming)
{
m_roaming = roaming;
if (!roaming) {
m_sleeping = false;
m_curr_frame = 0;
m_curr_bmp = m_alert;
update();
}
}
private:
Gfx::IntPoint m_temp_pos;
Core::ElapsedTimer m_timer;
int m_curr_frame = 1;
int m_moveX, m_moveY = 0;
bool m_up, m_down, m_left, m_right, m_sleeping = false;
bool m_roaming { true };
AK::NonnullRefPtr<Gfx::Bitmap> m_alert = *Gfx::Bitmap::load_from_file("/res/icons/catdog/alert.png");
AK::NonnullRefPtr<Gfx::Bitmap> m_erun1 = *Gfx::Bitmap::load_from_file("/res/icons/catdog/erun1.png");

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2021, Gunnar Beutner <gunnar@beutner.name>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "SpeechBubble.h"
#include <LibGUI/Painter.h>
#include <LibGfx/Palette.h>
void SpeechBubble::paint_event(GUI::PaintEvent&)
{
GUI::Painter painter(*this);
painter.clear_rect(rect(), Gfx::Color());
constexpr auto background_color = Gfx::Color::from_rgb(0xeaf688);
auto text_area = rect();
text_area.set_height(text_area.height() - 10);
painter.draw_rect(text_area, palette().active_window_border1());
text_area.shrink(2, 2);
painter.fill_rect(text_area, background_color);
auto connector_top_left = Gfx::IntPoint { rect().width() / 2 - 5, text_area.height() + 1 };
auto connector_top_right = Gfx::IntPoint { rect().width() / 2 + 5, text_area.height() + 1 };
auto connector_bottom = Gfx::IntPoint { rect().width() / 2 + 10, rect().height() };
painter.draw_triangle(connector_top_left, connector_top_right, connector_bottom, background_color);
painter.draw_line(connector_top_left, Gfx::IntPoint { connector_bottom.x() - 1, connector_bottom.y() }, palette().active_window_border1());
painter.draw_line(connector_top_right, connector_bottom, palette().active_window_border1());
painter.draw_text(text_area, "It looks like you're trying to debug\na program. Would you like some help?", Gfx::TextAlignment::Center);
}
void SpeechBubble::mousedown_event(GUI::MouseEvent& event)
{
if (event.button() != GUI::MouseButton::Left)
return;
if (on_dismiss)
on_dismiss();
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2021, Gunnar Beutner <gunnar@beutner.name>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibGUI/Widget.h>
class SpeechBubble final : public GUI::Widget {
C_OBJECT(SpeechBubble);
public:
virtual void paint_event(GUI::PaintEvent&) override;
virtual void mousedown_event(GUI::MouseEvent&) override;
Function<void()> on_dismiss;
private:
SpeechBubble() = default;
};

View file

@ -5,6 +5,8 @@
*/
#include "CatDog.h"
#include "SpeechBubble.h"
#include <LibCore/Timer.h>
#include <LibGUI/Action.h>
#include <LibGUI/Application.h>
#include <LibGUI/BoxLayout.h>
@ -63,5 +65,43 @@ int main(int argc, char** argv)
catdog_widget.start_timer(250, Core::TimerShouldFireWhenNotVisible::Yes);
catdog_widget.start_the_timer(); // timer for "mouse sleep detection"
auto advice_window = GUI::Window::construct();
advice_window->set_title("CatDog Advice");
advice_window->resize(225, 50);
advice_window->set_frameless(true);
advice_window->set_resizable(false);
advice_window->set_has_alpha_channel(true);
advice_window->set_alpha_hit_threshold(1.0f);
auto& advice_widget = advice_window->set_main_widget<SpeechBubble>();
advice_widget.set_layout<GUI::VerticalBoxLayout>();
advice_widget.layout()->set_spacing(0);
auto advice_timer = Core::Timer::construct();
advice_timer->set_interval(15000);
advice_timer->set_single_shot(true);
advice_timer->on_timeout = [&] {
window->move_to_front();
advice_window->move_to_front();
catdog_widget.set_roaming(false);
advice_window->move_to(window->x() - advice_window->width() / 2, window->y() - advice_window->height());
advice_window->show();
};
advice_timer->start();
advice_widget.on_dismiss = [&] {
catdog_widget.set_roaming(true);
advice_window->hide();
advice_timer->start();
};
// Let users toggle the advice functionality by clicking on catdog.
catdog_widget.on_click = [&] {
if (advice_timer->is_active())
advice_timer->stop();
else
advice_timer->start();
};
return app->exec();
}