mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 04:37:44 +00:00
Applications: Add "Welcome" application, inspired by Windows 98
This commit is contained in:
parent
0706bf470f
commit
6fd096999e
7 changed files with 319 additions and 0 deletions
14
Applications/Welcome/Makefile
Normal file
14
Applications/Welcome/Makefile
Normal file
|
@ -0,0 +1,14 @@
|
|||
include ../../Makefile.common
|
||||
|
||||
OBJS = \
|
||||
main.o \
|
||||
TextWidget.o \
|
||||
background.png.o
|
||||
|
||||
APP = Welcome
|
||||
|
||||
.SUFFIXES: .png
|
||||
%.png.o: %.png
|
||||
@echo "LINK $<"; $(LINK) --relocatable --format binary --output $@ $<
|
||||
|
||||
include ../Makefile.common
|
115
Applications/Welcome/TextWidget.cpp
Normal file
115
Applications/Welcome/TextWidget.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
#include <AK/String.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGUI/GPainter.h>
|
||||
|
||||
#include "TextWidget.h"
|
||||
|
||||
TextWidget::TextWidget(GWidget* parent)
|
||||
: GFrame(parent)
|
||||
{
|
||||
}
|
||||
|
||||
TextWidget::TextWidget(const StringView& text, GWidget* parent)
|
||||
: GFrame(parent)
|
||||
, m_text(text)
|
||||
{
|
||||
}
|
||||
|
||||
TextWidget::~TextWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void TextWidget::set_text(const StringView& text)
|
||||
{
|
||||
if (text == m_text)
|
||||
return;
|
||||
m_text = move(text);
|
||||
wrap_and_set_height();
|
||||
update();
|
||||
}
|
||||
|
||||
void TextWidget::paint_event(GPaintEvent& event)
|
||||
{
|
||||
GFrame::paint_event(event);
|
||||
|
||||
GPainter painter(*this);
|
||||
painter.add_clip_rect(event.rect());
|
||||
|
||||
int indent = 0;
|
||||
if (frame_thickness() > 0)
|
||||
indent = font().glyph_width('x') / 2;
|
||||
|
||||
for (int i = 0; i < m_lines.size(); i++) {
|
||||
auto& line = m_lines[i];
|
||||
|
||||
auto text_rect = frame_inner_rect();
|
||||
text_rect.move_by(indent, i * m_line_height);
|
||||
if (!line.is_empty())
|
||||
text_rect.set_width(text_rect.width() - indent * 2);
|
||||
|
||||
if (is_enabled()) {
|
||||
painter.draw_text(text_rect, line, m_text_alignment, foreground_color(), TextElision::None);
|
||||
} else {
|
||||
painter.draw_text(text_rect.translated(1, 1), line, font(), text_alignment(), Color::White, TextElision::Right);
|
||||
painter.draw_text(text_rect, line, font(), text_alignment(), Color::from_rgb(0x808080), TextElision::Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextWidget::resize_event(GResizeEvent& event)
|
||||
{
|
||||
wrap_and_set_height();
|
||||
GWidget::resize_event(event);
|
||||
}
|
||||
|
||||
void TextWidget::wrap_and_set_height()
|
||||
{
|
||||
Vector<String> words;
|
||||
int start = -1;
|
||||
for (int i = 0; i < m_text.length(); i++) {
|
||||
auto ch = m_text[i];
|
||||
|
||||
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
|
||||
if (start != -1)
|
||||
words.append(m_text.substring(start, i - start));
|
||||
start = -1;
|
||||
} else if (start == -1) {
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
if (start != -1)
|
||||
words.append(m_text.substring(start, m_text.length() - start));
|
||||
|
||||
auto rect = frame_inner_rect();
|
||||
if (frame_thickness() > 0)
|
||||
rect.set_width(rect.width() - font().glyph_width('x'));
|
||||
|
||||
StringBuilder builder;
|
||||
Vector<String> lines;
|
||||
int line_width = 0;
|
||||
for (auto& word : words) {
|
||||
int word_width = font().width(word);
|
||||
if (line_width != 0)
|
||||
word_width += font().glyph_width('x');
|
||||
|
||||
if (line_width + word_width > rect.width()) {
|
||||
lines.append(builder.to_string());
|
||||
line_width = 0;
|
||||
}
|
||||
|
||||
if (line_width != 0)
|
||||
builder.append(' ');
|
||||
builder.append(word);
|
||||
line_width += word_width;
|
||||
}
|
||||
auto last_line = builder.to_string();
|
||||
if (!last_line.is_empty()) {
|
||||
lines.append(last_line);
|
||||
}
|
||||
|
||||
m_lines = lines;
|
||||
|
||||
set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
|
||||
set_preferred_size(0, m_lines.size() * m_line_height + frame_thickness() * 2);
|
||||
}
|
38
Applications/Welcome/TextWidget.h
Normal file
38
Applications/Welcome/TextWidget.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibDraw/TextAlignment.h>
|
||||
#include <LibGUI/GFrame.h>
|
||||
|
||||
class TextWidget : public GFrame {
|
||||
C_OBJECT(TextWidget)
|
||||
public:
|
||||
explicit TextWidget(GWidget* parent = nullptr);
|
||||
TextWidget(const StringView& text, GWidget* parent = nullptr);
|
||||
virtual ~TextWidget() override;
|
||||
|
||||
String text() const { return m_text; }
|
||||
void set_text(const StringView&);
|
||||
|
||||
TextAlignment text_alignment() const { return m_text_alignment; }
|
||||
void set_text_alignment(TextAlignment text_alignment) { m_text_alignment = text_alignment; }
|
||||
|
||||
bool should_wrap() const { return m_should_wrap; }
|
||||
void set_should_wrap(bool should_wrap) { m_should_wrap = should_wrap; }
|
||||
|
||||
int line_height() const { return m_line_height; }
|
||||
void set_line_height(int line_height) { m_line_height = line_height; }
|
||||
|
||||
void wrap_and_set_height();
|
||||
|
||||
private:
|
||||
virtual void paint_event(GPaintEvent&) override;
|
||||
virtual void resize_event(GResizeEvent&) override;
|
||||
|
||||
String m_text;
|
||||
Vector<String> m_lines;
|
||||
TextAlignment m_text_alignment { TextAlignment::Center };
|
||||
bool m_should_wrap { false };
|
||||
int m_line_height { 0 };
|
||||
};
|
BIN
Applications/Welcome/background.png
Normal file
BIN
Applications/Welcome/background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 221 KiB |
150
Applications/Welcome/main.cpp
Normal file
150
Applications/Welcome/main.cpp
Normal file
|
@ -0,0 +1,150 @@
|
|||
#include <AK/String.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibDraw/PNGLoader.h>
|
||||
#include <LibGUI/GApplication.h>
|
||||
#include <LibGUI/GBoxLayout.h>
|
||||
#include <LibGUI/GButton.h>
|
||||
#include <LibGUI/GDesktop.h>
|
||||
#include <LibGUI/GLabel.h>
|
||||
#include <LibGUI/GStackWidget.h>
|
||||
#include <LibGUI/GWindow.h>
|
||||
|
||||
#include "TextWidget.h"
|
||||
|
||||
extern const u8 _binary_background_png_start[];
|
||||
extern const u8 _binary_background_png_size;
|
||||
|
||||
struct ContentPage {
|
||||
String menu_name;
|
||||
String title;
|
||||
Vector<String> content;
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Vector<ContentPage> pages = {
|
||||
{
|
||||
"Welcome",
|
||||
"Welcome",
|
||||
{
|
||||
"Welcome to the exciting new world of Serenity, where the year is 1998 and the leading OS vendor has decided to merge their flagship product with a Unix-like kernel.",
|
||||
"Sit back and relax as you take a brief tour of the options available on this screen.",
|
||||
"If you want to explore an option, just click it.",
|
||||
},
|
||||
},
|
||||
{
|
||||
"Register Now",
|
||||
"Register Now!",
|
||||
{
|
||||
"Registering your copy of Serenity opens the doors to full integration of Serenity into your life, your being, and your soul.",
|
||||
"By registering Serenity, you enter into the draw to win a lifetime supply of milk, delivered fresh each day by a mystical horse wearing a full tuxedo.",
|
||||
"To register, simply write your contact details on a piece of paper and hold it up to your monitor.",
|
||||
},
|
||||
},
|
||||
{
|
||||
"Connect to the Internet",
|
||||
"Connect to the Internet",
|
||||
{
|
||||
"On the Internet, you can correspond through electronic mail (e-mail), get the latest news and financial information, and visit Web sites around the world, most of which will make you really angry.",
|
||||
"Serenity includes several internet applications, such as an IRC (Internet relay chat) client, 4chan browser, telnet server, and basic utilities like ping.",
|
||||
"Come chat with us today! How bad can it be?",
|
||||
},
|
||||
},
|
||||
{
|
||||
"Have fun",
|
||||
"Play Some Games!",
|
||||
{
|
||||
"Serenity includes several games built right into the base system. These include the classic game Snake and the anti-productivity mainstay Minesweeper.",
|
||||
"With a little extra effort, you can even play the original id Software hit DOOM, albeit without sound. No sound just means you won't alert your boss, so it's more of a feature than a limitation.",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
GApplication app(argc, argv);
|
||||
|
||||
auto* window = new GWindow;
|
||||
window->set_title("Welcome to Serenity");
|
||||
Rect window_rect { 0, 0, 640, 360 };
|
||||
window_rect.center_within(GDesktop::the().rect());
|
||||
window->set_resizable(true);
|
||||
window->set_rect(window_rect);
|
||||
|
||||
auto* background = new GLabel;
|
||||
window->set_main_widget(background);
|
||||
background->set_fill_with_background_color(true);
|
||||
background->set_layout(make<GBoxLayout>(Orientation::Vertical));
|
||||
background->layout()->set_margins({ 8, 8, 8, 8 });
|
||||
background->layout()->set_spacing(8);
|
||||
background->set_icon(load_png_from_memory((const u8*)&_binary_background_png_start, (size_t)&_binary_background_png_size));
|
||||
background->set_size_policy(SizePolicy::Fill, SizePolicy::Fill);
|
||||
background->set_preferred_size(background->icon()->size());
|
||||
|
||||
//
|
||||
// header
|
||||
//
|
||||
|
||||
auto* header = new GLabel(background);
|
||||
header->set_font(Font::default_bold_font());
|
||||
header->set_text("Welcome to Serenity");
|
||||
header->set_text_alignment(TextAlignment::CenterLeft);
|
||||
header->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
|
||||
header->set_preferred_size(0, 30);
|
||||
|
||||
//
|
||||
// main section
|
||||
//
|
||||
|
||||
auto* main_section = new GWidget(background);
|
||||
main_section->set_layout(make<GBoxLayout>(Orientation::Horizontal));
|
||||
main_section->layout()->set_margins({ 0, 0, 0, 0 });
|
||||
main_section->layout()->set_spacing(8);
|
||||
main_section->set_size_policy(SizePolicy::Fill, SizePolicy::Fill);
|
||||
|
||||
auto* menu = new GWidget(main_section);
|
||||
menu->set_layout(make<GBoxLayout>(Orientation::Vertical));
|
||||
menu->layout()->set_margins({ 0, 0, 0, 0 });
|
||||
menu->layout()->set_spacing(8);
|
||||
menu->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
|
||||
menu->set_preferred_size(200, 0);
|
||||
|
||||
auto* stack = new GStackWidget(main_section);
|
||||
stack->set_size_policy(SizePolicy::Fill, SizePolicy::Fill);
|
||||
|
||||
for (auto& page : pages) {
|
||||
auto* content = new GWidget(stack);
|
||||
content->set_layout(make<GBoxLayout>(Orientation::Vertical));
|
||||
content->layout()->set_margins({ 0, 0, 0, 0 });
|
||||
content->layout()->set_spacing(8);
|
||||
content->set_size_policy(SizePolicy::Fill, SizePolicy::Fill);
|
||||
|
||||
auto* content_title = new GLabel(content);
|
||||
content_title->set_font(Font::default_bold_font());
|
||||
content_title->set_text(page.title);
|
||||
content_title->set_text_alignment(TextAlignment::CenterLeft);
|
||||
content_title->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
|
||||
content_title->set_preferred_size(0, 10);
|
||||
|
||||
for (auto& paragraph : page.content) {
|
||||
auto* content_text = new TextWidget(content);
|
||||
content_text->set_font(Font::default_font());
|
||||
content_text->set_text(paragraph);
|
||||
content_text->set_text_alignment(TextAlignment::TopLeft);
|
||||
content_text->set_line_height(12);
|
||||
content_text->wrap_and_set_height();
|
||||
}
|
||||
|
||||
auto* menu_option = new GButton(menu);
|
||||
menu_option->set_font(Font::default_font());
|
||||
menu_option->set_text(page.menu_name);
|
||||
menu_option->set_text_alignment(TextAlignment::CenterLeft);
|
||||
menu_option->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
|
||||
menu_option->set_preferred_size(0, 20);
|
||||
menu_option->on_click = [stack, content](GButton&) {
|
||||
stack->set_active_widget(content);
|
||||
content->invalidate_layout();
|
||||
};
|
||||
}
|
||||
|
||||
window->show();
|
||||
return app.exec();
|
||||
}
|
|
@ -87,6 +87,7 @@ cp ../Applications/ChanViewer/ChanViewer mnt/bin/ChanViewer
|
|||
cp ../Applications/Calculator/Calculator mnt/bin/Calculator
|
||||
cp ../Applications/SoundPlayer/SoundPlayer mnt/bin/SoundPlayer
|
||||
cp ../Applications/DisplayProperties/DisplayProperties mnt/bin/DisplayProperties
|
||||
cp ../Applications/Welcome/Welcome mnt/bin/Welcome
|
||||
cp ../Demos/HelloWorld/HelloWorld mnt/bin/HelloWorld
|
||||
cp ../Demos/HelloWorld2/HelloWorld2 mnt/bin/HelloWorld2
|
||||
cp ../Demos/RetroFetch/RetroFetch mnt/bin/RetroFetch
|
||||
|
|
|
@ -57,6 +57,7 @@ build_targets="$build_targets ../Applications/Taskbar"
|
|||
build_targets="$build_targets ../Applications/Terminal"
|
||||
build_targets="$build_targets ../Applications/TextEditor"
|
||||
build_targets="$build_targets ../Applications/SoundPlayer"
|
||||
build_targets="$build_targets ../Applications/Welcome"
|
||||
|
||||
build_targets="$build_targets ../Demos/Fire"
|
||||
build_targets="$build_targets ../Demos/HelloWorld"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue