diff options
Diffstat (limited to 'Applications/Welcome')
-rw-r--r-- | Applications/Welcome/Makefile | 14 | ||||
-rw-r--r-- | Applications/Welcome/TextWidget.cpp | 115 | ||||
-rw-r--r-- | Applications/Welcome/TextWidget.h | 38 | ||||
-rw-r--r-- | Applications/Welcome/background.png | bin | 0 -> 225952 bytes | |||
-rw-r--r-- | Applications/Welcome/main.cpp | 150 |
5 files changed, 317 insertions, 0 deletions
diff --git a/Applications/Welcome/Makefile b/Applications/Welcome/Makefile new file mode 100644 index 0000000000..a8b377dd82 --- /dev/null +++ b/Applications/Welcome/Makefile @@ -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 diff --git a/Applications/Welcome/TextWidget.cpp b/Applications/Welcome/TextWidget.cpp new file mode 100644 index 0000000000..ebd219d5e3 --- /dev/null +++ b/Applications/Welcome/TextWidget.cpp @@ -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); +} diff --git a/Applications/Welcome/TextWidget.h b/Applications/Welcome/TextWidget.h new file mode 100644 index 0000000000..7690c60cdf --- /dev/null +++ b/Applications/Welcome/TextWidget.h @@ -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 }; +}; diff --git a/Applications/Welcome/background.png b/Applications/Welcome/background.png Binary files differnew file mode 100644 index 0000000000..7078ce75c0 --- /dev/null +++ b/Applications/Welcome/background.png diff --git a/Applications/Welcome/main.cpp b/Applications/Welcome/main.cpp new file mode 100644 index 0000000000..14a20e3d61 --- /dev/null +++ b/Applications/Welcome/main.cpp @@ -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(); +} |