216 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include <algorithm>
 | 
						|
#include <ctime>
 | 
						|
#include <fstream>
 | 
						|
#include <cmath>
 | 
						|
#include <memory>
 | 
						|
 | 
						|
#include "ui/editor.h"
 | 
						|
#include "desktop.h"
 | 
						|
#include <SDL3/SDL_events.h>
 | 
						|
#include "client_network.h"
 | 
						|
#include "gfx/shape_renderer.h"
 | 
						|
#include "gfx/txt_renderer.h"
 | 
						|
#include "terminal.h"
 | 
						|
#include "ui/i_window_content.h"
 | 
						|
#include "ui/taskbar.h"
 | 
						|
#include <SDL3/SDL_video.h>
 | 
						|
#include <ui/cursor_manager.h>
 | 
						|
#include "ui/ui_window.h"
 | 
						|
 | 
						|
static const std::string& get_random_snippet(const std::vector<std::string>& snippets) {
 | 
						|
  if(snippets.empty()) {
 | 
						|
    static const std::string err = "ERR";
 | 
						|
    return err;
 | 
						|
  }
 | 
						|
  return snippets[rand() % snippets.size()];
 | 
						|
}
 | 
						|
 | 
						|
Desktop::Desktop(int screen_width, int screen_height, ClientNetwork* network) {
 | 
						|
  _taskbar = std::make_unique<Taskbar>(screen_width, screen_height);
 | 
						|
  _network = network;
 | 
						|
  _focused_window = nullptr;
 | 
						|
  _launcher_is_open = false;
 | 
						|
  _launcher = std::make_unique<Launcher>(5, 5 + _taskbar->get_height(), 200);
 | 
						|
 | 
						|
  /* Load snippets for temp wallpaper. */
 | 
						|
  std::ifstream snippet_file("assets/menu_background_snippets.txt");
 | 
						|
  if(snippet_file.is_open()) {
 | 
						|
    std::string line;
 | 
						|
    while(std::getline(snippet_file, line)) {
 | 
						|
      if(!line.empty()) { _snippets.push_back(line); }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Init animated background. */
 | 
						|
  for(int i = 0; i < 100; ++i) {
 | 
						|
    float y_pos = (float)(rand() % screen_height);
 | 
						|
    _background_text.push_back(
 | 
						|
      {get_random_snippet(_snippets), (float)(rand() % screen_width),
 | 
						|
        y_pos,
 | 
						|
        (float)(rand() % 30 + 10) / 100.0f,
 | 
						|
        (int)y_pos
 | 
						|
      });
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Desktop owns UIWindow, make sure we delete them. */
 | 
						|
Desktop::~Desktop(void) {}
 | 
						|
 | 
						|
void Desktop::add_window(std::unique_ptr<UIWindow> window) {
 | 
						|
  _windows.push_back(std::move(window));
 | 
						|
  /* Focus new window. */
 | 
						|
  _set_focused_window(_windows.back().get());
 | 
						|
}
 | 
						|
 | 
						|
void Desktop::_set_focused_window(UIWindow* window) {
 | 
						|
  if(window == _focused_window) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if(_focused_window) {
 | 
						|
    _focused_window->set_focused(false);
 | 
						|
  }
 | 
						|
 | 
						|
  _focused_window = window;
 | 
						|
  if(_focused_window) {
 | 
						|
    _focused_window->set_focused(true);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void Desktop::handle_event(SDL_Event* event, int screen_width, int screen_height) {
 | 
						|
  if(event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
 | 
						|
    int mouse_x = event->button.x;
 | 
						|
    int mouse_y = event->button.y;
 | 
						|
 | 
						|
    /* When launcher open, check for outside click to close it. */
 | 
						|
    if(_launcher_is_open && !_launcher->is_point_inside(mouse_x, mouse_y, screen_height)) {
 | 
						|
      _launcher_is_open = false;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Find the top-most window that was clicked. */
 | 
						|
    for(int i = _windows.size()-1; i >= 0; --i) {
 | 
						|
      if(_windows[i].get()->is_point_inside(mouse_x, mouse_y)) {
 | 
						|
        if(!_windows[i]->is_minimized()) {
 | 
						|
          _set_focused_window(_windows[i].get());
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else if(event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
 | 
						|
    if(_taskbar->is_start_button_clicked(event, screen_height)) {
 | 
						|
      _launcher_is_open = !_launcher_is_open;
 | 
						|
    } else if(_launcher_is_open) {
 | 
						|
      std::string app_to_launch = _launcher->handle_event(event, screen_height);
 | 
						|
      if(app_to_launch == "Terminal") {
 | 
						|
        auto term = std::make_unique<Terminal>(_network);
 | 
						|
        auto term_window = std::make_unique<UIWindow>("Terminal", 150, 150, 800, 500);
 | 
						|
        term_window->set_content(std::move(term));
 | 
						|
        add_window(std::move(term_window));
 | 
						|
        _launcher_is_open = false;
 | 
						|
      } else if(app_to_launch == "Editor") {
 | 
						|
        auto editor = std::make_unique<Editor>();
 | 
						|
        auto editor_window = std::make_unique<UIWindow>("Editor", 200, 200, 600, 400);
 | 
						|
        editor_window->set_content(std::move(editor));
 | 
						|
        add_window(std::move(editor_window));
 | 
						|
        _launcher_is_open = false;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      UIWindow* clicked_window = _taskbar->handle_event(event, screen_height, _windows);
 | 
						|
      if(clicked_window) {
 | 
						|
        if(clicked_window == _focused_window && !clicked_window->is_minimized()) {
 | 
						|
          clicked_window->minimize();
 | 
						|
          _set_focused_window(nullptr);
 | 
						|
        } else {
 | 
						|
          clicked_window->restore();
 | 
						|
          _set_focused_window(clicked_window);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else if(event->type == SDL_EVENT_MOUSE_MOTION) {
 | 
						|
    bool on_resize_handle = false;
 | 
						|
    /* Iterate backwards since top-most windows are at the end. */
 | 
						|
    for(int i = _windows.size() - 1; i >= 0; --i) {
 | 
						|
      if(_windows[i]->is_mouse_over_resize_handle(event->motion.x, 
 | 
						|
                                                  event->motion.y)) {
 | 
						|
        on_resize_handle = true;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    CursorManager::set_cursor(on_resize_handle ? CursorType::RESIZE_NWSE
 | 
						|
                                               : CursorType::ARROW);
 | 
						|
  }
 | 
						|
 | 
						|
  if(_focused_window) {
 | 
						|
    _focused_window->handle_event(event, screen_width, screen_height,
 | 
						|
                                  _taskbar->get_height());
 | 
						|
    IWindowContent* content = _focused_window->get_content();
 | 
						|
    if(content) {
 | 
						|
      /*
 | 
						|
       * Only terminal should receive direct text input this way.
 | 
						|
       * Editor gets it through the generic handle_event call.
 | 
						|
       */
 | 
						|
      content->handle_input(event);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void Desktop::update(int screen_width, int screen_height) {
 | 
						|
  /* Remove closed windows. */
 | 
						|
  _update_wallpaper(screen_width, screen_height);
 | 
						|
  _windows.erase(std::remove_if(_windows.begin(), _windows.end(),
 | 
						|
                                [this](const std::unique_ptr<UIWindow>& w) {
 | 
						|
                                  if (w->should_close()) {
 | 
						|
                                    if (w.get() == _focused_window) {
 | 
						|
                                      _focused_window = nullptr;
 | 
						|
                                    }
 | 
						|
                                    return true;
 | 
						|
                                  }
 | 
						|
                                  return false;
 | 
						|
                                }),
 | 
						|
                 _windows.end());
 | 
						|
}
 | 
						|
 | 
						|
UIWindow* Desktop::get_focused_window(void) {
 | 
						|
  return _focused_window;
 | 
						|
}
 | 
						|
 | 
						|
void Desktop::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
 | 
						|
                     int screen_height, bool show_cursor) {
 | 
						|
  _render_wallpaper(txt_renderer);
 | 
						|
  if(_launcher_is_open) {
 | 
						|
    _launcher->render(shape_renderer, txt_renderer, screen_height);
 | 
						|
  }
 | 
						|
  _taskbar->render(shape_renderer, txt_renderer, _windows, _focused_window);
 | 
						|
  /* Render non-focused windows first. */
 | 
						|
  for(const auto& win : _windows) {
 | 
						|
    if(win.get() != _focused_window && !win->is_minimized()) {
 | 
						|
      win.get()->render(shape_renderer, txt_renderer, screen_height, show_cursor);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  /* Render focused window last so it's on top. */
 | 
						|
  if(_focused_window && !_focused_window->is_minimized()) {
 | 
						|
    _focused_window->render(shape_renderer, txt_renderer, screen_height, show_cursor);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void Desktop::_render_wallpaper(TextRenderer* txt_renderer) {
 | 
						|
  const Color wallpaper_color = { 0.0f, 0.15f, 0.08f };
 | 
						|
  for(auto& line : _background_text) {
 | 
						|
    txt_renderer->render_text(line.text.c_str(), std::round(line.x),
 | 
						|
                              line.render_y, 1.0f, wallpaper_color);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void Desktop::_update_wallpaper(int screen_width, int screen_height) {
 | 
						|
  for(auto& line : _background_text) {
 | 
						|
    line.y_precise -= line.speed;
 | 
						|
    line.render_y = static_cast<int>(std::round(line.y_precise));
 | 
						|
    if(line.render_y < 0) {
 | 
						|
      line.y_precise = screen_height;
 | 
						|
      line.x = (float)(rand() % screen_width);
 | 
						|
      line.text = get_random_snippet(_snippets);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |