mirror of
https://github.com/clockworkpi/Menu.git
synced 2026-03-21 11:22:50 +01:00
gcores ~/apps/Menu branch first commit
This commit is contained in:
@@ -1,52 +0,0 @@
|
||||
|
||||
/*
|
||||
set_text(render void, text. char, color uint32)
|
||||
*/
|
||||
|
||||
class game+, control+, button {
|
||||
|
||||
inherit game::control = super;
|
||||
|
||||
private import lib::sdl2;
|
||||
|
||||
struct button {
|
||||
tex texture;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
inline set_text(render void, text. char, color uint32 = 0xff000000) {
|
||||
this.tex->init(
|
||||
global::uni_font->create_tex(render, text, color));
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
var rect SDL_Rect = this->get_rect();
|
||||
SDL_SetRenderDrawColor(render, 245, 245, 245, 0xff);
|
||||
SDL_RenderFillRect(render, &rect);
|
||||
if this->has_focus() {
|
||||
SDL_SetRenderDrawColor(render, 0, 162, 232, 0xff);
|
||||
else
|
||||
SDL_SetRenderDrawColor(render, 127, 127, 127, 0xff);
|
||||
}
|
||||
SDL_RenderDrawRect(render, &rect);
|
||||
if this.tex->get_texture() ~= null {
|
||||
var width int = this.tex->get_width();
|
||||
var height int = this.tex->get_height();
|
||||
rect.x++;
|
||||
rect.y++;
|
||||
rect.w -= 2;
|
||||
rect.h -= 2;
|
||||
this.tex->draw2(render,
|
||||
rect.x + (rect.w - width) / 2,
|
||||
rect.y + (rect.h - height) / 2, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
|
||||
/*
|
||||
set_text_color(color uint32)
|
||||
set_text(render void, text. char, color uint32)
|
||||
get_text() .char
|
||||
get_keybd_cb() void
|
||||
*/
|
||||
|
||||
class game+, control+, edit {
|
||||
|
||||
inherit game::control = super;
|
||||
|
||||
private import lib::sdl2;
|
||||
|
||||
private alias string = std::string;
|
||||
|
||||
struct edit {
|
||||
tex texture;
|
||||
str string;
|
||||
text_color uint32;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this);
|
||||
this.text_color = 0xff000000;
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
inline set_text_color(color uint32) {
|
||||
this.text_color = color;
|
||||
}
|
||||
|
||||
inline set_text(render void, text. char) {
|
||||
this.str->set(text);
|
||||
this.tex->init(
|
||||
global::uni_font->create_tex(render, text, this.text_color));
|
||||
}
|
||||
|
||||
inline get_text() .char {
|
||||
return this.str->ptr();
|
||||
}
|
||||
|
||||
inline get_keybd_cb() void {
|
||||
return lambda(text. char, this.edit) [
|
||||
this->set_text(this->get_window()->get_render(), text);
|
||||
];
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
define {
|
||||
TEXT_GAP = 3;
|
||||
}
|
||||
var rect SDL_Rect = this->get_rect();
|
||||
SDL_SetRenderDrawColor(render, 0xff, 0xff, 0xff, 0xff);
|
||||
SDL_RenderFillRect(render, &rect);
|
||||
if this->has_focus() {
|
||||
SDL_SetRenderDrawColor(render, 0, 162, 232, 0xff);
|
||||
else
|
||||
SDL_SetRenderDrawColor(render, 127, 127, 127, 0xff);
|
||||
}
|
||||
SDL_RenderDrawRect(render, &rect);
|
||||
if this.tex->get_texture() ~= null {
|
||||
var width int = this.tex->get_width();
|
||||
var height int = this.tex->get_height();
|
||||
var max_width int = rect.w - (TEXT_GAP * 2);
|
||||
if width > max_width;
|
||||
width = max_width;
|
||||
this.tex->draw2(render, rect.x + TEXT_GAP, rect.y + (rect.h - height) / 2, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
|
||||
/*
|
||||
set_normal_image(render void, filename. char) bool
|
||||
set_hover_image(render void, filename. char) bool
|
||||
set_image(render void, filename. char) bool
|
||||
set_outline_size(size int)
|
||||
get_outline_size() int
|
||||
*/
|
||||
|
||||
class game+, control+, image_button {
|
||||
|
||||
inherit game::control = super;
|
||||
|
||||
private import lib::sdl2;
|
||||
|
||||
struct image_button {
|
||||
normal texture;
|
||||
hover texture;
|
||||
image texture;
|
||||
outline_size int;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
inline set_normal_image(render void, filename. char) bool {
|
||||
if func = this.normal->load_file(render, filename) {
|
||||
this->set_size(
|
||||
this.normal->get_width(),
|
||||
this.normal->get_height());
|
||||
}
|
||||
}
|
||||
|
||||
inline set_hover_image(render void, filename. char) bool {
|
||||
return this.hover->load_file(render, filename);
|
||||
}
|
||||
|
||||
inline set_image(render void, filename. char) bool {
|
||||
return this.image->load_file(render, filename);
|
||||
}
|
||||
|
||||
inline set_outline_size(size int) {
|
||||
this.outline_size = size;
|
||||
}
|
||||
|
||||
inline get_outline_size() int {
|
||||
return this.outline_size;
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
var rect SDL_Rect = this->get_rect();
|
||||
if this->has_focus() {
|
||||
this.hover->draw(render, rect.x, rect.y);
|
||||
else
|
||||
this.normal->draw(render, rect.x, rect.y);
|
||||
}
|
||||
if this.outline_size {
|
||||
rect.x += this.outline_size;
|
||||
rect.y += this.outline_size;
|
||||
rect.w -= this.outline_size * 2;
|
||||
rect.h -= this.outline_size * 2;
|
||||
}
|
||||
var width int = this.image->get_width();
|
||||
var height int = this.image->get_height();
|
||||
if width > rect.w;
|
||||
width = rect.w;
|
||||
if height > rect.h;
|
||||
height = rect.h;
|
||||
this.image->draw3(render,
|
||||
rect.x + (rect.w - width) / 2,
|
||||
rect.y + (rect.h - height) / 2, width, height);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
|
||||
/*
|
||||
set_text(render void, text. char, color uint32) bool
|
||||
*/
|
||||
|
||||
class game+, control+, label {
|
||||
|
||||
inherit game::control = super;
|
||||
|
||||
private import lib::sdl2;
|
||||
|
||||
struct label {
|
||||
tex texture;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this); }
|
||||
func destructor() {
|
||||
destructor(this); }
|
||||
|
||||
func set_text(render void, text. char, color uint32 = 0xff000000) bool {
|
||||
if func = this.tex->init(global::uni_font->create_tex(render, text, color)) {
|
||||
this->set_size(
|
||||
this.tex->get_width(),
|
||||
this.tex->get_height());
|
||||
}
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
this.tex->draw(render,
|
||||
this->get_x(),
|
||||
this->get_y());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
|
||||
/*
|
||||
set_callback(on_select void, on_close void, arg void)
|
||||
add_menu(render void, id int, title. char)
|
||||
*/
|
||||
|
||||
class game+, control+, popup_menu {
|
||||
|
||||
inherit game::control = super;
|
||||
|
||||
private import rt::c, lib::sdl2;
|
||||
|
||||
private alias
|
||||
string = std::string,
|
||||
vector = std::vector;
|
||||
|
||||
class menu {
|
||||
struct menu {
|
||||
white_title texture;
|
||||
black_title texture;
|
||||
id int;
|
||||
}
|
||||
func constructor() {
|
||||
constructor(this);
|
||||
this.id = -1;
|
||||
}
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
}
|
||||
|
||||
struct popup_menu {
|
||||
menus vector<menu>;
|
||||
input_delay repeat;
|
||||
input_lock norepeat;
|
||||
on_select void;
|
||||
on_close void;
|
||||
arg void;
|
||||
cursor int;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
memset(this, 0, sizeof(popup_menu));
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
define {
|
||||
MENU_GAP = 12;
|
||||
MENU_HEIGHT = 25;
|
||||
}
|
||||
|
||||
func init(render void) bool {
|
||||
this.input_delay->init(300, -10, 20);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
on_select = lambda(id int, arg void) [
|
||||
|
||||
];
|
||||
on_close = lambda(arg void) [
|
||||
|
||||
];
|
||||
*/
|
||||
inline set_callback(on_select void, on_close void, arg void) {
|
||||
this.on_select = on_select;
|
||||
this.on_close = on_close;
|
||||
this.arg = arg;
|
||||
}
|
||||
|
||||
func add_menu(render void, id int, title. char) {
|
||||
var menu. menu = this.menus->new();
|
||||
menu.white_title->init(
|
||||
global::uni_font->create_tex(render, title, 0xffffffff));
|
||||
menu.black_title->init(
|
||||
global::uni_font->create_tex(render, title, 0xff000000));
|
||||
menu.id = id;
|
||||
var width int = menu.black_title->get_width() + (MENU_GAP * 2);
|
||||
if this->get_width() < width;
|
||||
this->set_width(width);
|
||||
this->set_height(this.menus->count() * MENU_HEIGHT + 2);
|
||||
}
|
||||
|
||||
func update(render void) {
|
||||
var state. uint8 = SDL_GetKeyboardState(null);
|
||||
if state[CPI_SCANCODE_UP] {
|
||||
if this.input_delay->do() {
|
||||
if this.cursor;
|
||||
this.cursor--;
|
||||
this.input_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_DOWN];
|
||||
if this.input_delay->do() {
|
||||
if this.cursor < this.menus->count() - 1;
|
||||
this.cursor++;
|
||||
this.input_delay->undo();
|
||||
}
|
||||
else
|
||||
this.input_delay->reset();
|
||||
}
|
||||
if state[CPI_SCANCODE_A] or
|
||||
state[CPI_SCANCODE_B] or
|
||||
state[CPI_SCANCODE_MENU] {
|
||||
if this.input_lock->do() {
|
||||
if state[CPI_SCANCODE_B] {
|
||||
proto fn(id int, arg void);
|
||||
fn[this.on_select](this.menus->at(this.cursor).id, this.arg);
|
||||
}
|
||||
{
|
||||
proto fn(arg void);
|
||||
fn[this.on_close](this.arg);
|
||||
}
|
||||
}
|
||||
else
|
||||
this.input_lock->set(false);
|
||||
}
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
var rect SDL_Rect = this->get_rect();
|
||||
SDL_SetRenderDrawColor(render, 0xff, 0xff, 0xff, 0xff);
|
||||
SDL_RenderFillRect(render, &rect);
|
||||
SDL_SetRenderDrawColor(render, 0xcd, 0xcd, 0xcd, 0xff);
|
||||
SDL_RenderDrawRect(render, &rect);
|
||||
rect.x += 1;
|
||||
rect.y += 1;
|
||||
rect.w -= 2;
|
||||
rect.h -= 2;
|
||||
forvar index size_t = 0, count size_t = this.menus->count(); index < count; index++ {
|
||||
var menu. menu = this.menus->at(index);
|
||||
if this.cursor == index {
|
||||
var sub_rect SDL_Rect;
|
||||
sub_rect.x = rect.x;
|
||||
sub_rect.y = rect.y;
|
||||
sub_rect.w = rect.w;
|
||||
sub_rect.h = MENU_HEIGHT;
|
||||
SDL_SetRenderDrawColor(render, 0x00, 0xa2, 0xe8, 0xff);
|
||||
SDL_RenderFillRect(render, &sub_rect);
|
||||
menu.white_title->draw(render, rect.x + MENU_GAP,
|
||||
rect.y + (MENU_HEIGHT - menu.white_title->get_height()) / 2);
|
||||
else
|
||||
menu.black_title->draw(render, rect.x + MENU_GAP,
|
||||
rect.y + (MENU_HEIGHT - menu.black_title->get_height()) / 2);
|
||||
}
|
||||
rect.y += MENU_HEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
func wake() {
|
||||
this.input_delay->reset(false);
|
||||
this.input_lock->set(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
|
||||
// template
|
||||
|
||||
class game+, control+, temp {
|
||||
|
||||
inherit game::control = super;
|
||||
|
||||
private import lib::sdl2;
|
||||
|
||||
struct temp {
|
||||
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
func init(render void) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
func update(render void) {
|
||||
this.super->update(render);
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
this.super->draw(render);
|
||||
}
|
||||
|
||||
func wake() {
|
||||
this.super->wake();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
|
||||
module game+ {
|
||||
|
||||
private import lib::sdl2;
|
||||
|
||||
define {
|
||||
CPI_WIDTH = 320;
|
||||
CPI_HEIGHT = 240;
|
||||
}
|
||||
|
||||
define {
|
||||
CPI_SCANCODE_MENU = SDL_SCANCODE_ESCAPE;
|
||||
CPI_SCANCODE_SELECT = SDL_SCANCODE_SPACE;
|
||||
CPI_SCANCODE_START = SDL_SCANCODE_RETURN;
|
||||
CPI_SCANCODE_A = SDL_SCANCODE_J;
|
||||
CPI_SCANCODE_B = SDL_SCANCODE_K;
|
||||
CPI_SCANCODE_X = SDL_SCANCODE_U;
|
||||
CPI_SCANCODE_Y = SDL_SCANCODE_I;
|
||||
CPI_SCANCODE_UP = SDL_SCANCODE_UP;
|
||||
CPI_SCANCODE_DOWN = SDL_SCANCODE_DOWN;
|
||||
CPI_SCANCODE_LEFT = SDL_SCANCODE_LEFT;
|
||||
CPI_SCANCODE_RIGHT = SDL_SCANCODE_RIGHT;
|
||||
CPI_SCANCODE_LK1 = SDL_SCANCODE_H;
|
||||
CPI_SCANCODE_LK2 = SDL_SCANCODE_Y;
|
||||
CPI_SCANCODE_LK3 = SDL_SCANCODE_UNKNOWN; // ???
|
||||
CPI_SCANCODE_LK4 = SDL_SCANCODE_O;
|
||||
CPI_SCANCODE_LK5 = SDL_SCANCODE_L;
|
||||
CPI_SCANCODE_SHIFT_SELECT = SDL_SCANCODE_KP_MINUS;
|
||||
CPI_SCANCODE_SHIFT_START = SDL_SCANCODE_KP_PLUS;
|
||||
CPI_SCANCODE_SHIFT_A = SDL_SCANCODE_H; // CPI_SCANCODE_LK1
|
||||
CPI_SCANCODE_SHIFT_B = SDL_SCANCODE_L; // CPI_SCANCODE_LK5
|
||||
CPI_SCANCODE_SHIFT_X = SDL_SCANCODE_Y; // CPI_SCANCODE_LK2
|
||||
CPI_SCANCODE_SHIFT_Y = SDL_SCANCODE_O; // CPI_SCANCODE_LK4
|
||||
}
|
||||
|
||||
define {
|
||||
CPI_BACKLIGHT = "/proc/driver/backlight";
|
||||
CPI_BATTERY = "/sys/class/power_supply/axp20x-battery/uevent";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
|
||||
class game+, control+ {
|
||||
|
||||
private import rt::c, lib::sdl2;
|
||||
|
||||
private alias vector = std::vector;
|
||||
|
||||
struct control {
|
||||
struct callback {
|
||||
update void;
|
||||
draw void;
|
||||
wake void;
|
||||
destructor void;
|
||||
}
|
||||
parent. scene;
|
||||
parent_control. control;
|
||||
controls vector<void>;
|
||||
focus_control. control;
|
||||
popup. control;
|
||||
closing_popup. control;
|
||||
pending_popup. control;
|
||||
x int;
|
||||
y int;
|
||||
width int;
|
||||
height int;
|
||||
enable bool;
|
||||
visible bool;
|
||||
focus bool;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
memset(this, 0, sizeof(control));
|
||||
this.enable = true;
|
||||
this.visible = true;
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
if this.popup ~= null;
|
||||
this->free_control(this.popup);
|
||||
if this.closing_popup ~= null;
|
||||
this->free_control(this.closing_popup);
|
||||
if this.pending_popup ~= null;
|
||||
this->free_control(this.pending_popup);
|
||||
forvar count size_t = this.controls->count(); count;;
|
||||
this->free_control(.this.controls->at(--count));
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline create_control<T>(x int, y int, width int = 0, height int = 0) .T {
|
||||
func = this.parent->create_control<T>(x, y, width, height);
|
||||
func->set_parent_control(this);
|
||||
}
|
||||
|
||||
inline new_control<T>(x int, y int, width int = 0, height int = 0) .T {
|
||||
this.controls->push_back(
|
||||
func = this->create_control<T>(this.x + x, this.y + y, width, height));
|
||||
}
|
||||
|
||||
inline free_control(control. control) {
|
||||
this.parent->free_control(control);
|
||||
}
|
||||
|
||||
// focus
|
||||
|
||||
func set_focus(control. control) {
|
||||
var prev. control = this.focus_control;
|
||||
if prev ~= null;
|
||||
prev.focus = false;
|
||||
this.focus_control = control, control.focus = true;
|
||||
}
|
||||
|
||||
inline get_focus() .control {
|
||||
return this.focus_control;
|
||||
}
|
||||
|
||||
// popup
|
||||
|
||||
func close_popup() {
|
||||
if this.popup ~= null {
|
||||
this.closing_popup = this.popup;
|
||||
this.popup = null;
|
||||
// xxx
|
||||
if this.callback.wake ~= null {
|
||||
proto fn(this void);
|
||||
fn[this.callback.wake](this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func close_parent_popup() {
|
||||
if this.parent_control == null {
|
||||
this.parent->close_popup();
|
||||
else
|
||||
this.parent_control->close_popup();
|
||||
}
|
||||
}
|
||||
|
||||
func set_popup(control. control) {
|
||||
if this.popup == null and this.closing_popup == null {
|
||||
this.popup = control;
|
||||
else
|
||||
if this.pending_popup ~= null;
|
||||
this->free_control(this.pending_popup);
|
||||
this.pending_popup = control;
|
||||
}
|
||||
}
|
||||
|
||||
func has_popup() bool {
|
||||
if this.popup ~= null or
|
||||
this.closing_popup ~= null or
|
||||
this.pending_popup ~= null {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
func update(render void) {
|
||||
proto fn(this void, render void);
|
||||
if this.closing_popup ~= null;
|
||||
this->free_control(this.closing_popup), this.closing_popup = null;
|
||||
if this.pending_popup ~= null {
|
||||
if this.popup ~= null;
|
||||
this->free_control(this.popup);
|
||||
this.popup = this.pending_popup;
|
||||
this.pending_popup = null;
|
||||
}
|
||||
// xxx
|
||||
if this.popup == null {
|
||||
forvar count size_t = this.controls->count(); count; {
|
||||
var control. control = .this.controls->at(--count);
|
||||
if control.callback.update ~= null;
|
||||
fn[control.callback.update](control, render);
|
||||
}
|
||||
else
|
||||
var popup. control = this.popup;
|
||||
if popup.callback.update ~= null;
|
||||
fn[popup.callback.update](popup, render);
|
||||
}
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
proto fn(this void, render void);
|
||||
forvar count size_t = this.controls->count(); count; {
|
||||
var control. control = .this.controls->at(--count);
|
||||
if control.callback.draw ~= null;
|
||||
fn[control.callback.draw](control, render);
|
||||
}
|
||||
if this.popup ~= null {
|
||||
var popup. control = this.popup;
|
||||
if popup.callback.draw ~= null;
|
||||
fn[popup.callback.draw](popup, render);
|
||||
}
|
||||
}
|
||||
|
||||
func wake() {
|
||||
proto fn(this void);
|
||||
forvar count size_t = this.controls->count(); count; {
|
||||
var control. control = .this.controls->at(--count);
|
||||
if control.callback.wake ~= null;
|
||||
fn[control.callback.wake](control);
|
||||
}
|
||||
if this.popup ~= null {
|
||||
var popup. control = this.popup;
|
||||
if popup.callback.wake ~= null;
|
||||
fn[popup.callback.wake](popup);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline set_parent(scene. scene) {
|
||||
this.parent = scene;
|
||||
}
|
||||
|
||||
inline get_parent() .scene {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
inline get_parent_t<T>() .T {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
inline set_parent_control(control. control) {
|
||||
this.parent_control = control;
|
||||
}
|
||||
|
||||
inline get_parent_control() .control {
|
||||
return this.parent_control;
|
||||
}
|
||||
|
||||
inline get_parent_control_t<T>() .T {
|
||||
return this.parent_control;
|
||||
}
|
||||
|
||||
inline get_window() .window {
|
||||
return this.parent->get_window();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline set_x(x int) { this.x = x; }
|
||||
inline set_y(y int) { this.y = y; }
|
||||
inline set_pos(x int, y int) { this.x = x, this.y = y; }
|
||||
inline set_width(width int) { this.width = width; }
|
||||
inline set_height(height int) { this.height = height; }
|
||||
inline set_size(width int, height int) {
|
||||
this.width = width,
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
inline get_x() int { return this.x; }
|
||||
inline get_y() int { return this.y; }
|
||||
inline get_width() int { return this.width; }
|
||||
inline get_height() int { return this.height; }
|
||||
inline get_right() int { return this.x + this.width; }
|
||||
inline get_bottom() int { return this.y + this.height; }
|
||||
inline get_rect() SDL_Rect {
|
||||
func.x = this.x,
|
||||
func.y = this.y,
|
||||
func.w = this.width,
|
||||
func.h = this.height;
|
||||
}
|
||||
|
||||
inline has_focus() bool { return this.focus; }
|
||||
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
|
||||
// SDL_GetTicks: This value wraps if the program runs for more than ~49 days.
|
||||
|
||||
class game+, delay {
|
||||
|
||||
private import lib::sdl2;
|
||||
|
||||
struct delay {
|
||||
duration uint32;
|
||||
t uint32;
|
||||
last_t uint32;
|
||||
done bool;
|
||||
}
|
||||
|
||||
inline init(duration uint32, done bool = false) {
|
||||
this.duration = duration;
|
||||
this.t = 0;
|
||||
this.last_t = 0;
|
||||
this.done = done;
|
||||
}
|
||||
|
||||
inline reset() {
|
||||
this.t = 0;
|
||||
this.last_t = 0;
|
||||
this.done = false;
|
||||
}
|
||||
|
||||
inline done() {
|
||||
this.done = true;
|
||||
}
|
||||
|
||||
inline done?() bool {
|
||||
return this.done;
|
||||
}
|
||||
|
||||
inline do() bool {
|
||||
if !this.done {
|
||||
this.last_t = SDL_GetTicks();
|
||||
if !this.t;
|
||||
this.t = this.last_t + this.duration;
|
||||
if this.t > this.last_t;
|
||||
return false;
|
||||
this.done = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline undo() {
|
||||
this.last_t = SDL_GetTicks();
|
||||
this.t = this.last_t + this.duration;
|
||||
this.done = false;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline get_duration() uint32 {
|
||||
return this.duration;
|
||||
}
|
||||
|
||||
inline set_duration(duration uint32) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
inline inc_duration(inc int32) {
|
||||
this.duration += inc;
|
||||
}
|
||||
|
||||
inline get_remain_t() uint32 {
|
||||
return this.t - this.last_t;
|
||||
}
|
||||
|
||||
inline get_per<T>(x T) T {
|
||||
return (float(this->get_remain_t()) / this.duration) * x;
|
||||
}
|
||||
|
||||
inline get_per_r<T>(x T) T {
|
||||
return x - this->get_per<T>(x);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
|
||||
class game+, fadeio {
|
||||
|
||||
private import rt::c, lib::sdl2;
|
||||
|
||||
struct fadeio {
|
||||
delay delay;
|
||||
texture texture;
|
||||
rect SDL_Rect;
|
||||
render void;
|
||||
done bool;
|
||||
r uint8;
|
||||
g uint8;
|
||||
b uint8;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
memset(this, 0, sizeof(fadeio));
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline init(wnd. window, duration uint32) {
|
||||
this.delay->init(duration);
|
||||
this.render = wnd->get_render();
|
||||
wnd->get_size(&this.rect.w, &this.rect.h);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline set_color(r uint8, g uint8, b uint8) {
|
||||
this.texture->destroy();
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
inline set_texture(texture void, auto_destroy bool = true) bool {
|
||||
if func = this.texture->init(texture, auto_destroy);
|
||||
this.texture->set_blend_mode(SDL_BLENDMODE_BLEND);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline done() {
|
||||
this.delay->done();
|
||||
}
|
||||
|
||||
inline reset() {
|
||||
this.delay->reset();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline do() bool {
|
||||
if func = this.delay->do() {
|
||||
if !this.done;
|
||||
this.texture->destroy(), this.done = true;
|
||||
else
|
||||
this->fade();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
private func fade() {
|
||||
var alpha uint8 = this.delay->get_per<uint8>(0xff);
|
||||
var texture void = this.texture->get_texture();
|
||||
if texture == null {
|
||||
SDL_SetRenderDrawBlendMode(this.render, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetRenderDrawColor(this.render, this.r, this.g, this.b, alpha);
|
||||
SDL_RenderFillRect(this.render, &this.rect);
|
||||
SDL_SetRenderDrawBlendMode(this.render, SDL_BLENDMODE_NONE);
|
||||
else
|
||||
this.texture->set_alpha_mod(alpha);
|
||||
this.texture->draw(this.render,
|
||||
this.rect.w - (this.rect.w + this.texture->get_width()) / 2,
|
||||
this.rect.h - (this.rect.h + this.texture->get_height()) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
|
||||
class game+, focus_map {
|
||||
|
||||
private import rt::c, lib::sdl2;
|
||||
|
||||
private alias vector = std::vector;
|
||||
|
||||
struct map {
|
||||
control. control;
|
||||
up. control;
|
||||
down. control;
|
||||
left. control;
|
||||
right. control;
|
||||
}
|
||||
|
||||
struct focus_map {
|
||||
map vector<map>;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
func register(control. control, up. control, down. control, left. control, right. control) {
|
||||
var map. map = this.map->new();
|
||||
map.control = control;
|
||||
map.up = up;
|
||||
map.down = down;
|
||||
map.left = left;
|
||||
map.right = right;
|
||||
}
|
||||
|
||||
func get(control. control, scancode SDL_Scancode) .control {
|
||||
var count size_t = this.map->count();
|
||||
while count {
|
||||
var map. map = this.map->at(--count);
|
||||
if map.control == control {
|
||||
if scancode == CPI_SCANCODE_UP {
|
||||
return map.up;
|
||||
elseif scancode == CPI_SCANCODE_DOWN;
|
||||
return map.down;
|
||||
elseif scancode == CPI_SCANCODE_LEFT;
|
||||
return map.left;
|
||||
elseif scancode == CPI_SCANCODE_RIGHT;
|
||||
return map.right;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
|
||||
class game+, font {
|
||||
|
||||
private import rt::c, lib::sdl2_ttf;
|
||||
|
||||
struct font {
|
||||
obj void;
|
||||
tex texture;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
this.obj = null;
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
this->close();
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
func open(font_name. char, size int) bool {
|
||||
this->close();
|
||||
if (this.obj = TTF_OpenFont(font_name, size)) == null {
|
||||
printf("TTF_OpenFont: %s\n", font_name);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
func close() {
|
||||
this.tex->destroy();
|
||||
if this.obj ~= null;
|
||||
TTF_CloseFont(this.obj), this.obj = null;
|
||||
}
|
||||
|
||||
// xxx
|
||||
inline get_width() int {
|
||||
return this.tex->get_width();
|
||||
}
|
||||
|
||||
inline get_height() int {
|
||||
return TTF_FontHeight(this.obj);
|
||||
}
|
||||
|
||||
inline get_line_skip() int {
|
||||
return TTF_FontLineSkip(this.obj);
|
||||
}
|
||||
|
||||
inline get_size(text. char, width. int, height. int) bool {
|
||||
return TTF_SizeUTF8(this.obj, text, width, height) == 0;
|
||||
}
|
||||
|
||||
func create_tex(render void, text. char, color uint32) void {
|
||||
var surface void = TTF_RenderUTF8_Solid(this.obj, text, color);
|
||||
if surface == null;
|
||||
return null;
|
||||
func = SDL_CreateTextureFromSurface(render, surface);
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
|
||||
// fixme
|
||||
func create_outlined_tex(render void, text. char, text_color uint32, outline_color uint32, outline_size int) void {
|
||||
TTF_SetFontOutline(this.obj, outline_size);
|
||||
var outline_texture. SDL_Surface = TTF_RenderUTF8_Solid(this.obj, text, outline_color);
|
||||
TTF_SetFontOutline(this.obj, 0);
|
||||
if outline_texture == null;
|
||||
return null;
|
||||
var text_texture. SDL_Surface = TTF_RenderUTF8_Solid(this.obj, text, text_color);
|
||||
if text_texture == null {
|
||||
SDL_FreeSurface(outline_texture);
|
||||
return null;
|
||||
}
|
||||
SDL_SetSurfaceBlendMode(outline_texture, SDL_BLENDMODE_BLEND);
|
||||
var rect SDL_Rect;
|
||||
rect.x = outline_size;
|
||||
rect.y = outline_size;
|
||||
rect.w = text_texture.w;
|
||||
rect.h = text_texture.h;
|
||||
SDL_BlitSurface(text_texture, null, outline_texture, &rect);
|
||||
func = SDL_CreateTextureFromSurface(render, outline_texture);
|
||||
SDL_FreeSurface(outline_texture);
|
||||
SDL_FreeSurface(text_texture);
|
||||
}
|
||||
|
||||
inline prepare(render void, text. char, color uint32) bool {
|
||||
return this.tex->init(this->create_tex(render, text, color));
|
||||
}
|
||||
|
||||
inline draw(render void, x int, y int) {
|
||||
this.tex->draw(render, x, y);
|
||||
}
|
||||
|
||||
inline draw2(render void, x int, y int, text. char, color uint32) {
|
||||
if this->prepare(render, text, color);
|
||||
this->draw(render, x, y);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
|
||||
class game+, norepeat {
|
||||
|
||||
struct norepeat {
|
||||
lock bool;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
this.lock = true;
|
||||
}
|
||||
|
||||
inline do() bool {
|
||||
if !this.lock {
|
||||
this.lock = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline set(lock bool = false) {
|
||||
this.lock = lock;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
|
||||
class game+, repeat {
|
||||
|
||||
private import lib::sdl2;
|
||||
|
||||
struct repeat {
|
||||
delay delay;
|
||||
duration int;
|
||||
inc int;
|
||||
count int;
|
||||
remains int;
|
||||
}
|
||||
|
||||
func init(duration uint32, inc int, count int) {
|
||||
this.delay->init(duration, true);
|
||||
this.duration = duration;
|
||||
this.inc = inc;
|
||||
this.count = count;
|
||||
this.remains = count;
|
||||
}
|
||||
|
||||
inline reset(done bool = true) {
|
||||
this.delay->init(this.duration, done);
|
||||
this.remains = this.count;
|
||||
}
|
||||
|
||||
inline do() bool {
|
||||
return this.delay->do();
|
||||
}
|
||||
|
||||
func undo() {
|
||||
if this.remains > 0 {
|
||||
this.remains--;
|
||||
this.delay->inc_duration(this.inc);
|
||||
}
|
||||
this.delay->undo();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
|
||||
class game+, scene+ {
|
||||
|
||||
private import rt::c;
|
||||
|
||||
private alias vector = std::vector;
|
||||
|
||||
struct scene {
|
||||
struct callback {
|
||||
update void;
|
||||
draw void;
|
||||
wake void;
|
||||
destructor void;
|
||||
}
|
||||
parent. window;
|
||||
name. char;
|
||||
controls vector<void>;
|
||||
focus_control. control;
|
||||
popup. control;
|
||||
closing_popup. control;
|
||||
pending_popup. control;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
memset(this, 0, sizeof(scene));
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
if this.popup ~= null;
|
||||
free_control(this.popup);
|
||||
if this.closing_popup ~= null;
|
||||
free_control(this.closing_popup);
|
||||
if this.pending_popup ~= null;
|
||||
free_control(this.pending_popup);
|
||||
forvar count size_t = this.controls->count(); count;;
|
||||
free_control(.this.controls->at(--count));
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline set_window(wnd. window) {
|
||||
this.parent = wnd;
|
||||
}
|
||||
|
||||
inline get_window() .window {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
inline set_name(name. char) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
inline get_name() .char {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline quit() bool {
|
||||
return this.parent->pop_scene() ~= null;
|
||||
}
|
||||
|
||||
// control
|
||||
|
||||
func new_control<T>(x int, y int, width int = 0, height int = 0, standalone bool = false) .T {
|
||||
func = malloc_t<T>();
|
||||
#if objectid(T).func.update;
|
||||
func.super.callback.update = T::update*;
|
||||
#endif
|
||||
#if objectid(T).func.draw;
|
||||
func.super.callback.draw = T::draw*;
|
||||
#endif
|
||||
#if objectid(T).func.wake;
|
||||
func.super.callback.wake = T::wake*;
|
||||
#endif
|
||||
#if objectid(T).func.destructor;
|
||||
func.super.callback.destructor = T::destructor*;
|
||||
#endif
|
||||
func->set_parent(this);
|
||||
func->set_pos(x, y);
|
||||
func->set_size(width, height);
|
||||
#if objectid(T).func.init;
|
||||
if !func->init(this.parent->get_render()) {
|
||||
printf("Failed to load \"%s\" control.\n", objectid(T).name);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
if !standalone;
|
||||
this.controls->push_back(func);
|
||||
}
|
||||
|
||||
inline create_control<T>(x int, y int, width int = 0, height int = 0) .T {
|
||||
return this->new_control<T>(x, y, width, height, true);
|
||||
}
|
||||
|
||||
static func free_control(control. control) {
|
||||
if control.callback.destructor ~= null {
|
||||
proto fn(this void);
|
||||
fn[control.callback.destructor](control);
|
||||
}
|
||||
free(control);
|
||||
}
|
||||
|
||||
// focus
|
||||
|
||||
func set_focus(control. control) {
|
||||
var prev. control = this.focus_control;
|
||||
if prev ~= null;
|
||||
prev.focus = false;
|
||||
this.focus_control = control, control.focus = true;
|
||||
}
|
||||
|
||||
inline get_focus() .control {
|
||||
return this.focus_control;
|
||||
}
|
||||
|
||||
// popup
|
||||
|
||||
func close_popup() {
|
||||
if this.popup ~= null {
|
||||
this.closing_popup = this.popup;
|
||||
this.popup = null;
|
||||
// xxx
|
||||
if this.callback.wake ~= null {
|
||||
proto fn(this void);
|
||||
fn[this.callback.wake](this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func set_popup(control. control) {
|
||||
if this.popup == null and this.closing_popup == null {
|
||||
this.popup = control;
|
||||
else
|
||||
if this.pending_popup ~= null;
|
||||
free_control(this.pending_popup);
|
||||
this.pending_popup = control;
|
||||
}
|
||||
}
|
||||
|
||||
func has_popup() bool {
|
||||
if this.popup ~= null or
|
||||
this.closing_popup ~= null or
|
||||
this.pending_popup ~= null {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
func update(render void) {
|
||||
proto fn(this void, render void);
|
||||
if this.closing_popup ~= null;
|
||||
free_control(this.closing_popup), this.closing_popup = null;
|
||||
if this.pending_popup ~= null {
|
||||
if this.popup ~= null;
|
||||
free_control(this.popup);
|
||||
this.popup = this.pending_popup;
|
||||
this.pending_popup = null;
|
||||
}
|
||||
// xxx
|
||||
if this.popup == null {
|
||||
forvar count size_t = this.controls->count(); count; {
|
||||
var control. control = .this.controls->at(--count);
|
||||
if control.callback.update ~= null;
|
||||
fn[control.callback.update](control, render);
|
||||
}
|
||||
else
|
||||
var popup. control = this.popup;
|
||||
if popup.callback.update ~= null;
|
||||
fn[popup.callback.update](popup, render);
|
||||
}
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
proto fn(this void, render void);
|
||||
forvar count size_t = this.controls->count(); count; {
|
||||
var control. control = .this.controls->at(--count);
|
||||
if control.callback.draw ~= null;
|
||||
fn[control.callback.draw](control, render);
|
||||
}
|
||||
if this.popup ~= null {
|
||||
var popup. control = this.popup;
|
||||
if popup.callback.draw ~= null;
|
||||
fn[popup.callback.draw](popup, render);
|
||||
}
|
||||
}
|
||||
|
||||
func wake() {
|
||||
proto fn(this void);
|
||||
forvar count size_t = this.controls->count(); count; {
|
||||
var control. control = .this.controls->at(--count);
|
||||
if control.callback.wake ~= null;
|
||||
fn[control.callback.wake](control);
|
||||
}
|
||||
if this.popup ~= null {
|
||||
var popup. control = this.popup;
|
||||
if popup.callback.wake ~= null;
|
||||
fn[popup.callback.wake](popup);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
|
||||
class game+, small_font {
|
||||
|
||||
private import rt::c, lib::sdl2;
|
||||
|
||||
struct small_font {
|
||||
textures(13) texture;
|
||||
font_width int;
|
||||
font_height int;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this);
|
||||
this.font_width = 0;
|
||||
this.font_height = 0;
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
func init(render void, font_width int, font_height int, filename. char) bool {
|
||||
var tex texture;
|
||||
if !tex->load_file(render, filename);
|
||||
return false;
|
||||
if tex->get_width() ~= (font_width * 13) or tex->get_height() ~= font_height;
|
||||
return false;
|
||||
forvar i int = 0; i < 13; i++;
|
||||
this.textures[i]->init(tex->clone_tex(render, i * font_width, 0, font_width, font_height, SDL_BLENDMODE_BLEND));
|
||||
this.font_width = font_width;
|
||||
this.font_height = font_height;
|
||||
return true;
|
||||
}
|
||||
|
||||
func draw_cap(render void, x int, y int, cap uint) {
|
||||
var str(8) char;
|
||||
forvar index int = 0, count int = snprintf(&str, 8, "%u", cap); index < count; index++ {
|
||||
this.textures[str[index] - '0']->draw(render, x, y);
|
||||
x += this.font_width;
|
||||
}
|
||||
this.textures[10]->draw(render, x, y);
|
||||
}
|
||||
|
||||
func draw_time(render void, x int, y int, t time_t, draw_colon bool = true) {
|
||||
var tm. struct_tm = localtime(&t);
|
||||
if !tm.tm_hour {
|
||||
tm.tm_hour = 12;
|
||||
elseif tm.tm_hour > 12;
|
||||
tm.tm_hour -= 12;
|
||||
}
|
||||
var str(8) char;
|
||||
forvar index int = 0, count int =
|
||||
sprintf(&str, "%u:%02u",
|
||||
tm.tm_hour,
|
||||
tm.tm_min); index < count; index++ {
|
||||
var c char = str[index];
|
||||
if isdigit(c) {
|
||||
this.textures[c - '0']->draw(render, x, y);
|
||||
elseif draw_colon;
|
||||
this.textures[11]->draw(render, x, y);
|
||||
}
|
||||
x += this.font_width;
|
||||
}
|
||||
}
|
||||
|
||||
func draw_page(render void, x int, y int, cur uint, last uint) {
|
||||
var str(16) char;
|
||||
forvar index int = 0, count int = snprintf(&str, 16, "%u/%u", cur, last); index < count; index++ {
|
||||
var c char = str[index];
|
||||
if isdigit(c) {
|
||||
this.textures[c - '0']->draw(render, x, y);
|
||||
else
|
||||
this.textures[12]->draw(render, x, y);
|
||||
}
|
||||
x += this.font_width;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
|
||||
class game+, texture {
|
||||
|
||||
private import
|
||||
rt::c,
|
||||
lib::sdl2,
|
||||
lib::sdl2_image;
|
||||
|
||||
struct texture {
|
||||
obj void;
|
||||
format uint32;
|
||||
width int;
|
||||
height int;
|
||||
auto_destroy bool;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
memset(this, 0, sizeof(texture));
|
||||
this.auto_destroy = true;
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
this->destroy();
|
||||
}
|
||||
|
||||
func destroy() {
|
||||
if this.auto_destroy {
|
||||
if this.obj ~= null;
|
||||
SDL_DestroyTexture(this.obj);
|
||||
}
|
||||
this.obj = null;
|
||||
this.width = 0;
|
||||
this.height = 0;
|
||||
}
|
||||
|
||||
func init(texture void, auto_destroy bool = true) bool {
|
||||
this->destroy();
|
||||
if texture == null {
|
||||
return false;
|
||||
}
|
||||
if SDL_QueryTexture(texture, &this.format, null, &this.width, &this.height);
|
||||
return false;
|
||||
this.obj = texture;
|
||||
this.auto_destroy = auto_destroy;
|
||||
return true;
|
||||
}
|
||||
|
||||
func load_file(render void, filename. char) bool {
|
||||
this->destroy();
|
||||
if (this.obj = IMG_LoadTexture(render, filename)) == null {
|
||||
printf("IMG_LoadTexture: %s\n", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
if SDL_QueryTexture(this.obj, &this.format, null, &this.width, &this.height) {
|
||||
this->destroy();
|
||||
return false;
|
||||
}
|
||||
this.auto_destroy = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
func load_file_with_colorkey(render void, filename. char, r uint8, g uint8, b uint8) bool {
|
||||
var surface. SDL_Surface = IMG_Load(filename);
|
||||
if surface == null {
|
||||
printf("IMG_Load: %s\n", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
if SDL_SetColorKey(surface, SDL_RLEACCEL, SDL_MapRGB(surface.format, r, g, b)) {
|
||||
SDL_FreeSurface(surface);
|
||||
return false;
|
||||
}
|
||||
var texture void = SDL_CreateTextureFromSurface(render, surface);
|
||||
SDL_FreeSurface(surface);
|
||||
if texture == null;
|
||||
return false;
|
||||
return this->init(texture);
|
||||
}
|
||||
|
||||
func clone_tex(render void, x int, y int, width int, height int, blend_mode SDL_BlendMode = SDL_BLENDMODE_NONE) void {
|
||||
if this.obj == null;
|
||||
return null;
|
||||
if (func = SDL_CreateTexture(render, this.format, SDL_TEXTUREACCESS_TARGET, width, height)) == null;
|
||||
return;
|
||||
SDL_SetRenderTarget(render, func);
|
||||
SDL_SetTextureBlendMode(func, blend_mode);
|
||||
SDL_RenderCopy(render, this.obj,
|
||||
&global::make_rect(x, y, width, height),
|
||||
&global::make_rect(0, 0, width, height));
|
||||
SDL_SetRenderTarget(render, null);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline draw(render void, x int, y int) {
|
||||
SDL_RenderCopy(render, this.obj, null,
|
||||
&this->make_rect(x, y));
|
||||
}
|
||||
|
||||
inline draw2(render void, x int, y int, width int, height int) {
|
||||
SDL_RenderCopy(render, this.obj,
|
||||
&global::make_rect(0, 0, width, height),
|
||||
&global::make_rect(x, y, width, height));
|
||||
}
|
||||
|
||||
inline draw3(render void, x int, y int, width int, height int) {
|
||||
SDL_RenderCopy(render, this.obj, &this->make_rect(0, 0),
|
||||
&global::make_rect(x, y, width, height));
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline make_rect(x int, y int) SDL_Rect {
|
||||
func.x = x,
|
||||
func.y = y,
|
||||
func.w = this.width,
|
||||
func.h = this.height;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline get_texture() void {
|
||||
return this.obj;
|
||||
}
|
||||
|
||||
inline get_width() int {
|
||||
return this.width;
|
||||
}
|
||||
|
||||
inline get_height() int {
|
||||
return this.height;
|
||||
}
|
||||
|
||||
inline get_blend_mode() SDL_BlendMode {
|
||||
if SDL_GetTextureBlendMode(this.obj, &func);
|
||||
func = SDL_BLENDMODE_INVALID;
|
||||
}
|
||||
|
||||
inline set_blend_mode(mode SDL_BlendMode) int {
|
||||
return SDL_SetTextureBlendMode(this.obj, mode);
|
||||
}
|
||||
|
||||
inline get_alpha_mod() uint8 {
|
||||
if SDL_GetTextureAlphaMod(this.obj, &func);
|
||||
func = 0;
|
||||
}
|
||||
|
||||
inline set_alpha_mod(alpha uint8) int {
|
||||
return SDL_SetTextureAlphaMod(this.obj, alpha);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,312 +0,0 @@
|
||||
|
||||
class game+, window {
|
||||
|
||||
private import rt::c, lib::sdl2, lib::sdl2_image;
|
||||
|
||||
private alias
|
||||
string = std::string,
|
||||
vector_ptr = std::vector_ptr;
|
||||
|
||||
struct window {
|
||||
wnd void;
|
||||
render void;
|
||||
scenes vector_ptr<scene>;
|
||||
garbage vector_ptr<scene>;
|
||||
current_scene. scene;
|
||||
pending_scene. scene;
|
||||
turbo uint32;
|
||||
quit bool;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
memset(this, 0, sizeof(window));
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
if this.current_scene ~= null;
|
||||
this->safe_free_scene(this.current_scene);
|
||||
if this.pending_scene ~= null;
|
||||
this->safe_free_scene(this.pending_scene);
|
||||
using count size_t = this.scenes->count() {
|
||||
while count {
|
||||
this->free_scene_internal(this.scenes->at(--count));
|
||||
}
|
||||
}
|
||||
this->dump();
|
||||
if this.render ~= null;
|
||||
SDL_DestroyRenderer(this.render);
|
||||
if this.wnd ~= null;
|
||||
SDL_DestroyWindow(this.wnd);
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
func create_wnd(title. char, w int, h int,
|
||||
x int = SDL_WINDOWPOS_UNDEFINED,
|
||||
y int = SDL_WINDOWPOS_UNDEFINED) bool {
|
||||
if (this.wnd = SDL_CreateWindow(title, x, y, w, h,
|
||||
SDL_WINDOW_FULLSCREEN |
|
||||
SDL_WINDOW_OPENGL |
|
||||
SDL_WINDOW_SHOWN)) == null;
|
||||
return false;
|
||||
if (this.render = SDL_CreateRenderer(this.wnd, -1,
|
||||
SDL_RENDERER_ACCELERATED |
|
||||
SDL_RENDERER_TARGETTEXTURE)) == null {
|
||||
SDL_DestroyWindow(this.wnd), this.wnd = null;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// scene
|
||||
|
||||
func new_scene<T>() .T {
|
||||
func = malloc_t<T>();
|
||||
#if objectid(T).func.update;
|
||||
func.super.callback.update = T::update*;
|
||||
#endif
|
||||
#if objectid(T).func.draw;
|
||||
func.super.callback.draw = T::draw*;
|
||||
#endif
|
||||
#if objectid(T).func.wake;
|
||||
func.super.callback.wake = T::wake*;
|
||||
#endif
|
||||
#if objectid(T).func.destructor;
|
||||
func.super.callback.destructor = T::destructor*;
|
||||
#endif
|
||||
func->set_window(this);
|
||||
func->set_name(objectid(T).name);
|
||||
#if objectid(T).func.init;
|
||||
if !func->init(this.render) {
|
||||
printf("Failed to load \"%s\" scene.\n", objectid(T).name);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static func free_scene_internal(scene. scene) {
|
||||
if scene.callback.destructor ~= null {
|
||||
proto fn(this void);
|
||||
fn[scene.callback.destructor](scene);
|
||||
}
|
||||
free(scene);
|
||||
}
|
||||
|
||||
inline free_scene(scene. scene) {
|
||||
this.garbage->push_back(scene);
|
||||
}
|
||||
|
||||
func safe_free_scene(scene. scene) {
|
||||
var count size_t = this.scenes->count();
|
||||
while count {
|
||||
if this.scenes->at(--count) == scene {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this->free_scene(scene);
|
||||
}
|
||||
|
||||
inline push_scene(scene. scene) {
|
||||
this.scenes->push_back(scene);
|
||||
}
|
||||
|
||||
inline get_last_scene() .scene {
|
||||
if this.scenes->empty();
|
||||
return null;
|
||||
return this.scenes->back();
|
||||
}
|
||||
|
||||
inline pop_scene() .scene {
|
||||
if this.scenes->empty();
|
||||
return null;
|
||||
this->set_scene(func = this.scenes->back());
|
||||
this.scenes->pop_back();
|
||||
if func.callback.wake ~= null {
|
||||
proto fn(this void);
|
||||
fn[func.callback.wake](func);
|
||||
}
|
||||
}
|
||||
|
||||
func set_scene(scene. scene) {
|
||||
if this.current_scene == null {
|
||||
this.current_scene = scene;
|
||||
else
|
||||
if this.pending_scene ~= null;
|
||||
this->safe_free_scene(this.pending_scene);
|
||||
this.pending_scene = scene;
|
||||
}
|
||||
}
|
||||
|
||||
inline set_new_scene<T>() {
|
||||
this->set_scene(this->new_scene<T>());
|
||||
}
|
||||
|
||||
private inline swap_scene() {
|
||||
if this.pending_scene ~= null {
|
||||
if this.current_scene ~= null;
|
||||
this->safe_free_scene(this.current_scene);
|
||||
this.current_scene = this.pending_scene;
|
||||
this.pending_scene = null;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline dump() {
|
||||
var count size_t = this.garbage->count();
|
||||
while count {
|
||||
this->free_scene_internal(this.garbage->at(--count));
|
||||
}
|
||||
this.garbage->clear();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline update() {
|
||||
var scene. scene = this.current_scene;
|
||||
if scene.callback.update ~= null {
|
||||
proto fn(this void, render void);
|
||||
fn[scene.callback.update](scene, this.render);
|
||||
}
|
||||
}
|
||||
|
||||
inline draw() {
|
||||
var scene. scene = this.current_scene;
|
||||
if scene.callback.draw ~= null {
|
||||
proto fn(this void, render void);
|
||||
fn[scene.callback.draw](scene, this.render);
|
||||
}
|
||||
}
|
||||
|
||||
inline present() {
|
||||
SDL_RenderPresent(this.render);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline enable_turbo(ms int) {
|
||||
this.turbo = SDL_GetTicks() + ms;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline quit() {
|
||||
this.quit = true;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
func on_keydown(event. SDL_KeyboardEvent) {
|
||||
if !event.repeat {
|
||||
if event.keysym.scancode == CPI_SCANCODE_SHIFT_START {
|
||||
var surface void = this->screen_capture_to_surface2();
|
||||
if surface ~= null {
|
||||
var tm. struct_tm = localtime(&time(null));
|
||||
var filename string;
|
||||
IMG_SavePNG(surface, filename->format("screenshots/%04d-%02d-%02d-%02d_%02d_%02d_%04d.png",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, random<int>(10000)));
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
func game_loop() {
|
||||
this->enable_turbo(8000);
|
||||
while !this.quit {
|
||||
var event SDL_Event;
|
||||
while SDL_PollEvent(&event) {
|
||||
if event.type == SDL_KEYDOWN {
|
||||
this->on_keydown(&event.key);
|
||||
this->enable_turbo(3000);
|
||||
elseif event.type == SDL_QUIT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this->update();
|
||||
if this.pending_scene == null {
|
||||
this->draw();
|
||||
this->present();
|
||||
}
|
||||
this->swap_scene();
|
||||
this->dump();
|
||||
if this.turbo < SDL_GetTicks() {
|
||||
forvar standby uint32 = SDL_GetTicks() + 300 ;; {
|
||||
if SDL_PollEvent(&event) {
|
||||
if event.type == SDL_KEYDOWN {
|
||||
this->on_keydown(&event.key);
|
||||
this->enable_turbo(3000);
|
||||
break;
|
||||
elseif event.type == SDL_QUIT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if SDL_GetTicks() > standby;
|
||||
break;
|
||||
usleep(50000);
|
||||
}
|
||||
else
|
||||
usleep(3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline get_handle() void {
|
||||
return this.wnd;
|
||||
}
|
||||
|
||||
inline get_render() void {
|
||||
return this.render;
|
||||
}
|
||||
|
||||
inline get_scene() .scene {
|
||||
return this.scene;
|
||||
}
|
||||
|
||||
inline get_size(w. int, h. int) {
|
||||
SDL_GetWindowSize(this.wnd, w, h);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
func screen_capture_to_surface(rect. SDL_Rect) void {
|
||||
var format uint32 = SDL_GetWindowPixelFormat(this.wnd);
|
||||
var surface. SDL_Surface = SDL_CreateRGBSurfaceWithFormat(0, rect.w, rect.h, 24, format);
|
||||
if surface == null;
|
||||
return null;
|
||||
if SDL_LockSurface(surface) {
|
||||
SDL_FreeSurface(surface);
|
||||
return null;
|
||||
}
|
||||
SDL_RenderReadPixels(this.render, rect, format, surface.pixels, surface.pitch);
|
||||
SDL_UnlockSurface(surface);
|
||||
return surface;
|
||||
}
|
||||
|
||||
func screen_capture_to_surface2() void {
|
||||
var rect SDL_Rect = 0;
|
||||
this->get_size(&rect.w, &rect.h);
|
||||
return this->screen_capture_to_surface(&rect);
|
||||
}
|
||||
|
||||
func screen_capture(rect. SDL_Rect) void {
|
||||
var surface void = this->screen_capture_to_surface(rect);
|
||||
if surface == null;
|
||||
return null;
|
||||
func = SDL_CreateTextureFromSurface(this.render, surface);
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
|
||||
func screen_capture2() void {
|
||||
var surface void = this->screen_capture_to_surface2();
|
||||
if surface == null;
|
||||
return null;
|
||||
func = SDL_CreateTextureFromSurface(this.render, surface);
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
|
||||
module game+, global {
|
||||
|
||||
private import rt::c, lib::sdl2;
|
||||
|
||||
private alias
|
||||
string = std::string,
|
||||
strings = std::strings;
|
||||
|
||||
var config cfg;
|
||||
|
||||
var skin_dir string;
|
||||
|
||||
var apps app_list;
|
||||
|
||||
var wifi wifi;
|
||||
|
||||
// deprecated
|
||||
var outlined_font bool = false;
|
||||
|
||||
var uni_font font;
|
||||
|
||||
var small_font small_font;
|
||||
|
||||
//
|
||||
|
||||
func init(render void) bool {
|
||||
if !config->open("bean.cfg");
|
||||
return false;
|
||||
if config->find("skin") == null;
|
||||
config->add("skin", "default");
|
||||
if config->find("font") == null;
|
||||
config->add("font", "unifont-12.0.01.ttf");
|
||||
// deprecated
|
||||
using value. char = config->get("outlined_font") {
|
||||
if value ~= null and !strcasecmp(value, "true") {
|
||||
outlined_font = true;
|
||||
}
|
||||
}
|
||||
skin_dir->format("skins/%s",
|
||||
config->get("skin"));
|
||||
if !apps->init("bean.db");
|
||||
return false;
|
||||
if !wifi->init();
|
||||
return false;
|
||||
var filename string;
|
||||
if !uni_font->open(filename->format("fonts/%s", config->get("font")), 16);
|
||||
return false;
|
||||
small_font->init(render, 10, 12,
|
||||
make_path("small_font_10x12.png"));
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
func make_path(filename. char) .char {
|
||||
static path string;
|
||||
return path->format("%s/%s",
|
||||
skin_dir->ptr(), filename);
|
||||
}
|
||||
|
||||
inline make_rect(x int, y int, width int, height int) SDL_Rect {
|
||||
func.x = x,
|
||||
func.y = y,
|
||||
func.w = width,
|
||||
func.h = height;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
func get_backlight_level() byte {
|
||||
func = -1;
|
||||
var stream void = fopen(CPI_BACKLIGHT, "r");
|
||||
if stream ~= null {
|
||||
if fread(&func, 1, 1, stream) == 1;
|
||||
func -= '0';
|
||||
fclose(stream);
|
||||
}
|
||||
}
|
||||
|
||||
func set_backlight_level(level byte) bool {
|
||||
var stream void = fopen(CPI_BACKLIGHT, "w");
|
||||
if stream ~= null {
|
||||
defer fclose(stream);
|
||||
level += '0';
|
||||
if fwrite(&level, 1, 1, stream) == 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
func get_battery_cap() int {
|
||||
var lines strings;
|
||||
if lines->load_file(CPI_BATTERY) <= 0;
|
||||
return -1;
|
||||
var strs strings;
|
||||
func = 0;
|
||||
forvar index size_t = 0, count size_t = lines->count(); index < count; index++ {
|
||||
var line. char = lines->item(index);
|
||||
if strstr(line, "POWER_SUPPLY_STATUS=") ~= null {
|
||||
if strs->split(line, "=") == 2 {
|
||||
if !strcasecmp(strs->item(1), "Charging");
|
||||
func = 0x100;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
forvar index size_t = 0, count size_t = lines->count(); index < count; index++ {
|
||||
var line. char = lines->item(index);
|
||||
if strstr(line, "POWER_SUPPLY_CAPACITY=") ~= null {
|
||||
strs->clear();
|
||||
if strs->split(line, "=") == 2;
|
||||
return func | atoi(strs->item(1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
class game+, launcher {
|
||||
|
||||
private import lib::sdl2;
|
||||
|
||||
struct launcher {
|
||||
wnd window;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this); }
|
||||
func destructor() {
|
||||
destructor(this); }
|
||||
|
||||
func start(title. char) bool {
|
||||
if !this.wnd->create_wnd(title, CPI_WIDTH, CPI_HEIGHT);
|
||||
return false;
|
||||
if !global::init(this.wnd->get_render());
|
||||
return false;
|
||||
this.wnd->set_new_scene<scene::intro>();
|
||||
this.wnd->game_loop();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,699 +0,0 @@
|
||||
|
||||
/*
|
||||
set_callback(on_select void, on_close void, arg void)
|
||||
set_fadeout(fadeout. fadeio)
|
||||
set_ext(ext. char)
|
||||
set_dir(render void, dir_name. char) bool
|
||||
refresh(render void) bool
|
||||
set_mode(mode mode)
|
||||
set_exec_format(format. char)
|
||||
hidden_files(visible bool)
|
||||
cursor_to(name. char) bool
|
||||
goto_parent_dir(render void) bool
|
||||
get_dir_count() size_t
|
||||
get_file_count() size_t
|
||||
get_all_count() size_t
|
||||
get_path() .char
|
||||
close()
|
||||
*/
|
||||
|
||||
class game+, scene+, file_browser {
|
||||
|
||||
inherit game::scene = super;
|
||||
|
||||
private import rt::c, lib::sdl2;
|
||||
|
||||
private alias
|
||||
string = std::string,
|
||||
strings = std::strings,
|
||||
vector = std::vector;
|
||||
|
||||
private alias popup_menu = control::popup_menu;
|
||||
|
||||
enum mode {
|
||||
browse,
|
||||
select,
|
||||
select_file,
|
||||
select_dir,
|
||||
select_image,
|
||||
exec
|
||||
}
|
||||
|
||||
struct file {
|
||||
icon texture;
|
||||
black_font texture;
|
||||
white_font texture;
|
||||
link bool;
|
||||
type uchar;
|
||||
str(NAME_MAX) char;
|
||||
}
|
||||
|
||||
struct file_browser {
|
||||
struct tex {
|
||||
dir texture;
|
||||
reg texture;
|
||||
lnk texture;
|
||||
name texture;
|
||||
image texture;
|
||||
empty texture;
|
||||
}
|
||||
fadeio fadeio;
|
||||
fadeout. fadeio;
|
||||
image_timer delay;
|
||||
input_delay repeat;
|
||||
input_lock norepeat;
|
||||
root string;
|
||||
path string;
|
||||
ext strings;
|
||||
dirs vector<file>;
|
||||
files vector<file>;
|
||||
on_select void;
|
||||
on_close void;
|
||||
arg void;
|
||||
cursor int;
|
||||
start_index int;
|
||||
exec_format string;
|
||||
mode mode;
|
||||
hidden_files bool;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
memset(this, 0, sizeof(file_browser));
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
define {
|
||||
TOP_HEIGHT = 23;
|
||||
ITEM_HEIGHT = 25;
|
||||
SCROLL_WIDTH = 8;
|
||||
SCROLL_HEIGHT = 80;
|
||||
}
|
||||
|
||||
func init(render void) bool {
|
||||
this.tex.dir->load_file(render,
|
||||
global::make_path("file_browser/dir.png"));
|
||||
this.tex.reg->load_file(render,
|
||||
global::make_path("file_browser/reg.png"));
|
||||
this.tex.lnk->load_file(render,
|
||||
global::make_path("file_browser/lnk.png"));
|
||||
this.tex.empty->init(
|
||||
global::uni_font->create_tex(render, "Empty", 0xff000000));
|
||||
var wnd. window = this->get_window();
|
||||
this.fadeio->init(wnd, 300);
|
||||
this.fadeio->set_texture(wnd->screen_capture2());
|
||||
this.image_timer->init(300);
|
||||
this.input_delay->init(300, -48, 6);
|
||||
this.exec_format->set("%s");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
on_select = lambda(filename. char, arg void) [
|
||||
|
||||
];
|
||||
on_close = lambda(arg void) [
|
||||
|
||||
];
|
||||
*/
|
||||
inline set_callback(on_select void, on_close void, arg void) {
|
||||
this.on_select = on_select;
|
||||
this.on_close = on_close;
|
||||
this.arg = arg;
|
||||
}
|
||||
|
||||
inline set_fadeout(fadeout. fadeio) {
|
||||
this.fadeout = fadeout;
|
||||
}
|
||||
|
||||
private inline reload_image() {
|
||||
this.tex.image->destroy();
|
||||
this.image_timer->reset();
|
||||
}
|
||||
|
||||
/*
|
||||
slow
|
||||
*/
|
||||
private static func sort(items. vector<file>) {
|
||||
forvar i int = 0, c int = items->count() - 1; i < c; i++ {
|
||||
forvar j int = 0; j < c - i; j++ {
|
||||
var x. file = items->at(j);
|
||||
var y. file = items->at(j + 1);
|
||||
if strcmp(&x.str, &y.str) > 0 {
|
||||
var tmp $file = .x;
|
||||
.x = .y;
|
||||
.y = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func set_ext(ext. char) {
|
||||
this.ext->clear();
|
||||
this.ext->split(ext, ",");
|
||||
}
|
||||
|
||||
private func is_allow_ext(filename. char) bool {
|
||||
if this.ext->empty();
|
||||
return true;
|
||||
var extension. char = strrchr(filename, '.');
|
||||
if extension == null {
|
||||
extension = "?";
|
||||
else
|
||||
extension++;
|
||||
}
|
||||
var count size_t = this.ext->count();
|
||||
while count {
|
||||
if !strcasecmp(this.ext->item(--count), extension);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
func set_dir(render void, dir_name. char, root bool = false) bool {
|
||||
var dir void = opendir(dir_name);
|
||||
if dir == null;
|
||||
return false;
|
||||
this.tex.name->init(
|
||||
global::uni_font->create_tex(render, dir_name, 0xffffffff));
|
||||
this.path->set(dir_name);
|
||||
while this.path->len() > 1 and
|
||||
this.path->ends_with('/');
|
||||
this.path->remove_back();
|
||||
if root;
|
||||
this.root->set(this.path->ptr());
|
||||
this.dirs->clear();
|
||||
this.files->clear();
|
||||
this.cursor = 0;
|
||||
this.start_index = 0;
|
||||
using ent. struct_dirent {
|
||||
while (ent = readdir(dir)) ~= null {
|
||||
var file. file;
|
||||
var link bool = false;
|
||||
if ent.d_type == DT_LNK {
|
||||
var str string;
|
||||
var path. char = realpath(str->format("%s/%s", this.path->ptr(), &ent.d_name), null);
|
||||
if path == null;
|
||||
continue;
|
||||
defer free(path);
|
||||
var st struct_stat;
|
||||
if stat(path, &st);
|
||||
continue;
|
||||
if S_ISDIR(st.st_mode) {
|
||||
ent.d_type = DT_DIR;
|
||||
elseif S_ISREG(st.st_mode);
|
||||
ent.d_type = DT_REG;
|
||||
else
|
||||
ent.d_type = DT_UNKNOWN;
|
||||
}
|
||||
link = true;
|
||||
}
|
||||
if this.hidden_files and ent.d_name[0] == '.' {
|
||||
continue;
|
||||
}
|
||||
if ent.d_type == DT_DIR {
|
||||
if ent.d_name[0] == '.' and !ent.d_name[1] or
|
||||
ent.d_name[1] == '.' and !ent.d_name[2] {
|
||||
file = null;
|
||||
else
|
||||
file = this.dirs->new();
|
||||
file.icon->init(this.tex.dir->get_texture(), false);
|
||||
}
|
||||
elseif ent.d_type == DT_REG;
|
||||
if this->is_allow_ext(&ent.d_name) {
|
||||
file = this.files->new();
|
||||
file.icon->init(this.tex.reg->get_texture(), false);
|
||||
else
|
||||
file = null;
|
||||
}
|
||||
else
|
||||
file = null;
|
||||
}
|
||||
if file ~= null {
|
||||
file.link = link;
|
||||
file.type = ent.d_type;
|
||||
strcpy(&file.str, &ent.d_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
this->sort(&this.dirs);
|
||||
this->sort(&this.files);
|
||||
this->reload_image();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline refresh(render void) bool {
|
||||
return this->set_dir(render, this.path->ptr());
|
||||
}
|
||||
|
||||
inline set_mode(mode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
inline set_exec_format(format. char) {
|
||||
this.exec_format->set(format);
|
||||
}
|
||||
|
||||
inline hidden_files(visible bool) {
|
||||
this.hidden_files = visible;
|
||||
}
|
||||
|
||||
func cursor_to(name. char) bool {
|
||||
forvar index size_t = 0, count size_t = this.dirs->count(); index < count; index++ {
|
||||
if !strcmp(&this.dirs->at(index).str, name) {
|
||||
this.cursor = index;
|
||||
this->update_scroll();
|
||||
this->reload_image();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
forvar index size_t = 0, count size_t = this.files->count(); index < count; index++ {
|
||||
if !strcmp(&this.files->at(index).str, name) {
|
||||
this.cursor = this.dirs->count() + index;
|
||||
this->update_scroll();
|
||||
this->reload_image();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
func goto_parent_dir(render void) bool {
|
||||
if this.path->empty();
|
||||
return false;
|
||||
var path string;
|
||||
path->set(this.path->ptr());
|
||||
while path->ends_with('/');
|
||||
path->remove_back();
|
||||
if path->empty();
|
||||
return true;
|
||||
/*
|
||||
fixme
|
||||
*/
|
||||
if !strcmp(path->ptr(), this.root->ptr()) {
|
||||
this->close();
|
||||
return true;
|
||||
}
|
||||
var slash. char = strrchr(path->ptr(), '/');
|
||||
if slash == null;
|
||||
return false;
|
||||
var cur_dir string;
|
||||
cur_dir->set(slash + 1);
|
||||
if slash == path->ptr() {
|
||||
path->set("/");
|
||||
else
|
||||
path->set(path->ptr(), slash - path->ptr());
|
||||
}
|
||||
if func = this->set_dir(render, path->ptr()) {
|
||||
if !cur_dir->empty() {
|
||||
this->cursor_to(cur_dir->ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline get_dir_count() size_t {
|
||||
return this.dirs->count();
|
||||
}
|
||||
|
||||
inline get_file_count() size_t {
|
||||
return this.files->count();
|
||||
}
|
||||
|
||||
inline get_all_count() size_t {
|
||||
return this.dirs->count() + this.files->count();
|
||||
}
|
||||
|
||||
inline get_path() .char {
|
||||
return this.path->ptr();
|
||||
}
|
||||
|
||||
private func get_selected_file() .file {
|
||||
var cursor int = this.cursor;
|
||||
var dir_count size_t = this.dirs->count();
|
||||
if dir_count and cursor < dir_count {
|
||||
return this.dirs->at(cursor);
|
||||
else
|
||||
if (cursor -= dir_count) < this.files->count();
|
||||
return this.files->at(cursor);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
func close() {
|
||||
if this.on_close ~= null {
|
||||
proto fn(arg void);
|
||||
fn[this.on_close](this.arg);
|
||||
}
|
||||
if this.fadeout ~= null {
|
||||
this.fadeout->set_texture(this->get_window()->screen_capture2());
|
||||
this.fadeout->reset();
|
||||
}
|
||||
this->quit();
|
||||
}
|
||||
|
||||
private func select(filename. char) {
|
||||
if this.on_select ~= null {
|
||||
proto fn(filename. char, arg void);
|
||||
fn[this.on_select](filename, this.arg);
|
||||
}
|
||||
this->close();
|
||||
}
|
||||
|
||||
private func exec(filename. char) {
|
||||
var str string;
|
||||
exec3(this->get_window(), "Please Wait",
|
||||
str->format(this.exec_format->ptr(), filename));
|
||||
}
|
||||
|
||||
private func action(render void) {
|
||||
var file. file = this->get_selected_file();
|
||||
if file ~= null {
|
||||
if file.type == DT_DIR {
|
||||
var new_path string;
|
||||
new_path->set(this.path->ptr());
|
||||
while new_path->ends_with('/');
|
||||
new_path->remove_back();
|
||||
this->set_dir(render,
|
||||
new_path->appendf("/%s", &file.str));
|
||||
elseif file.type == DT_REG;
|
||||
if this.mode == mode.select or
|
||||
this.mode == mode.select_file or
|
||||
this.mode == mode.select_image {
|
||||
var filename string;
|
||||
this->select(filename->format("%s/%s",
|
||||
this->get_path(), &file.str));
|
||||
elseif this.mode == mode.exec;
|
||||
var filename string;
|
||||
this->exec(filename->format("%s/%s",
|
||||
this->get_path(), &file.str));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func show_popup(render void, file. file) {
|
||||
// MENU_COPY
|
||||
// MENU_PASTE
|
||||
define {
|
||||
MENU_REFRESH = 1;
|
||||
MENU_EXECUTE = 2;
|
||||
MENU_SELECT = 3;
|
||||
MENU_LINK = 4;
|
||||
MENU_DELETE = 5;
|
||||
MENU_EXIT = 6;
|
||||
}
|
||||
this->close_popup();
|
||||
var popup. popup_menu = this->create_control<popup_menu>(0, 0);
|
||||
popup->set_callback(
|
||||
lambda(id int, this.file_browser) [
|
||||
if id == MENU_REFRESH {
|
||||
this->refresh(this->get_window()->get_render());
|
||||
elseif id == MENU_EXECUTE;
|
||||
var file. file = this->get_selected_file();
|
||||
if file ~= null {
|
||||
var filename string;
|
||||
this->exec(filename->format("%s/%s",
|
||||
this->get_path(), &file.str));
|
||||
}
|
||||
elseif id == MENU_SELECT;
|
||||
var file. file = this->get_selected_file();
|
||||
if file ~= null {
|
||||
var filename string;
|
||||
this->select(filename->format("%s/%s",
|
||||
this->get_path(), &file.str));
|
||||
}
|
||||
elseif id == MENU_LINK;
|
||||
var file. file = this->get_selected_file();
|
||||
if file ~= null {
|
||||
var parent. scene::main = this->get_window()->get_last_scene();
|
||||
if parent ~= null {
|
||||
if !strcmp(parent->get_name(), "main") {
|
||||
import scene::main;
|
||||
var tile_menu. tile_menu = parent.tile_menu;
|
||||
tile_menu->set_mode(tile_menu::mode.link);
|
||||
var filename string;
|
||||
var link string;
|
||||
link->format(this.exec_format->ptr(),
|
||||
filename->format("%s/%s", this->get_path(), &file.str));
|
||||
tile_menu->set_link(link->ptr());
|
||||
this->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif id == MENU_DELETE;
|
||||
var file. file = this->get_selected_file();
|
||||
if file ~= null {
|
||||
var filename string;
|
||||
system(filename->format("sudo rm -rf \"%s/%s\"",
|
||||
this->get_path(), &file.str));
|
||||
// TODO
|
||||
}
|
||||
elseif id == MENU_EXIT;
|
||||
this->close();
|
||||
}
|
||||
],
|
||||
lambda(this.file_browser) [
|
||||
this->close_popup();
|
||||
], this);
|
||||
popup->add_menu(render, MENU_REFRESH, "Refresh");
|
||||
if file ~= null {
|
||||
if file.type == DT_REG {
|
||||
var filename string;
|
||||
var st struct_stat;
|
||||
if !stat(filename->format("%s/%s", this->get_path(), &file.str), &st) {
|
||||
if st.st_mode & S_IXUSR {
|
||||
popup->add_menu(render, MENU_EXECUTE, "Execute");
|
||||
}
|
||||
}
|
||||
if this.mode == mode.browse or
|
||||
this.mode == mode.exec {
|
||||
popup->add_menu(render, MENU_LINK, "Link");
|
||||
}
|
||||
elseif file.type == DT_DIR;
|
||||
if this.mode == mode.select or
|
||||
this.mode == mode.select_dir {
|
||||
popup->add_menu(render, MENU_SELECT, "Select");
|
||||
}
|
||||
}
|
||||
}
|
||||
// popup->add_menu(render, MENU_DELETE, "Delete");
|
||||
popup->add_menu(render, MENU_EXIT, "Exit");
|
||||
var rect SDL_Rect = 0;
|
||||
this->get_window()->get_size(&rect.w, &rect.h);
|
||||
popup->set_pos(
|
||||
(rect.w - popup->get_width()) / 2,
|
||||
(rect.h - popup->get_height()) / 2);
|
||||
this->set_popup(popup);
|
||||
}
|
||||
|
||||
private func update_scroll() {
|
||||
var rect SDL_Rect = 0;
|
||||
this->get_window()->get_size(&rect.w, &rect.h);
|
||||
if this.start_index > this.cursor {
|
||||
this.start_index = this.cursor;
|
||||
else
|
||||
var display_count int = (rect.h - TOP_HEIGHT) / ITEM_HEIGHT;
|
||||
var delta int = this.cursor - this.start_index + 1;
|
||||
if display_count < delta;
|
||||
this.start_index += delta - display_count;
|
||||
}
|
||||
}
|
||||
|
||||
func update(render void) {
|
||||
if this->has_popup() {
|
||||
this.super->update(render);
|
||||
else
|
||||
if this.image_timer->do() {
|
||||
if this.mode == mode.select_image {
|
||||
if this.tex.image->get_texture() == null {
|
||||
var file. file = this->get_selected_file();
|
||||
if file ~= null {
|
||||
if file.type == DT_REG {
|
||||
var filename string;
|
||||
this.tex.image->load_file(render,
|
||||
filename->format("%s/%s", this->get_path(), &file.str));
|
||||
}
|
||||
}
|
||||
this.image_timer->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
var state. uint8 = SDL_GetKeyboardState(null);
|
||||
if state[CPI_SCANCODE_UP] {
|
||||
if this.input_delay->do() {
|
||||
if this.cursor {
|
||||
this.cursor--;
|
||||
this->update_scroll();
|
||||
this->reload_image();
|
||||
}
|
||||
this.input_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_DOWN];
|
||||
if this.input_delay->do() {
|
||||
if this.cursor < this->get_all_count() -1 {
|
||||
this.cursor++;
|
||||
this->update_scroll();
|
||||
this->reload_image();
|
||||
}
|
||||
this.input_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_LEFT];
|
||||
if this.input_delay->do() {
|
||||
if this.cursor - 10 < 0 {
|
||||
this.cursor = 0;
|
||||
else
|
||||
this.cursor -= 10;
|
||||
}
|
||||
this->update_scroll();
|
||||
this->reload_image();
|
||||
this.input_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_RIGHT];
|
||||
if this.input_delay->do() {
|
||||
if this.cursor + 10 < this->get_all_count() -1 {
|
||||
this.cursor += 10;
|
||||
else
|
||||
this.cursor = this->get_all_count() -1;
|
||||
}
|
||||
this->update_scroll();
|
||||
this->reload_image();
|
||||
this.input_delay->undo();
|
||||
}
|
||||
else
|
||||
this.input_delay->reset();
|
||||
}
|
||||
if state[CPI_SCANCODE_A] {
|
||||
if this.input_lock->do();
|
||||
this->goto_parent_dir(render);
|
||||
elseif state[CPI_SCANCODE_B];
|
||||
if this.input_lock->do();
|
||||
this->action(render);
|
||||
elseif state[CPI_SCANCODE_MENU];
|
||||
if this.input_lock->do();
|
||||
this->show_popup(render, this->get_selected_file());
|
||||
else
|
||||
this.input_lock->set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func draw_items(render void, items. vector<file>, begin size_t, cursor int, rect. SDL_Rect, x int, y& int) bool {
|
||||
forvar index size_t = begin, count size_t = items->count(); index < count; index++ {
|
||||
var item. file = items->at(index);
|
||||
var sub_rect SDL_Rect;
|
||||
sub_rect.x = 0;
|
||||
sub_rect.y = y;
|
||||
sub_rect.w = rect.w;
|
||||
sub_rect.h = ITEM_HEIGHT;
|
||||
if index + cursor == this.cursor {
|
||||
SDL_SetRenderDrawColor(render, 0x00, 0xa2, 0xe8, 0xff);
|
||||
SDL_RenderFillRect(render, &sub_rect);
|
||||
if item.white_font->get_texture() == null {
|
||||
item.white_font->init(
|
||||
global::uni_font->create_tex(render, &item.str, 0xffffffff));
|
||||
}
|
||||
item.white_font->draw(render, x + item.icon->get_width() + 3,
|
||||
y + (ITEM_HEIGHT - item.white_font->get_height()) / 2);
|
||||
else
|
||||
if (y - TOP_HEIGHT) / ITEM_HEIGHT % 2 {
|
||||
SDL_SetRenderDrawColor(render, 0xe0, 0xe0, 0xe0, 0xff);
|
||||
SDL_RenderFillRect(render, &sub_rect);
|
||||
}
|
||||
if item.black_font->get_texture() == null {
|
||||
item.black_font->init(
|
||||
global::uni_font->create_tex(render, &item.str, 0xff000000));
|
||||
}
|
||||
item.black_font->draw(render, x + item.icon->get_width() + 3,
|
||||
y + (ITEM_HEIGHT - item.black_font->get_height()) / 2);
|
||||
}
|
||||
item.icon->draw(render, x,
|
||||
y + (ITEM_HEIGHT - item.icon->get_height()) / 2);
|
||||
if item.link {
|
||||
this.tex.lnk->draw(render, x,
|
||||
y + (ITEM_HEIGHT - this.tex.lnk->get_height()) / 2);
|
||||
}
|
||||
if (y += ITEM_HEIGHT) > rect.h;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
SDL_SetRenderDrawColor(render, 0xff, 0xff, 0xff, 0xff);
|
||||
SDL_RenderClear(render);
|
||||
var rect SDL_Rect = 0;
|
||||
this->get_window()->get_size(&rect.w, &rect.h);
|
||||
var sub_rect SDL_Rect;
|
||||
sub_rect.x = 0;
|
||||
sub_rect.y = 0;
|
||||
sub_rect.w = rect.w;
|
||||
sub_rect.h = TOP_HEIGHT;
|
||||
SDL_SetRenderDrawColor(render, 0x35, 0x35, 0x35, 0xff);
|
||||
SDL_RenderFillRect(render, &sub_rect);
|
||||
if this.tex.name->get_width() > rect.w {
|
||||
this.tex.name->draw(render,
|
||||
-(this.tex.name->get_width() - rect.w) - 4,
|
||||
(TOP_HEIGHT - this.tex.name->get_height()) / 2);
|
||||
else
|
||||
this.tex.name->draw(render,
|
||||
(rect.w - this.tex.name->get_width()) / 2,
|
||||
(TOP_HEIGHT - this.tex.name->get_height()) / 2);
|
||||
}
|
||||
var file_count int = this->get_all_count();
|
||||
if file_count {
|
||||
var x int = 4;
|
||||
var y int = TOP_HEIGHT;
|
||||
var dir_count size_t = this.dirs->count();
|
||||
if dir_count and this.start_index < dir_count {
|
||||
if this->draw_items(render, &this.dirs, this.start_index, 0, &rect, x, y);
|
||||
this->draw_items(render, &this.files, 0, dir_count, &rect, x, y);
|
||||
else
|
||||
this->draw_items(render, &this.files, this.start_index - dir_count, dir_count, &rect, x, y);
|
||||
}
|
||||
var display_count int = (rect.h - TOP_HEIGHT) / ITEM_HEIGHT;
|
||||
if display_count < file_count {
|
||||
sub_rect.x = rect.w - SCROLL_WIDTH;
|
||||
sub_rect.y = TOP_HEIGHT +
|
||||
int((float(this.start_index) / (file_count - display_count)) *
|
||||
(rect.h - (TOP_HEIGHT + SCROLL_HEIGHT)));
|
||||
sub_rect.w = SCROLL_WIDTH;
|
||||
sub_rect.h = SCROLL_HEIGHT;
|
||||
SDL_SetRenderDrawColor(render, 0x80, 0x80, 0x80, 0xff);
|
||||
SDL_RenderFillRect(render, &sub_rect);
|
||||
}
|
||||
else
|
||||
this.tex.empty->draw(render,
|
||||
(rect.w - this.tex.empty->get_width()) / 2,
|
||||
(rect.h - this.tex.empty->get_height()) / 2);
|
||||
}
|
||||
define {
|
||||
IMAGE_MAX_WIDTH = 80;
|
||||
IMAGE_MAX_HEIGHT = 80;
|
||||
IMAGE_GAP = 15;
|
||||
}
|
||||
if this.tex.image->get_texture() ~= null {
|
||||
var width int = this.tex.image->get_width();
|
||||
var height int = this.tex.image->get_height();
|
||||
if width > IMAGE_MAX_WIDTH;
|
||||
width = IMAGE_MAX_WIDTH;
|
||||
if height > IMAGE_MAX_HEIGHT;
|
||||
height = IMAGE_MAX_HEIGHT;
|
||||
this.tex.image->draw3(render,
|
||||
rect.w - (width + IMAGE_GAP),
|
||||
rect.h - (height + IMAGE_GAP), width, height);
|
||||
}
|
||||
this.super->draw(render);
|
||||
this.fadeio->do();
|
||||
}
|
||||
|
||||
func wake() {
|
||||
this.input_delay->reset(false);
|
||||
this.input_lock->set(true);
|
||||
this.super->wake();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
|
||||
class game+, scene+, intro {
|
||||
|
||||
inherit game::scene = super;
|
||||
|
||||
private import lib::sdl2;
|
||||
|
||||
struct intro {
|
||||
fadeio fadeio;
|
||||
delay delay;
|
||||
logo texture;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this); }
|
||||
func destructor() {
|
||||
destructor(this); }
|
||||
|
||||
func init(render void) bool {
|
||||
this.fadeio->init(this->get_window(), 2000);
|
||||
this.fadeio->set_color(235, 235, 235);
|
||||
this.delay->init(1000);
|
||||
this.logo->load_file(render,
|
||||
global::make_path("logo.png"));
|
||||
return true;
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
SDL_SetRenderDrawColor(render, 235, 235, 235, 0xff);
|
||||
SDL_RenderClear(render);
|
||||
var wnd. window = this->get_window();
|
||||
var rect SDL_Rect = 0;
|
||||
wnd->get_size(&rect.w, &rect.h);
|
||||
this.logo->draw(render,
|
||||
rect.w - (rect.w + this.logo->get_width()) / 2,
|
||||
rect.h - (rect.h + this.logo->get_height()) / 2);
|
||||
if this.fadeio->do() and this.delay->do() {
|
||||
wnd->set_new_scene<scene::main>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,646 +0,0 @@
|
||||
|
||||
/*
|
||||
set_callback(on_done void, on_close void, arg void)
|
||||
set_fadeout(fadeout. fadeio)
|
||||
set_title(render void, title. char)
|
||||
set_text(render void, text. char)
|
||||
get_text() .char
|
||||
close()
|
||||
*/
|
||||
|
||||
class game+, scene+, keybd {
|
||||
|
||||
inherit game::scene = super;
|
||||
|
||||
private import rt::c, std::utf8, lib::sdl2;
|
||||
|
||||
private alias string = std::string;
|
||||
|
||||
private define {
|
||||
BUTTON_COL = 11;
|
||||
BUTTON_ROW = 4;
|
||||
BUTTON_COUNT = BUTTON_COL * BUTTON_ROW;
|
||||
BUTTON_WIDTH = 25;
|
||||
BUTTON_HEIGHT = 23;
|
||||
BUTTON_GAP = 3;
|
||||
}
|
||||
|
||||
private var layout(3, BUTTON_COUNT) char = {
|
||||
|
||||
// 0
|
||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-',
|
||||
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '_',
|
||||
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ':', '\'',
|
||||
'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '=',
|
||||
|
||||
// 1
|
||||
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '+',
|
||||
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '\\',
|
||||
'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '"',
|
||||
'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '|',
|
||||
|
||||
// 2
|
||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-',
|
||||
'~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '_',
|
||||
'(', ')', '[', ']', '{', '}', ':', ';', '\'', '"', '\\',
|
||||
',', '.', '/', '=', '<', '>', '?', '|', '+', '\0', '\0'
|
||||
|
||||
};
|
||||
|
||||
private define {
|
||||
SHIFT = -1;
|
||||
BACKSPACE = -2;
|
||||
SPACE = -3;
|
||||
TAB = -4;
|
||||
RETURN = -5;
|
||||
}
|
||||
|
||||
struct keybd {
|
||||
struct tex {
|
||||
title texture;
|
||||
text texture;
|
||||
}
|
||||
fadeio fadeio;
|
||||
fadeout. fadeio;
|
||||
caret_timer delay;
|
||||
cursor_delay repeat;
|
||||
remove_delay repeat;
|
||||
input_lock norepeat;
|
||||
buf string;
|
||||
on_done void;
|
||||
on_close void;
|
||||
arg void;
|
||||
mode int;
|
||||
lock bool;
|
||||
prev_mode int;
|
||||
prev_lock bool;
|
||||
cursor int;
|
||||
prev_cursor int;
|
||||
start_x int;
|
||||
caret_pos int;
|
||||
caret_x int;
|
||||
draw_caret bool;
|
||||
enable_return bool;
|
||||
enable_shift bool;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
memset(this, 0, sizeof(keybd));
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
module singleton {
|
||||
|
||||
var initd bool = false;
|
||||
|
||||
var ascii(128) texture;
|
||||
var shift texture;
|
||||
var shift_white texture;
|
||||
var backspace texture;
|
||||
var space texture;
|
||||
var tab texture;
|
||||
var ret texture;
|
||||
|
||||
}
|
||||
|
||||
func init(render void) bool {
|
||||
if !singleton::initd {
|
||||
var str(2) char = 0;
|
||||
forvar c int = 1; c < 128; c++ {
|
||||
str[0] = c;
|
||||
singleton::ascii[c]->init(
|
||||
global::uni_font->create_tex(render, &str, 0xff000000));
|
||||
}
|
||||
singleton::shift->init(
|
||||
global::uni_font->create_tex(render, "Shift", 0xff000000));
|
||||
singleton::shift_white->init(
|
||||
global::uni_font->create_tex(render, "Shift", 0xffffffff));
|
||||
singleton::backspace->init(
|
||||
global::uni_font->create_tex(render, "Back", 0xff000000));
|
||||
singleton::space->init(
|
||||
global::uni_font->create_tex(render, "Space", 0xff000000));
|
||||
singleton::tab->init(
|
||||
global::uni_font->create_tex(render, "Tab", 0xff000000));
|
||||
singleton::ret->init(
|
||||
global::uni_font->create_tex(render, "Return", 0xff000000));
|
||||
singleton::initd = true;
|
||||
}
|
||||
var wnd. window = this->get_window();
|
||||
this.fadeio->init(wnd, 300);
|
||||
this.fadeio->set_texture(wnd->screen_capture2());
|
||||
this.caret_timer->init(450);
|
||||
this.cursor_delay->init(300, -65, 4);
|
||||
this.remove_delay->init(300, -42, 7);
|
||||
this.prev_cursor = -1;
|
||||
this.draw_caret = true;
|
||||
this.enable_shift = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
on_done = lambda(text. char, arg void) [
|
||||
|
||||
];
|
||||
on_close = lambda(arg void) [
|
||||
|
||||
];
|
||||
*/
|
||||
inline set_callback(on_done void, on_close void, arg void) {
|
||||
this.on_done = on_done;
|
||||
this.on_close = on_close;
|
||||
this.arg = arg;
|
||||
}
|
||||
|
||||
inline set_fadeout(fadeout. fadeio) {
|
||||
this.fadeout = fadeout;
|
||||
}
|
||||
|
||||
func set_title(render void, title. char) {
|
||||
this.tex.title->init(
|
||||
global::uni_font->create_tex(render, title, 0xff000000));
|
||||
}
|
||||
|
||||
private inline update_text(render void) {
|
||||
this.tex.text->init(
|
||||
global::uni_font->create_tex(render, this.buf->ptr(), 0xff000000));
|
||||
}
|
||||
|
||||
private define {
|
||||
TEXT_GAP = 10;
|
||||
}
|
||||
|
||||
private func set_caret(pos int) {
|
||||
this.caret_timer->reset();
|
||||
this.caret_pos = pos;
|
||||
var nul. char = this.buf->ptr(this.caret_pos);
|
||||
var tmp char = .nul;
|
||||
.nul = 0;
|
||||
var caret_x int;
|
||||
if global::uni_font->get_size(this.buf->ptr(), &caret_x, null) {
|
||||
if this.caret_x = caret_x {
|
||||
this.caret_x++;
|
||||
else
|
||||
this.caret_x--;
|
||||
}
|
||||
var rect SDL_Rect = 0;
|
||||
this->get_window()->get_size(&rect.w, &rect.h);
|
||||
if this.tex.text->get_width() > (rect.w -= TEXT_GAP) {
|
||||
if this.caret_x < this.start_x {
|
||||
this.start_x = this.caret_x;
|
||||
else
|
||||
if (this.caret_x - this.start_x) > rect.w;
|
||||
this.start_x = this.caret_x - rect.w;
|
||||
}
|
||||
else
|
||||
this.start_x = 0;
|
||||
}
|
||||
else
|
||||
this.start_x = 0;
|
||||
this.caret_x = 0;
|
||||
}
|
||||
.nul = tmp;
|
||||
this.draw_caret = true;
|
||||
}
|
||||
|
||||
func set_text(render void, text. char) {
|
||||
this.buf->set(text);
|
||||
this->update_text(render);
|
||||
this.start_x = 0;
|
||||
this->set_caret(this.buf->len());
|
||||
}
|
||||
|
||||
inline get_text() .char {
|
||||
return this.buf->ptr();
|
||||
}
|
||||
|
||||
private func insert_char(render void, c char) {
|
||||
var buf(2) char;
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
this.buf->insert(this.caret_pos, &buf);
|
||||
this->update_text(render);
|
||||
this->set_caret(this.caret_pos + 1);
|
||||
}
|
||||
|
||||
private func insert(render void, str. char) {
|
||||
this.buf->insert(this.caret_pos, str);
|
||||
this->update_text(render);
|
||||
this->set_caret(this.caret_pos + strlen(str));
|
||||
}
|
||||
|
||||
private func remove(render void) bool {
|
||||
var tail int;
|
||||
var len int = utf8len_s(this.buf->ptr(), this.caret_pos, &tail);
|
||||
if len == -1;
|
||||
return false;
|
||||
if tail {
|
||||
if this.buf->remove(this.caret_pos - tail, tail) {
|
||||
this->update_text(render);
|
||||
this->set_caret(this.caret_pos - tail);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private func toggle_shift() {
|
||||
if this.mode == 0 {
|
||||
this.mode = 1;
|
||||
elseif this.mode == 1;
|
||||
if this.lock {
|
||||
this.mode = 0;
|
||||
this.lock = false;
|
||||
else
|
||||
this.lock = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func move_caret(left_right bool) bool {
|
||||
if left_right {
|
||||
var tail int;
|
||||
var len int = utf8len_s(this.buf->ptr(), this.caret_pos, &tail);
|
||||
if len == -1;
|
||||
return false;
|
||||
if tail {
|
||||
this->set_caret(this.caret_pos - tail);
|
||||
}
|
||||
else
|
||||
if this.caret_pos >= this.buf->len();
|
||||
return false;
|
||||
var size int = utf8table[uchar(.this.buf->ptr(this.caret_pos))];
|
||||
if (this.caret_pos + size) > this.buf->len();
|
||||
return false;
|
||||
this->set_caret(this.caret_pos + size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
func close() {
|
||||
if this.on_close ~= null {
|
||||
proto fn(arg void);
|
||||
fn[this.on_close](this.arg);
|
||||
}
|
||||
if this.fadeout ~= null {
|
||||
this.fadeout->set_texture(this->get_window()->screen_capture2());
|
||||
this.fadeout->reset();
|
||||
}
|
||||
this->quit();
|
||||
}
|
||||
|
||||
private func done() {
|
||||
if this.on_done ~= null {
|
||||
proto fn(text. char, arg void);
|
||||
fn[this.on_done](this.buf->ptr(), this.arg);
|
||||
}
|
||||
this->close();
|
||||
}
|
||||
|
||||
func update(render void) {
|
||||
if this.caret_timer->do() {
|
||||
this.draw_caret = !this.draw_caret;
|
||||
this.caret_timer->undo();
|
||||
}
|
||||
var state. uint8 = SDL_GetKeyboardState(null);
|
||||
if state[CPI_SCANCODE_LEFT] {
|
||||
if this.cursor_delay->do() {
|
||||
if this.cursor < 0 {
|
||||
this.prev_cursor = -1;
|
||||
if this.cursor == SHIFT {
|
||||
this.cursor = TAB;
|
||||
elseif this.cursor == SPACE;
|
||||
this.cursor = SHIFT;
|
||||
elseif this.cursor == RETURN;
|
||||
this.cursor = SPACE;
|
||||
elseif this.cursor == BACKSPACE;
|
||||
if this.enable_return {
|
||||
this.cursor = RETURN;
|
||||
else
|
||||
this.cursor = SPACE;
|
||||
}
|
||||
else
|
||||
this.cursor = BACKSPACE;
|
||||
}
|
||||
else
|
||||
if this.cursor % BUTTON_COL {
|
||||
this.cursor--;
|
||||
else
|
||||
this.cursor = (this.cursor / BUTTON_COL + 1) * BUTTON_COL - 1;
|
||||
}
|
||||
}
|
||||
this.cursor_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_RIGHT];
|
||||
if this.cursor_delay->do() {
|
||||
if this.cursor < 0 {
|
||||
this.prev_cursor = -1;
|
||||
if this.cursor == TAB {
|
||||
this.cursor = SHIFT;
|
||||
elseif this.cursor == SHIFT;
|
||||
this.cursor = SPACE;
|
||||
elseif this.cursor == SPACE;
|
||||
if this.enable_return {
|
||||
this.cursor = RETURN;
|
||||
else
|
||||
this.cursor = BACKSPACE;
|
||||
}
|
||||
elseif this.cursor == RETURN;
|
||||
this.cursor = BACKSPACE;
|
||||
else
|
||||
this.cursor = TAB;
|
||||
}
|
||||
else
|
||||
if this.cursor % BUTTON_COL == BUTTON_COL - 1 {
|
||||
this.cursor = (this.cursor / BUTTON_COL) * BUTTON_COL;
|
||||
else
|
||||
this.cursor++;
|
||||
}
|
||||
}
|
||||
this.cursor_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_UP];
|
||||
if this.cursor_delay->do() {
|
||||
if this.cursor < 0 {
|
||||
if this.prev_cursor < 0 {
|
||||
if this.cursor == TAB {
|
||||
this.cursor = BUTTON_COUNT - BUTTON_COL;
|
||||
elseif this.cursor == SHIFT;
|
||||
this.cursor = BUTTON_COUNT - (BUTTON_COL - 2);
|
||||
elseif this.cursor == SPACE;
|
||||
this.cursor = BUTTON_COUNT - (BUTTON_COL - 4);
|
||||
elseif this.cursor == RETURN;
|
||||
this.cursor = BUTTON_COUNT - (BUTTON_COL - 7);
|
||||
else
|
||||
this.cursor = BUTTON_COUNT - (BUTTON_COL - 9);
|
||||
}
|
||||
else
|
||||
this.cursor = this.prev_cursor;
|
||||
}
|
||||
else
|
||||
if this.cursor - BUTTON_COL > -1;
|
||||
this.cursor -= BUTTON_COL;
|
||||
}
|
||||
this.cursor_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_DOWN];
|
||||
if this.cursor_delay->do() {
|
||||
if this.cursor > -1 {
|
||||
if this.cursor + BUTTON_COL < BUTTON_COUNT {
|
||||
this.cursor += BUTTON_COL;
|
||||
else
|
||||
this.prev_cursor = this.cursor;
|
||||
var col int = this.cursor % BUTTON_COL;
|
||||
if col >= 0 and col <= 1 {
|
||||
this.cursor = TAB;
|
||||
elseif col >= 2 and col <= 3;
|
||||
this.cursor = SHIFT;
|
||||
elseif col >= 4 and col <= 8;
|
||||
this.cursor = SPACE;
|
||||
if this.enable_return {
|
||||
if col >= 7 and col <= 8;
|
||||
this.cursor = RETURN;
|
||||
}
|
||||
else
|
||||
this.cursor = BACKSPACE;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cursor_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_A];
|
||||
if this.remove_delay->do() {
|
||||
this->remove(render);
|
||||
this.remove_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_LK1];
|
||||
if this.cursor_delay->do() {
|
||||
this->move_caret(true);
|
||||
this.cursor_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_LK5];
|
||||
if this.cursor_delay->do() {
|
||||
this->move_caret(false);
|
||||
this.cursor_delay->undo();
|
||||
}
|
||||
// CPI_SCANCODE_LK2
|
||||
// CPI_SCANCODE_LK4
|
||||
else
|
||||
this.cursor_delay->reset();
|
||||
this.remove_delay->reset();
|
||||
}
|
||||
if state[CPI_SCANCODE_MENU] {
|
||||
if this.input_lock->do() {
|
||||
this->close();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_SELECT];
|
||||
if this.input_lock->do() {
|
||||
if this.mode == 2 {
|
||||
this.mode = this.prev_mode;
|
||||
this.lock = this.prev_lock;
|
||||
this.enable_shift = true;
|
||||
else
|
||||
this.prev_mode = this.mode;
|
||||
this.prev_lock = this.lock;
|
||||
this.mode = 2;
|
||||
this.lock = false;
|
||||
this.enable_shift = false;
|
||||
}
|
||||
}
|
||||
elseif state[CPI_SCANCODE_START];
|
||||
if this.input_lock->do() {
|
||||
this->done();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_B];
|
||||
if this.input_lock->do() {
|
||||
if this.cursor < 0 {
|
||||
if this.cursor == SHIFT {
|
||||
this->toggle_shift();
|
||||
elseif this.cursor == BACKSPACE;
|
||||
this->remove(render);
|
||||
elseif this.cursor == SPACE;
|
||||
this->insert_char(render, ' ');
|
||||
elseif this.cursor == TAB;
|
||||
this->insert_char(render, '\t');
|
||||
elseif this.cursor == RETURN;
|
||||
this->insert_char(render, '\n');
|
||||
}
|
||||
else
|
||||
var pressed char = layout[this.mode, this.cursor];
|
||||
if pressed {
|
||||
if this.mode == 1 {
|
||||
if !this.lock;
|
||||
this.mode = 0;
|
||||
}
|
||||
this->insert_char(render, pressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif state[CPI_SCANCODE_X];
|
||||
if this.input_lock->do() {
|
||||
this->toggle_shift();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_Y];
|
||||
if this.input_lock->do() {
|
||||
this->insert_char(render, ' ');
|
||||
}
|
||||
elseif state[CPI_SCANCODE_SHIFT_SELECT];
|
||||
if this.input_lock->do() {
|
||||
var wnd. window = this->get_window();
|
||||
var browser. scene::file_browser = wnd->new_scene<scene::file_browser>();
|
||||
browser->set_callback(
|
||||
lambda(filename. char, this.keybd) [
|
||||
this->insert(this->get_window()->get_render(), filename);
|
||||
], null, this
|
||||
);
|
||||
browser->set_fadeout(&this.fadeio);
|
||||
if browser->set_dir(wnd->get_render(), "/home/cpi") or
|
||||
browser->set_dir(wnd->get_render(), "/") {
|
||||
browser->set_mode(
|
||||
scene::file_browser::mode.select);
|
||||
wnd->push_scene(this);
|
||||
wnd->set_scene(browser);
|
||||
else
|
||||
wnd->free_scene(browser);
|
||||
}
|
||||
}
|
||||
else
|
||||
this.input_lock->set(false);
|
||||
}
|
||||
}
|
||||
|
||||
private func draw_button(render void, index int, rect. SDL_Rect, tex. texture, custom_color bool = false) {
|
||||
var focus bool = index == this.cursor;
|
||||
if !custom_color {
|
||||
if focus {
|
||||
SDL_SetRenderDrawColor(render, 0xff, 0xff, 0xff, 0xff);
|
||||
else
|
||||
SDL_SetRenderDrawColor(render, 235, 235, 235, 0xff);
|
||||
}
|
||||
}
|
||||
SDL_RenderFillRect(render, rect);
|
||||
if focus {
|
||||
SDL_SetRenderDrawColor(render, 0, 162, 232, 0xff);
|
||||
SDL_RenderDrawRect(render, rect);
|
||||
else
|
||||
SDL_SetRenderDrawColor(render, 127, 127, 127, 0xff);
|
||||
SDL_RenderDrawRect(render, rect);
|
||||
}
|
||||
tex->draw(render,
|
||||
rect.x + (rect.w - tex->get_width()) / 2,
|
||||
rect.y + (rect.h - tex->get_height()) / 2);
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
define {
|
||||
TITLE_X = 10;
|
||||
TITLE_Y = 10;
|
||||
TEXT_Y = 45;
|
||||
KEYBD_Y = 85;
|
||||
}
|
||||
SDL_SetRenderDrawColor(render, 245, 245, 245, 0xff);
|
||||
SDL_RenderClear(render);
|
||||
var rect SDL_Rect = 0;
|
||||
this->get_window()->get_size(&rect.w, &rect.h);
|
||||
// title
|
||||
this.tex.title->draw(render, TITLE_X, TITLE_Y);
|
||||
using caret_x int {
|
||||
// text
|
||||
if this.tex.text->get_texture() == null {
|
||||
caret_x = rect.w / 2;
|
||||
else
|
||||
var width int = this.tex.text->get_width();
|
||||
if width > (rect.w - TEXT_GAP) {
|
||||
var x int = (TEXT_GAP / 2);
|
||||
caret_x = x + (this.caret_x - this.start_x);
|
||||
this.tex.text->draw(render, x + -this.start_x, TEXT_Y);
|
||||
else
|
||||
var x int = (rect.w - width) / 2;
|
||||
caret_x = x + this.caret_x;
|
||||
this.tex.text->draw(render, x, TEXT_Y);
|
||||
}
|
||||
}
|
||||
// caret
|
||||
if this.draw_caret {
|
||||
SDL_SetRenderDrawColor(render, 125, 125, 125, 0xff);
|
||||
SDL_RenderDrawLine(render, caret_x, TEXT_Y, caret_x,
|
||||
TEXT_Y + global::uni_font->get_height());
|
||||
}
|
||||
}
|
||||
// keybd
|
||||
var sub_rect SDL_Rect;
|
||||
var x int = (rect.w - ((BUTTON_COL * (BUTTON_WIDTH + BUTTON_GAP)) - BUTTON_GAP)) / 2;
|
||||
var y int = KEYBD_Y;
|
||||
forvar index int = 0; index < BUTTON_COUNT; index++ {
|
||||
sub_rect.x = x + ((index % BUTTON_COL) * (BUTTON_WIDTH + BUTTON_GAP));
|
||||
sub_rect.y = y + ((index / BUTTON_COL) * (BUTTON_HEIGHT + BUTTON_GAP));
|
||||
sub_rect.w = BUTTON_WIDTH;
|
||||
sub_rect.h = BUTTON_HEIGHT;
|
||||
this->draw_button(render, index, &sub_rect,
|
||||
&singleton::ascii[layout[this.mode, index]]);
|
||||
}
|
||||
sub_rect.x = x;
|
||||
sub_rect.y += BUTTON_WIDTH + BUTTON_GAP;
|
||||
sub_rect.w = ((BUTTON_WIDTH + BUTTON_GAP) * 2) - BUTTON_GAP;
|
||||
sub_rect.h = BUTTON_HEIGHT;
|
||||
this->draw_button(render, TAB, &sub_rect,
|
||||
&singleton::tab);
|
||||
sub_rect.x += sub_rect.w + BUTTON_GAP;
|
||||
sub_rect.w = ((BUTTON_WIDTH + BUTTON_GAP) * 2) - BUTTON_GAP;
|
||||
sub_rect.h = BUTTON_HEIGHT;
|
||||
{
|
||||
var custom_color bool = false;
|
||||
var tex. texture = &singleton::shift;
|
||||
if this.enable_shift {
|
||||
if this.mode == 1 {
|
||||
if this.lock {
|
||||
tex = &singleton::shift_white;
|
||||
SDL_SetRenderDrawColor(render, 130, 130, 130, 0xff);
|
||||
else
|
||||
SDL_SetRenderDrawColor(render, 205, 205, 205, 0xff);
|
||||
}
|
||||
custom_color = true;
|
||||
}
|
||||
else
|
||||
SDL_SetRenderDrawColor(render, 165, 165, 165, 0xff);
|
||||
custom_color = true;
|
||||
}
|
||||
this->draw_button(render, SHIFT, &sub_rect, tex, custom_color);
|
||||
}
|
||||
SDL_SetRenderDrawColor(render, 205, 205, 205, 0xff);
|
||||
if this.enable_return {
|
||||
sub_rect.x += sub_rect.w + BUTTON_GAP;
|
||||
sub_rect.w = ((BUTTON_WIDTH + BUTTON_GAP) * 3) - BUTTON_GAP;
|
||||
sub_rect.h = BUTTON_HEIGHT;
|
||||
this->draw_button(render, SPACE, &sub_rect,
|
||||
&singleton::space, true);
|
||||
sub_rect.x += sub_rect.w + BUTTON_GAP;
|
||||
sub_rect.w = ((BUTTON_WIDTH + BUTTON_GAP) * 2) - BUTTON_GAP;
|
||||
sub_rect.h = BUTTON_HEIGHT;
|
||||
this->draw_button(render, RETURN, &sub_rect,
|
||||
&singleton::ret);
|
||||
else
|
||||
sub_rect.x += sub_rect.w + BUTTON_GAP;
|
||||
sub_rect.w = ((BUTTON_WIDTH + BUTTON_GAP) * 5) - BUTTON_GAP;
|
||||
sub_rect.h = BUTTON_HEIGHT;
|
||||
this->draw_button(render, SPACE, &sub_rect,
|
||||
&singleton::space, true);
|
||||
}
|
||||
sub_rect.x += sub_rect.w + BUTTON_GAP;
|
||||
sub_rect.w = ((BUTTON_WIDTH + BUTTON_GAP) * 2) - BUTTON_GAP;
|
||||
sub_rect.h = BUTTON_HEIGHT;
|
||||
this->draw_button(render, BACKSPACE, &sub_rect,
|
||||
&singleton::backspace);
|
||||
this.fadeio->do();
|
||||
}
|
||||
|
||||
func wake() {
|
||||
this.caret_timer->done();
|
||||
this.cursor_delay->reset(false);
|
||||
this.remove_delay->reset(false);
|
||||
this.input_lock->set(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
|
||||
class game+, scene+, main+, status_bar {
|
||||
|
||||
inherit game::control = super;
|
||||
|
||||
private import rt::c, lib::sdl2;
|
||||
|
||||
struct status_bar {
|
||||
long_timer delay;
|
||||
short_timer delay;
|
||||
batt_icon(4) texture;
|
||||
batt_charging_icon texture;
|
||||
batt_cap int;
|
||||
wifi_icon(4) texture;
|
||||
wifi_sig int;
|
||||
colon bool;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this);
|
||||
this.batt_cap = -1;
|
||||
this.wifi_sig = -1;
|
||||
this.colon = true;
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
define {
|
||||
BATT_UNKNOWN = 0;
|
||||
BATT_LOW = 1;
|
||||
BATT_MID = 2;
|
||||
BATT_FULL = 3;
|
||||
}
|
||||
|
||||
define {
|
||||
WIFI_OFF = 0;
|
||||
WIFI_LOW = 1;
|
||||
WIFI_MID = 2;
|
||||
WIFI_HIGH = 3;
|
||||
}
|
||||
|
||||
func init(render void) bool {
|
||||
this.long_timer->init(3000);
|
||||
this.long_timer->done();
|
||||
this.short_timer->init(1000);
|
||||
this.short_timer->done();
|
||||
this.batt_icon[BATT_UNKNOWN]->load_file(render,
|
||||
global::make_path("main/battery.png"));
|
||||
this.batt_icon[BATT_LOW]->load_file(render,
|
||||
global::make_path("main/battery_low.png"));
|
||||
this.batt_icon[BATT_MID]->load_file(render,
|
||||
global::make_path("main/battery_mid.png"));
|
||||
this.batt_icon[BATT_FULL]->load_file(render,
|
||||
global::make_path("main/battery_full.png"));
|
||||
this.batt_charging_icon->load_file(render,
|
||||
global::make_path("main/battery_charging.png"));
|
||||
this.wifi_icon[WIFI_OFF]->load_file(render,
|
||||
global::make_path("main/wifi.png"));
|
||||
this.wifi_icon[WIFI_LOW]->load_file(render,
|
||||
global::make_path("main/wifi_low.png"));
|
||||
this.wifi_icon[WIFI_MID]->load_file(render,
|
||||
global::make_path("main/wifi_mid.png"));
|
||||
this.wifi_icon[WIFI_HIGH]->load_file(render,
|
||||
global::make_path("main/wifi_high.png"));
|
||||
return true;
|
||||
}
|
||||
|
||||
func update(render void) {
|
||||
if this.long_timer->do() {
|
||||
if !global::wifi->is_connected(&this.wifi_sig);
|
||||
this.wifi_sig = -1;
|
||||
this.long_timer->undo();
|
||||
}
|
||||
if this.short_timer->do() {
|
||||
this.batt_cap = global::get_battery_cap();
|
||||
this.colon = !this.colon;
|
||||
this.short_timer->undo();
|
||||
}
|
||||
}
|
||||
|
||||
private func get_batt_icon() .texture {
|
||||
var icon int = BATT_UNKNOWN;
|
||||
if this.batt_cap ~= -1 {
|
||||
var cap int = this.batt_cap & ~0x100;
|
||||
if cap > 65 {
|
||||
icon = BATT_FULL;
|
||||
elseif cap > 20;
|
||||
icon = BATT_MID;
|
||||
elseif cap > 0;
|
||||
icon = BATT_LOW;
|
||||
}
|
||||
}
|
||||
return &this.batt_icon[icon];
|
||||
}
|
||||
|
||||
private func get_wifi_icon() .texture {
|
||||
var icon int;
|
||||
if this.wifi_sig > 60 {
|
||||
icon = WIFI_HIGH;
|
||||
elseif this.wifi_sig > 30;
|
||||
icon = WIFI_MID;
|
||||
elseif this.wifi_sig > 0;
|
||||
icon = WIFI_LOW;
|
||||
else
|
||||
icon = WIFI_OFF;
|
||||
}
|
||||
return &this.wifi_icon[icon];
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
var x int = this->get_right();
|
||||
var y int = this->get_y();
|
||||
using batt_icon. texture = this->get_batt_icon() {
|
||||
if this.batt_cap ~= -1;
|
||||
global::small_font->draw_cap(render, x -= 40, y + 7, this.batt_cap & ~0x100);;
|
||||
batt_icon->draw(render, x -= batt_icon->get_width(), y);
|
||||
if this.batt_cap ~= -1 and
|
||||
this.batt_cap & 0x100;
|
||||
this.batt_charging_icon->draw(render, x, y);
|
||||
}
|
||||
using wifi_icon. texture = this->get_wifi_icon() {
|
||||
wifi_icon->draw(render, x -= wifi_icon->get_width(), y);
|
||||
}
|
||||
global::small_font->draw_time(render,
|
||||
x -= 55, y + 7, time(null), this.colon);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
|
||||
/*
|
||||
set_callback(on_press void, arg void)
|
||||
add_menu(render void, id int, title. char, icon_filename. char) bool
|
||||
set_cursor(cursor int)
|
||||
get_selected_menu() .menu
|
||||
*/
|
||||
|
||||
class game+, scene+, main+, sub_menu {
|
||||
|
||||
inherit game::control = super;
|
||||
|
||||
private import rt::c, lib::sdl2;
|
||||
|
||||
class menu {
|
||||
struct menu {
|
||||
icon texture;
|
||||
title texture;
|
||||
id int;
|
||||
}
|
||||
func constructor() {
|
||||
constructor(this); }
|
||||
func destructor() {
|
||||
destructor(this); }
|
||||
}
|
||||
|
||||
struct sub_menu {
|
||||
struct tex {
|
||||
button texture;
|
||||
button_hover texture;
|
||||
}
|
||||
menus(MENU_COUNT) menu;
|
||||
menu_count int;
|
||||
input_delay repeat;
|
||||
input_lock norepeat;
|
||||
cursor int;
|
||||
on_press void;
|
||||
arg void;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
memset(this, 0, sizeof(sub_menu));
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
define {
|
||||
MENU_COUNT = 5;
|
||||
BUTTON_WIDTH = 40;
|
||||
BUTTON_HEIGHT = 40;
|
||||
BUTTON_GAP = 10;
|
||||
}
|
||||
|
||||
func init(render void) bool {
|
||||
this.tex.button->load_file(render,
|
||||
global::make_path("main/button_40x40.png"));
|
||||
this.tex.button_hover->load_file(render,
|
||||
global::make_path("main/button_hover_40x40.png"));
|
||||
this.input_delay->init(300, -10, 20);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline set_callback(on_press void, arg void) {
|
||||
this.on_press = on_press;
|
||||
this.arg = arg;
|
||||
}
|
||||
|
||||
func add_menu(render void, id int, title. char, icon_filename. char) bool {
|
||||
if this.menu_count >= MENU_COUNT;
|
||||
return false;
|
||||
this.menus[this.menu_count].icon->load_file(render, icon_filename);
|
||||
this.menus[this.menu_count].title->init(
|
||||
global::uni_font->create_tex(render, title, 0xff000000));
|
||||
this.menus[this.menu_count].id = id;
|
||||
this.menu_count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
func update(render void) {
|
||||
if this->has_focus() {
|
||||
var state. uint8 = SDL_GetKeyboardState(null);
|
||||
if state[CPI_SCANCODE_LEFT] {
|
||||
if this.input_delay->do() {
|
||||
if this.cursor;
|
||||
this.cursor--;
|
||||
this.input_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_RIGHT];
|
||||
if this.input_delay->do() {
|
||||
if this.cursor < MENU_COUNT - 1;
|
||||
this.cursor++;
|
||||
this.input_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_UP];
|
||||
var parent. scene::main = this->get_parent();
|
||||
var cursor int = this.cursor;
|
||||
#if MENU_COUNT > tile_menu::TILE_HALF_COUNT;
|
||||
cursor /= (MENU_COUNT / tile_menu::TILE_HALF_COUNT);
|
||||
#else
|
||||
cursor += (tile_menu::TILE_HALF_COUNT - MENU_COUNT) / 2;
|
||||
#endif
|
||||
if (cursor += tile_menu::TILE_HALF_COUNT) >= tile_menu::TILE_COUNT;
|
||||
cursor = tile_menu::TILE_COUNT - 1;
|
||||
var tile_menu. tile_menu = parent.tile_menu;
|
||||
tile_menu->set_cursor(cursor);
|
||||
tile_menu->wake();
|
||||
parent->set_focus(tile_menu);
|
||||
else
|
||||
this.input_delay->reset();
|
||||
}
|
||||
if state[CPI_SCANCODE_B] {
|
||||
if this.input_lock->do() {
|
||||
var menu. menu = this->get_selected_menu();
|
||||
if menu ~= null {
|
||||
proto fn(id int, arg void);
|
||||
fn[this.on_press](menu.id, this.arg);
|
||||
}
|
||||
}
|
||||
else
|
||||
this.input_lock->set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
var focus bool = this->has_focus();
|
||||
var rect SDL_Rect = 0;
|
||||
this->get_window()->get_size(&rect.w, &rect.h);
|
||||
var x int = this->get_x() +
|
||||
(this->get_width() - ((BUTTON_WIDTH * MENU_COUNT) + (BUTTON_GAP * (MENU_COUNT - 1)))) / 2;
|
||||
var y int = this->get_y();
|
||||
forvar index int = 0; index < MENU_COUNT; index++ {
|
||||
var menu. menu = &this.menus[index];
|
||||
if focus and this.cursor == index {
|
||||
this.tex.button_hover->draw(render, x, y);
|
||||
// out of bounds
|
||||
menu.title->draw(render,
|
||||
this->get_x() + (rect.w - menu.title->get_width()) / 2,
|
||||
y - (menu.title->get_height() + 4));
|
||||
else
|
||||
this.tex.button->draw(render, x, y);
|
||||
}
|
||||
menu.icon->draw(render, x + 1, y + 1);
|
||||
x += (BUTTON_WIDTH + BUTTON_GAP);
|
||||
}
|
||||
}
|
||||
|
||||
func wake() {
|
||||
this.input_delay->reset(false);
|
||||
this.input_lock->set(true);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline set_cursor(cursor int) {
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
inline get_selected_menu() .menu {
|
||||
if this.cursor < this.menu_count;
|
||||
return &this.menus[this.cursor];
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,635 +0,0 @@
|
||||
|
||||
/*
|
||||
reload_page(render void)
|
||||
set_mode(mode. mode)
|
||||
get_mode() mode
|
||||
set_link(filename. char)
|
||||
clear_link()
|
||||
get_page() int
|
||||
set_page(render void, page int)
|
||||
set_cursor(cursor int)
|
||||
get_app(index int) .tile_app
|
||||
get_selected_app() .tile_app
|
||||
*/
|
||||
|
||||
class game+, scene+, main+, tile_menu {
|
||||
|
||||
inherit game::control = super;
|
||||
|
||||
private import rt::c, lib::sdl2;
|
||||
|
||||
private alias
|
||||
string = std::string,
|
||||
strings = std::strings;
|
||||
|
||||
private alias popup_menu = control::popup_menu;
|
||||
|
||||
enum mode {
|
||||
none,
|
||||
move,
|
||||
link
|
||||
}
|
||||
|
||||
class image_cache {
|
||||
private import rt::c;
|
||||
private alias
|
||||
vector = std::vector,
|
||||
string = std::string;
|
||||
struct cache {
|
||||
filename string;
|
||||
tex texture;
|
||||
}
|
||||
struct image_cache {
|
||||
caches vector<cache>;
|
||||
}
|
||||
func constructor() {
|
||||
constructor(this); }
|
||||
func destructor() {
|
||||
destructor(this); }
|
||||
func find(filename. char) .cache {
|
||||
var count size_t = this.caches->count();
|
||||
while count {
|
||||
var cache. cache = this.caches->at(--count);
|
||||
if !strcmp(cache.filename->ptr(), filename) {
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
func load_file(render void, filename. char) void {
|
||||
var cache. cache = this->find(filename);
|
||||
if cache == null {
|
||||
cache = this.caches->new();
|
||||
cache.filename->set(filename);
|
||||
if !cache.tex->load_file(render, filename) {
|
||||
this.caches->pop_back();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return cache.tex->get_texture();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fixme
|
||||
*/
|
||||
class tile_app {
|
||||
struct tile_app {
|
||||
struct tex {
|
||||
icon texture;
|
||||
title texture;
|
||||
}
|
||||
icon. char;
|
||||
title. char;
|
||||
cmd. char;
|
||||
slot int;
|
||||
type int;
|
||||
}
|
||||
func constructor() {
|
||||
constructor(this); }
|
||||
func destructor() {
|
||||
destructor(this); }
|
||||
}
|
||||
|
||||
struct tile_menu {
|
||||
struct tex {
|
||||
tile texture;
|
||||
tile_hover texture;
|
||||
// ...
|
||||
move_mode texture;
|
||||
link_mode texture;
|
||||
}
|
||||
input_delay repeat;
|
||||
input_lock norepeat;
|
||||
page int;
|
||||
cursor int;
|
||||
struct slide {
|
||||
delay delay;
|
||||
dir bool;
|
||||
}
|
||||
image_cache image_cache;
|
||||
apps(TILE_COUNT) tile_app;
|
||||
temp_apps(TILE_COUNT) tile_app;
|
||||
moving_icon texture;
|
||||
mode mode;
|
||||
from int;
|
||||
link string;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
memset(this, 0, sizeof(tile_menu));
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
define {
|
||||
TILE_COUNT = 10;
|
||||
TILE_HALF_COUNT = TILE_COUNT / 2;
|
||||
TILE_WIDTH = 52;
|
||||
TILE_HEIGHT = 52;
|
||||
TILE_GAP = 10;
|
||||
}
|
||||
|
||||
define {
|
||||
MAX_PAGE = 10;
|
||||
}
|
||||
|
||||
static func free_app(app. tile_app) {
|
||||
app.tex.icon->destroy();
|
||||
app.tex.title->destroy();
|
||||
app.icon = null;
|
||||
app.title = null;
|
||||
app.cmd = null;
|
||||
app.type = -1;
|
||||
}
|
||||
|
||||
func reload_page(render void) {
|
||||
struct args {
|
||||
tile_menu. tile_menu;
|
||||
tile_apps. tile_app;
|
||||
render void;
|
||||
begin int;
|
||||
}
|
||||
var arg args;
|
||||
arg.tile_menu = this;
|
||||
arg.tile_apps = &this.apps;
|
||||
arg.render = render;
|
||||
arg.begin = (this.page - 1) * TILE_COUNT;
|
||||
forvar i int = 0; i < TILE_COUNT; i++ {
|
||||
var app. tile_app = &this.apps[i];
|
||||
this->free_app(app);
|
||||
app.slot = arg.begin + i;
|
||||
}
|
||||
global::apps->for_each(arg.begin, arg.begin + (TILE_COUNT - 1),
|
||||
lambda(app. app_list::app, arg. args) [
|
||||
var tile_menu. tile_menu = arg.tile_menu;
|
||||
var tile_app. tile_app = &arg.tile_apps[app.slot - arg.begin];
|
||||
tile_app.tex.icon->init(
|
||||
tile_menu.image_cache->load_file(arg.render,
|
||||
tile_app.icon = app.icon->ptr()), false);
|
||||
using title void {
|
||||
tile_app.title = app.title->ptr();
|
||||
// deprecated
|
||||
if global::outlined_font {
|
||||
title = global::uni_font->create_outlined_tex(arg.render, tile_app.title,
|
||||
0xffffffff, 0xff000000, 1);
|
||||
else
|
||||
title = global::uni_font->create_tex(arg.render, tile_app.title, 0xff000000);
|
||||
}
|
||||
tile_app.tex.title->init(title);
|
||||
}
|
||||
tile_app.cmd = app.cmd->ptr();
|
||||
tile_app.type = app.type;
|
||||
], &arg
|
||||
);
|
||||
}
|
||||
|
||||
func init(render void) bool {
|
||||
this.tex.tile->load_file(render,
|
||||
global::make_path("main/tile_52x52.png"));
|
||||
this.tex.tile_hover->load_file(render,
|
||||
global::make_path("main/tile_hover_52x52.png"));
|
||||
// ...
|
||||
this.tex.move_mode->init(
|
||||
global::uni_font->create_tex(render, "Move Mode", 0xffffffff));
|
||||
this.tex.link_mode->init(
|
||||
global::uni_font->create_tex(render, "Link Mode", 0xffffffff));
|
||||
this.input_delay->init(300, -25, 10);
|
||||
this.slide.delay->done();
|
||||
this.page = 1;
|
||||
this->reload_page(render);
|
||||
return true;
|
||||
}
|
||||
|
||||
private func exec(cmd. char) {
|
||||
if .cmd == '#' {
|
||||
var strs strings;
|
||||
strs->split(++cmd, "\t");
|
||||
/*
|
||||
#exec dir ext format
|
||||
*/
|
||||
if !strcmp(strs->first_item(), "exec") {
|
||||
if strs->count() > 3 {
|
||||
var wnd. window = this->get_window();
|
||||
var browser. scene::file_browser = wnd->new_scene<scene::file_browser>();
|
||||
browser->set_fadeout(&this->get_parent_t<scene::main>().fadeio);
|
||||
browser->hidden_files(true);
|
||||
browser->set_mode(
|
||||
scene::file_browser::mode.exec);
|
||||
if strlen(strs->item(2));
|
||||
browser->set_ext(strs->item(2));
|
||||
browser->set_exec_format(strs->item(3));
|
||||
mkdir(strs->item(1), 0775);
|
||||
if browser->set_dir(wnd->get_render(), strs->item(1), true) {
|
||||
wnd->push_scene(this->get_parent());
|
||||
wnd->set_scene(browser);
|
||||
else
|
||||
wnd->free_scene(browser);
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif .cmd;
|
||||
exec3(this->get_window(), "Please Wait", cmd);
|
||||
}
|
||||
}
|
||||
|
||||
// popup
|
||||
|
||||
private func adjust_popup_pos(popup. popup_menu) {
|
||||
var x int = this->get_x() + TILE_GAP;
|
||||
var y int = this->get_y();
|
||||
if this.cursor < TILE_HALF_COUNT {
|
||||
x += this.cursor * (TILE_WIDTH + TILE_GAP);
|
||||
else
|
||||
x += (this.cursor - TILE_HALF_COUNT) * (TILE_WIDTH + TILE_GAP);
|
||||
y += TILE_HEIGHT + TILE_GAP;
|
||||
}
|
||||
x += TILE_WIDTH;
|
||||
var rect SDL_Rect = 0;
|
||||
this->get_window()->get_size(&rect.w, &rect.h);
|
||||
var popup_width int = popup->get_width();
|
||||
var popup_height int = popup->get_height();
|
||||
if (x + popup_width) > rect.w;
|
||||
x -= popup_width + TILE_WIDTH;
|
||||
if (y + popup_height) > rect.h;
|
||||
y = rect.h - popup_height;
|
||||
popup->set_pos(x, y);
|
||||
}
|
||||
|
||||
private func show_edit_popup(render void, app. tile_app) {
|
||||
define {
|
||||
POPUP_WIDTH = 280;
|
||||
POPUP_HEIGHT = 186;
|
||||
}
|
||||
var rect SDL_Rect = 0;
|
||||
this->get_window()->get_size(&rect.w, &rect.h);
|
||||
this->close_popup();
|
||||
var popup. edit_popup = this->create_control<edit_popup>(
|
||||
(rect.w - POPUP_WIDTH) / 2,
|
||||
(rect.h - POPUP_HEIGHT) / 2, POPUP_WIDTH, POPUP_HEIGHT);
|
||||
popup->fill_in(render, app);
|
||||
this->set_popup(popup);
|
||||
}
|
||||
|
||||
private func show_popup(render void, app. tile_app) {
|
||||
define {
|
||||
MENU_REMOVE = -1;
|
||||
MENU_EXECUTE = 0;
|
||||
MENU_MOVE = 1;
|
||||
MENU_EDIT = 2;
|
||||
}
|
||||
this->close_popup();
|
||||
var popup. popup_menu = this->create_control<popup_menu>(0, 0);
|
||||
popup->set_callback(
|
||||
lambda(id int, this.tile_menu) [
|
||||
var app. tile_app = this->get_selected_app();
|
||||
if id == MENU_REMOVE {
|
||||
if global::apps->remove(app.slot);
|
||||
this->free_app(app);
|
||||
elseif id == MENU_EXECUTE;
|
||||
if app.cmd ~= null;
|
||||
this->exec(app.cmd);
|
||||
elseif id == MENU_MOVE;
|
||||
var render void = this->get_window()->get_render();
|
||||
this.from = app.slot;
|
||||
this.moving_icon->init(
|
||||
this.image_cache->load_file(render, app.icon), false);
|
||||
this.mode = mode.move;
|
||||
elseif id == MENU_EDIT;
|
||||
this->show_edit_popup(this->get_window()->get_render(), app);
|
||||
}
|
||||
],
|
||||
lambda(this.tile_menu) [
|
||||
this->close_popup();
|
||||
], this);
|
||||
if app.type == -1 {
|
||||
popup->add_menu(render, MENU_EDIT, "Edit");
|
||||
else
|
||||
popup->add_menu(render, MENU_EXECUTE, "Execute");
|
||||
popup->add_menu(render, MENU_MOVE, "Move");
|
||||
if app.type {
|
||||
popup->add_menu(render, MENU_EDIT, "Edit");
|
||||
popup->add_menu(render, MENU_REMOVE, "Remove");
|
||||
}
|
||||
}
|
||||
this->adjust_popup_pos(popup);
|
||||
this->set_popup(popup);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
private func try_slide(render void, cursor int, page int, dir bool, delay int = 300) {
|
||||
if this.slide.delay->done?() {
|
||||
this.cursor = cursor;
|
||||
this.page = page;
|
||||
this.temp_apps = this.apps;
|
||||
memset(&this.apps, 0, sizeof(tile_app, TILE_COUNT));
|
||||
this->reload_page(render);
|
||||
this.slide.dir = dir;
|
||||
this.slide.delay->init(delay);
|
||||
this->get_window()->enable_turbo(delay * 2);
|
||||
}
|
||||
}
|
||||
|
||||
func update(render void) {
|
||||
if this->has_focus() {
|
||||
if this->has_popup() {
|
||||
this.super->update(render);
|
||||
else
|
||||
var state. uint8 = SDL_GetKeyboardState(null);
|
||||
if state[CPI_SCANCODE_LEFT] {
|
||||
if this.input_delay->do() {
|
||||
if !this.cursor {
|
||||
if this.page > 1 {
|
||||
this->try_slide(render, TILE_HALF_COUNT - 1, this.page - 1, false);
|
||||
else
|
||||
this->try_slide(render, TILE_HALF_COUNT - 1, MAX_PAGE, false);
|
||||
}
|
||||
elseif this.cursor == TILE_HALF_COUNT;
|
||||
if this.page > 1 {
|
||||
this->try_slide(render, TILE_COUNT - 1, this.page - 1, false);
|
||||
else
|
||||
this->try_slide(render, TILE_COUNT - 1, MAX_PAGE, false);
|
||||
}
|
||||
elseif this.cursor;
|
||||
this.cursor--;
|
||||
}
|
||||
this.input_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_RIGHT];
|
||||
if this.input_delay->do() {
|
||||
if this.cursor == TILE_HALF_COUNT - 1 {
|
||||
if this.page < MAX_PAGE {
|
||||
this->try_slide(render, 0, this.page + 1, true);
|
||||
else
|
||||
this->try_slide(render, 0, 1, true);
|
||||
}
|
||||
elseif this.cursor == TILE_COUNT - 1;
|
||||
if this.page < MAX_PAGE {
|
||||
this->try_slide(render, TILE_HALF_COUNT, this.page + 1, true);
|
||||
else
|
||||
this->try_slide(render, TILE_HALF_COUNT, 1, true);
|
||||
}
|
||||
elseif this.cursor < TILE_COUNT - 1;
|
||||
this.cursor++;
|
||||
}
|
||||
this.input_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_UP];
|
||||
if this.input_delay->do() {
|
||||
if this.cursor >= TILE_HALF_COUNT;
|
||||
this.cursor -= TILE_HALF_COUNT;
|
||||
this.input_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_DOWN];
|
||||
if this.input_delay->do() {
|
||||
if this.cursor < TILE_HALF_COUNT {
|
||||
this.cursor += TILE_HALF_COUNT;
|
||||
elseif this.mode == mode.none;
|
||||
var parent. scene::main = this->get_parent();
|
||||
var cursor int = this.cursor - TILE_HALF_COUNT;
|
||||
#if TILE_HALF_COUNT > sub_menu::MENU_COUNT;
|
||||
cursor /= (TILE_HALF_COUNT / sub_menu::MENU_COUNT);
|
||||
#else
|
||||
cursor += (sub_menu::MENU_COUNT - TILE_HALF_COUNT) / 2;
|
||||
#endif
|
||||
if cursor >= sub_menu::MENU_COUNT;
|
||||
cursor = sub_menu::MENU_COUNT - 1;
|
||||
var sub_menu. sub_menu = parent.sub_menu;
|
||||
sub_menu->set_cursor(cursor);
|
||||
sub_menu->wake();
|
||||
parent->set_focus(sub_menu);
|
||||
}
|
||||
this.input_delay->undo();
|
||||
}
|
||||
else
|
||||
this.input_delay->reset();
|
||||
}
|
||||
if state[CPI_SCANCODE_A] {
|
||||
if this.input_lock->do() {
|
||||
if this.mode == mode.move {
|
||||
this.mode = mode.none;
|
||||
this.moving_icon->destroy();
|
||||
elseif this.mode == mode.link;
|
||||
this.mode = mode.none;
|
||||
this.link->clear();
|
||||
}
|
||||
}
|
||||
elseif state[CPI_SCANCODE_B];
|
||||
if this.input_lock->do() {
|
||||
if this.mode == mode.none {
|
||||
var app. tile_app = this->get_selected_app();
|
||||
if app.cmd ~= null {
|
||||
this->exec(app.cmd);
|
||||
}
|
||||
elseif this.mode == mode.move;
|
||||
var app. tile_app = this->get_selected_app();
|
||||
if app.slot == this.from {
|
||||
this.mode = mode.none;
|
||||
this.moving_icon->destroy();
|
||||
else
|
||||
if app.type {
|
||||
if global::apps->move(this.from, app.slot);
|
||||
this->reload_page(render);
|
||||
this.mode = mode.none;
|
||||
this.moving_icon->destroy();
|
||||
else
|
||||
// system app
|
||||
}
|
||||
}
|
||||
elseif this.mode == mode.link;
|
||||
var app. tile_app = this->get_selected_app();
|
||||
if app.type == -1 {
|
||||
app.cmd = this.link->ptr();
|
||||
this->show_edit_popup(render, app);
|
||||
this.mode = mode.none;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif state[CPI_SCANCODE_MENU];
|
||||
if this.input_lock->do() {
|
||||
if this.mode == mode.none;
|
||||
this->show_popup(render, this->get_selected_app());
|
||||
}
|
||||
elseif state[CPI_SCANCODE_LK1];
|
||||
if this.input_lock->do() {
|
||||
if this.page > 1 {
|
||||
this->try_slide(render, this.cursor, this.page - 1, false);
|
||||
else
|
||||
this->try_slide(render, this.cursor, MAX_PAGE, false);
|
||||
}
|
||||
}
|
||||
elseif state[CPI_SCANCODE_LK5];
|
||||
if this.input_lock->do() {
|
||||
if this.page < MAX_PAGE {
|
||||
this->try_slide(render, this.cursor, this.page + 1, true);
|
||||
else
|
||||
this->try_slide(render, this.cursor, 1, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
this.input_lock->set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func draw_icon(render void, icon. texture, rect. SDL_Rect) {
|
||||
var width int = icon->get_width();
|
||||
var height int = icon->get_height();
|
||||
if width > rect.w;
|
||||
width = rect.w;
|
||||
if height > rect.h;
|
||||
height = rect.h;
|
||||
icon->draw3(render,
|
||||
rect.x + (rect.w - width) / 2,
|
||||
rect.y + (rect.h - height) / 2, width, height);
|
||||
}
|
||||
|
||||
private func draw_tiles(render void, x int, y int, start int, end int) {
|
||||
var rect SDL_Rect;
|
||||
rect.y = y + 1;
|
||||
rect.w = TILE_WIDTH - 2;
|
||||
rect.h = TILE_HEIGHT - 2;
|
||||
forvar index int = start; index < end; index++ {
|
||||
var app. tile_app = &this.apps[index];
|
||||
rect.x = x + 1;
|
||||
if this->has_focus() and this.cursor == index {
|
||||
this.tex.tile_hover->draw(render, x, y);
|
||||
if this.moving_icon->get_texture() == null {
|
||||
this->draw_icon(render, &app.tex.icon, &rect);
|
||||
else
|
||||
this->draw_icon(render, &this.moving_icon, &rect);
|
||||
}
|
||||
// out of bounds
|
||||
app.tex.title->draw(render,
|
||||
this->get_x() + (this->get_width() - app.tex.title->get_width()) / 2,
|
||||
this->get_bottom() + 5);
|
||||
else
|
||||
this.tex.tile->draw(render, x, y);
|
||||
this->draw_icon(render,
|
||||
&app.tex.icon, &rect);
|
||||
}
|
||||
x += (TILE_GAP + TILE_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
private func draw_temp_tiles(render void, x int, y int, start int, end int) {
|
||||
var rect SDL_Rect;
|
||||
rect.y = y + 1;
|
||||
rect.w = TILE_WIDTH - 2;
|
||||
rect.h = TILE_HEIGHT - 2;
|
||||
forvar index int = start; index < end; index++ {
|
||||
this.tex.tile->draw(render, x, y);
|
||||
rect.x = x + 1;
|
||||
this->draw_icon(render, &this.temp_apps[index].tex.icon, &rect);
|
||||
x += (TILE_GAP + TILE_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
private func slide(render void) int {
|
||||
if this.slide.delay->do() {
|
||||
forvar index int = 0; index < TILE_COUNT; index++;
|
||||
this->free_app(&this.temp_apps[index]);
|
||||
return 0;
|
||||
}
|
||||
var delta int = this.slide.delay->get_per_r<int>(this->get_width());
|
||||
if this.slide.dir {
|
||||
this->draw_temp_tiles(render,
|
||||
this->get_x() - delta + TILE_GAP,
|
||||
this->get_y(), 0, TILE_HALF_COUNT);
|
||||
this->draw_temp_tiles(render,
|
||||
this->get_x() - delta + TILE_GAP,
|
||||
this->get_y() + (TILE_GAP + TILE_HEIGHT), TILE_HALF_COUNT, TILE_COUNT);
|
||||
return this->get_width() - delta;
|
||||
else
|
||||
this->draw_temp_tiles(render,
|
||||
this->get_x() + delta + TILE_GAP,
|
||||
this->get_y(), 0, TILE_HALF_COUNT);
|
||||
this->draw_temp_tiles(render,
|
||||
this->get_x() + delta + TILE_GAP,
|
||||
this->get_y() + (TILE_GAP + TILE_HEIGHT), TILE_HALF_COUNT, TILE_COUNT);
|
||||
return -(this->get_width() - delta);
|
||||
}
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
var delta int = this->slide(render);
|
||||
this->draw_tiles(render,
|
||||
this->get_x() + TILE_GAP + delta,
|
||||
this->get_y(), 0, TILE_HALF_COUNT);
|
||||
this->draw_tiles(render,
|
||||
this->get_x() + TILE_GAP + delta,
|
||||
this->get_y() + (TILE_GAP + TILE_HEIGHT), TILE_HALF_COUNT, TILE_COUNT);
|
||||
this.super->draw(render);
|
||||
// out of bounds
|
||||
if this.mode ~= mode.none {
|
||||
define {
|
||||
PADDING = 3;
|
||||
}
|
||||
var tex. texture;
|
||||
if this.mode == mode.move {
|
||||
tex = &this.tex.move_mode;
|
||||
elseif this.mode == mode.link;
|
||||
tex = &this.tex.link_mode;
|
||||
}
|
||||
var rect SDL_Rect;
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.w = tex->get_width() + (PADDING * 2);
|
||||
rect.h = tex->get_height() + (PADDING * 2);
|
||||
SDL_SetRenderDrawColor(render, 52, 152, 219, 0xff);
|
||||
SDL_RenderFillRect(render, &rect);
|
||||
tex->draw(render, PADDING, PADDING);
|
||||
}
|
||||
}
|
||||
|
||||
func wake() {
|
||||
this.input_delay->reset(false);
|
||||
this.input_lock->set(true);
|
||||
this.super->wake();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline set_mode(mode. mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
inline get_mode() mode {
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
inline set_link(filename. char) {
|
||||
this.link->set(filename);
|
||||
}
|
||||
|
||||
inline clear_link() {
|
||||
this.link->clear();
|
||||
}
|
||||
|
||||
inline get_page() int {
|
||||
return this.page;
|
||||
}
|
||||
|
||||
inline set_page(render void, page int) {
|
||||
this.page = page;
|
||||
this->reload_page(render);
|
||||
}
|
||||
|
||||
inline set_cursor(cursor int) {
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
inline get_app(index int) .tile_app {
|
||||
return &this.apps[index];
|
||||
}
|
||||
|
||||
inline get_selected_app() .tile_app {
|
||||
return this->get_app(this.cursor);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
|
||||
class game+, scene+, main+ {
|
||||
|
||||
inherit game::scene = super;
|
||||
|
||||
private import rt::c, lib::sdl2;
|
||||
|
||||
private alias vector = std::vector;
|
||||
|
||||
struct main {
|
||||
struct tex {
|
||||
background texture;
|
||||
}
|
||||
fadeio fadeio;
|
||||
input_lock norepeat;
|
||||
status_bar. status_bar;
|
||||
tile_menu. tile_menu;
|
||||
sub_menu. sub_menu;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
private func standby() bool {
|
||||
var level byte = global::get_backlight_level();
|
||||
if level == -1;
|
||||
return false;
|
||||
if !global::set_backlight_level(0);
|
||||
return false;
|
||||
lambda signal(pids. vector<int>, sig int) [
|
||||
var count size_t = pids->count();
|
||||
while count {
|
||||
var pid int = .pids->at(--count);
|
||||
if pid ~= -1;
|
||||
kill(pid, sig);
|
||||
}
|
||||
];
|
||||
var pids vector<int>;
|
||||
pids->push_back(find_pid_by_cmdline("/home/cpi/launcher/sys.py/gsnotify/gsnotify-arm"));
|
||||
signal(&pids, SIGTSTP);
|
||||
for ;; {
|
||||
var event SDL_Event;
|
||||
while SDL_PollEvent(&event) {
|
||||
if event.type == SDL_KEYDOWN {
|
||||
break 2;
|
||||
elseif event.type == SDL_QUIT;
|
||||
this->get_window()->quit();
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
sleep(3);
|
||||
}
|
||||
signal(&pids, SIGCONT);
|
||||
forvar attempt int = 0; attempt < 3; attempt++ {
|
||||
if global::set_backlight_level(level);
|
||||
break;
|
||||
sleep(1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
func init(render void) bool {
|
||||
var wnd. window = this->get_window();
|
||||
var rect SDL_Rect = 0;
|
||||
wnd->get_size(&rect.w, &rect.h);
|
||||
this.tex.background->load_file(render,
|
||||
global::make_path("main/background.png"));
|
||||
this.fadeio->init(wnd, 300);
|
||||
this.fadeio->set_texture(wnd->screen_capture2());
|
||||
// 1st
|
||||
this.tile_menu = this->new_control<tile_menu>(0, 36, rect.w, 114);
|
||||
define {
|
||||
MENU_NONE = 1;
|
||||
MENU_BROWSER = 2;
|
||||
MENU_STANDBY = 3;
|
||||
MENU_QUIT = 4;
|
||||
}
|
||||
// 2nd
|
||||
this.sub_menu = this->new_control<sub_menu>(0, 176, rect.w, 40);
|
||||
this.sub_menu->set_callback(
|
||||
lambda(id int, this.main) [
|
||||
if id == MENU_BROWSER {
|
||||
var wnd. window = this->get_window();
|
||||
var browser. scene::file_browser = wnd->new_scene<scene::file_browser>();
|
||||
browser->set_fadeout(&this.fadeio);
|
||||
browser->set_mode(
|
||||
scene::file_browser::mode.browse);
|
||||
var cwd(0x800) char;
|
||||
if getcwd(&cwd, sizeof(cwd)) ~= null and browser->set_dir(wnd->get_render(), &cwd) {
|
||||
wnd->push_scene(this);
|
||||
wnd->set_scene(browser);
|
||||
else
|
||||
wnd->free_scene(browser);
|
||||
}
|
||||
elseif id == MENU_STANDBY;
|
||||
this->standby();
|
||||
elseif id == MENU_QUIT;
|
||||
this->get_window()->quit();
|
||||
}
|
||||
], this
|
||||
);
|
||||
this.sub_menu->add_menu(render, MENU_BROWSER, "File Browser",
|
||||
global::make_path("main/browser.png"));
|
||||
this.sub_menu->add_menu(render, MENU_STANDBY, "Standby",
|
||||
global::make_path("main/standby.png"));
|
||||
this.sub_menu->add_menu(render, MENU_QUIT, "Quit",
|
||||
global::make_path("main/quit.png"));
|
||||
// 3rd
|
||||
this.status_bar = this->new_control<status_bar>(8, 4, rect.w - 16, 26);
|
||||
this->set_focus(this.tile_menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
func update(render void) {
|
||||
this.super->update(render);
|
||||
var state. uint8 = SDL_GetKeyboardState(null);
|
||||
if state[CPI_SCANCODE_SELECT] {
|
||||
/*
|
||||
if this.input_lock->do() {
|
||||
var cwd(0x800) char;
|
||||
if getcwd(&cwd, sizeof(cwd)) ~= null {
|
||||
var filename std::string;
|
||||
filename->format("%s/bean", &cwd);
|
||||
execl( filename->ptr(),
|
||||
filename->ptr(), null);
|
||||
}
|
||||
}
|
||||
*/
|
||||
else
|
||||
this.input_lock->set(false);
|
||||
}
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
if this.tex.background->get_texture() == null {
|
||||
SDL_SetRenderDrawColor(render, 0xff, 0xff, 0xff, 0xff);
|
||||
SDL_RenderClear(render);
|
||||
else
|
||||
this.tex.background->draw(render, 0, 0);
|
||||
}
|
||||
var rect SDL_Rect = 0;
|
||||
this->get_window()->get_size(&rect.w, &rect.h);
|
||||
// ...
|
||||
global::small_font->draw_page(render, 8, rect.h - 18,
|
||||
this.tile_menu->get_page(), tile_menu::MAX_PAGE);
|
||||
this.super->draw(render);
|
||||
this.fadeio->do();
|
||||
}
|
||||
|
||||
func wake() {
|
||||
this.input_lock->set(true);
|
||||
this.super->wake();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
|
||||
/*
|
||||
fill_in(render void, app. tile_app)
|
||||
*/
|
||||
|
||||
class game+, scene+, main+, edit_popup {
|
||||
|
||||
inherit game::control = super;
|
||||
|
||||
private import rt::c, lib::sdl2;
|
||||
|
||||
private alias string = std::string;
|
||||
|
||||
private alias
|
||||
button = control::button,
|
||||
edit = control::edit,
|
||||
image_button = control::image_button,
|
||||
label = control::label;
|
||||
|
||||
private alias tile_app = tile_menu::tile_app;
|
||||
|
||||
struct edit_popup {
|
||||
input_delay repeat;
|
||||
input_lock norepeat;
|
||||
new_icon string;
|
||||
focus_map focus_map;
|
||||
app. tile_app;
|
||||
label_title. label;
|
||||
label_cmd. label;
|
||||
label_icon. label;
|
||||
edit_title. edit;
|
||||
edit_cmd. edit;
|
||||
button_icon. image_button;
|
||||
button_cancel. button;
|
||||
button_save. button;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
func init(render void) bool {
|
||||
this.input_delay->init(300, -10, 20);
|
||||
var rect SDL_Rect = this->get_rect();
|
||||
var y int = 10;
|
||||
this.label_title = this->new_control<label>(10, y);
|
||||
this.label_title->set_text(render, "Title");
|
||||
this.edit_title = this->new_control<edit>(
|
||||
10, y += (this.label_title->get_height() + 3), rect.w - 20, 25);
|
||||
this.label_cmd = this->new_control<label>(
|
||||
10, y += (this.edit_title->get_height() + 3));
|
||||
this.label_cmd->set_text(render, "CommandLine");
|
||||
this.edit_cmd = this->new_control<edit>(
|
||||
10, y += (this.label_cmd->get_height() + 3), rect.w - 20, 25);
|
||||
this.label_icon = this->new_control<label>(
|
||||
10, y += (this.edit_cmd->get_height() + 3));
|
||||
this.label_icon->set_text(render, "Icon");
|
||||
this.button_icon = this->new_control<image_button>(
|
||||
10, y += (this.label_icon->get_height() + 3));
|
||||
this.button_icon->set_normal_image(render,
|
||||
global::make_path("main/tile_52x52.png"));
|
||||
this.button_icon->set_hover_image(render,
|
||||
global::make_path("main/tile_hover_52x52.png"));
|
||||
this.button_icon->set_outline_size(1);
|
||||
define {
|
||||
BUTTON_WIDTH = 70;
|
||||
BUTTON_HEIGHT = 30;
|
||||
}
|
||||
this.button_cancel = this->new_control<button>(
|
||||
rect.w - ((BUTTON_WIDTH * 2) + 16),
|
||||
rect.h - (BUTTON_HEIGHT + 10), BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
this.button_cancel->set_text(render, "Cancel");
|
||||
this.button_save = this->new_control<button>(
|
||||
rect.w - (BUTTON_WIDTH + 10),
|
||||
rect.h - (BUTTON_HEIGHT + 10), BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
this.button_save->set_text(render, "Save");
|
||||
this.focus_map->register(this.edit_title, null, this.edit_cmd, null, null);
|
||||
this.focus_map->register(this.edit_cmd, this.edit_title, this.button_icon, null, null);
|
||||
this.focus_map->register(this.button_icon, this.edit_cmd, null, null, this.button_cancel);
|
||||
this.focus_map->register(this.button_cancel, this.edit_cmd, null, this.button_icon, this.button_save);
|
||||
this.focus_map->register(this.button_save, this.edit_cmd, null, this.button_cancel, null);
|
||||
this->set_focus(this.edit_title);
|
||||
return true;
|
||||
}
|
||||
|
||||
func fill_in(render void, app. tile_app) {
|
||||
this.app = app;
|
||||
if app.title ~= null;
|
||||
this.edit_title->set_text(render, app.title);
|
||||
if app.cmd ~= null;
|
||||
this.edit_cmd->set_text(render, app.cmd);
|
||||
if app.icon ~= null;
|
||||
this.button_icon->set_image(render, app.icon);
|
||||
}
|
||||
|
||||
private func show_keybd(render void, title. char, edit. edit) {
|
||||
var wnd. window = this->get_window();
|
||||
var keybd. scene::keybd = wnd->new_scene<scene::keybd>();
|
||||
keybd->set_callback(edit->get_keybd_cb(), null, edit);
|
||||
keybd->set_fadeout(&this->get_parent_t<scene::main>().fadeio);
|
||||
keybd->set_title(render, title);
|
||||
keybd->set_text(render, edit->get_text());
|
||||
wnd->push_scene(this->get_parent());
|
||||
wnd->set_scene(keybd);
|
||||
}
|
||||
|
||||
private func close() {
|
||||
var parent. tile_menu = this->get_parent_control();
|
||||
parent->clear_link();
|
||||
parent->close_popup();
|
||||
}
|
||||
|
||||
func update(render void) {
|
||||
var state. uint8 = SDL_GetKeyboardState(null);
|
||||
if state[CPI_SCANCODE_UP] {
|
||||
if this.input_delay->do() {
|
||||
var focus void = this.focus_map->get(this->get_focus(), CPI_SCANCODE_UP);
|
||||
if focus ~= null;
|
||||
this->set_focus(focus);
|
||||
this.input_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_DOWN];
|
||||
if this.input_delay->do() {
|
||||
var focus void = this.focus_map->get(this->get_focus(), CPI_SCANCODE_DOWN);
|
||||
if focus ~= null;
|
||||
this->set_focus(focus);
|
||||
this.input_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_LEFT];
|
||||
if this.input_delay->do() {
|
||||
var focus void = this.focus_map->get(this->get_focus(), CPI_SCANCODE_LEFT);
|
||||
if focus ~= null;
|
||||
this->set_focus(focus);
|
||||
this.input_delay->undo();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_RIGHT];
|
||||
if this.input_delay->do() {
|
||||
var focus void = this.focus_map->get(this->get_focus(), CPI_SCANCODE_RIGHT);
|
||||
if focus ~= null;
|
||||
this->set_focus(focus);
|
||||
this.input_delay->undo();
|
||||
}
|
||||
else
|
||||
this.input_delay->reset();
|
||||
}
|
||||
if state[CPI_SCANCODE_A] or
|
||||
state[CPI_SCANCODE_MENU] {
|
||||
if this.input_lock->do() {
|
||||
this->close();
|
||||
}
|
||||
elseif state[CPI_SCANCODE_B];
|
||||
if this.input_lock->do() {
|
||||
var focus void = this->get_focus();
|
||||
if focus == this.edit_title {
|
||||
this->show_keybd(render, "Title", this.edit_title);
|
||||
elseif focus == this.edit_cmd;
|
||||
this->show_keybd(render, "CommandLine", this.edit_cmd);
|
||||
elseif focus == this.button_icon;
|
||||
var wnd. window = this->get_window();
|
||||
var browser. scene::file_browser = wnd->new_scene<scene::file_browser>();
|
||||
browser->set_callback(
|
||||
lambda(filename. char, this.edit_popup) [
|
||||
var render void = this->get_window()->get_render();
|
||||
if this.button_icon->set_image(render, filename) {
|
||||
this.new_icon->set(filename);
|
||||
else
|
||||
var app. tile_app = this.app;
|
||||
this.button_icon->set_image(render, app.icon);
|
||||
this.new_icon->clear();
|
||||
}
|
||||
], null, this
|
||||
);
|
||||
browser->set_fadeout(&this->get_parent_t<scene::main>().fadeio);
|
||||
browser->set_mode(
|
||||
scene::file_browser::mode.select_image);
|
||||
var path string;
|
||||
var cwd(0x800) char;
|
||||
if getcwd(&cwd, sizeof(cwd)) ~= null and
|
||||
browser->set_dir(wnd->get_render(), path->format("%s/icons", &cwd)) or
|
||||
browser->set_dir(wnd->get_render(), &cwd) {
|
||||
wnd->push_scene(this->get_parent());
|
||||
wnd->set_scene(browser);
|
||||
else
|
||||
wnd->free_scene(browser);
|
||||
}
|
||||
elseif focus == this.button_cancel;
|
||||
this->close();
|
||||
elseif focus == this.button_save;
|
||||
var tile_app. tile_app = this.app;
|
||||
var new_icon. char;
|
||||
if this.new_icon->empty() {
|
||||
new_icon = tile_app.icon;
|
||||
else
|
||||
new_icon = this.new_icon->ptr();
|
||||
}
|
||||
if tile_app.type == -1 {
|
||||
global::apps->insert(tile_app.slot, 1,
|
||||
this.edit_title->get_text(),
|
||||
this.edit_cmd->get_text(), new_icon);
|
||||
else
|
||||
global::apps->update(tile_app.slot, tile_app.type,
|
||||
this.edit_title->get_text(),
|
||||
this.edit_cmd->get_text(), new_icon);
|
||||
}
|
||||
var parent. tile_menu = this->get_parent_control();
|
||||
parent->reload_page(render);
|
||||
this->close();
|
||||
}
|
||||
}
|
||||
else
|
||||
this.input_lock->set(false);
|
||||
}
|
||||
this.super->update(render);
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
var rect SDL_Rect = this->get_rect();
|
||||
SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetRenderDrawColor(render, 245, 245, 245, 230);
|
||||
SDL_RenderFillRect(render, &rect);
|
||||
SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE);
|
||||
SDL_SetRenderDrawColor(render, 0xcd, 0xcd, 0xcd, 0xff);
|
||||
SDL_RenderDrawRect(render, &rect);
|
||||
this.super->draw(render);
|
||||
}
|
||||
|
||||
func wake() {
|
||||
this.input_delay->reset(false);
|
||||
this.input_lock->set(true);
|
||||
this.super->wake();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
|
||||
// template
|
||||
|
||||
class game+, scene+, temp {
|
||||
|
||||
inherit game::scene = super;
|
||||
|
||||
private import lib::sdl2;
|
||||
|
||||
struct temp {
|
||||
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
func init(render void) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
func update(render void) {
|
||||
this.super->update(render);
|
||||
}
|
||||
|
||||
func draw(render void) {
|
||||
SDL_SetRenderDrawColor(render, 0, 0, 0, 0xff);
|
||||
SDL_RenderClear(render);
|
||||
this.super->draw(render);
|
||||
}
|
||||
|
||||
func wake() {
|
||||
this.super->wake();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
/*
|
||||
powered by bean 0.382 r388
|
||||
*/
|
||||
|
||||
module app+ {
|
||||
|
||||
func main() {
|
||||
var launcher game::launcher;
|
||||
launcher->start("BeanShell");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
app::main();
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
|
||||
module program+ {
|
||||
|
||||
private import
|
||||
rt::c,
|
||||
lib::sdl2,
|
||||
lib::sdl2_image,
|
||||
lib::sdl2_mixer,
|
||||
lib::sdl2_ttf;
|
||||
|
||||
func startup() {
|
||||
std::init();
|
||||
if !lib::curl::so::init() or
|
||||
!lib::dbus::so::init() or
|
||||
!lib::sdl2::so::init() or
|
||||
!lib::sdl2_image::so::init() or
|
||||
!lib::sdl2_mixer::so::init() or
|
||||
!lib::sdl2_ttf::so::init()or
|
||||
!lib::sqlite3::so::init() {
|
||||
exit(1);
|
||||
}
|
||||
init_sdl();
|
||||
srand2(clock(), time(null), getpid());
|
||||
}
|
||||
|
||||
func cleanup() {
|
||||
quit_sdl();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module program+ {
|
||||
|
||||
func init_sdl() {
|
||||
if SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0 {
|
||||
printf("SDL_Init: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
if !IMG_Init(IMG_INIT_PNG) {
|
||||
printf("IMG_Init: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
if !Mix_Init(MIX_INIT_MP3) {
|
||||
printf("Mix_Init: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
if TTF_Init() == -1 {
|
||||
printf("TTF_Init: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
func quit_sdl() {
|
||||
TTF_Quit();
|
||||
Mix_Quit();
|
||||
IMG_Quit();
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
|
||||
/*
|
||||
FIXME
|
||||
*/
|
||||
|
||||
class app_list+ {
|
||||
|
||||
private import rt::c;
|
||||
|
||||
private alias
|
||||
string = std::string,
|
||||
vector = std::vector;
|
||||
|
||||
struct app {
|
||||
slot int;
|
||||
type int;
|
||||
title string;
|
||||
cmd string;
|
||||
icon string;
|
||||
extra string;
|
||||
}
|
||||
|
||||
struct app_list {
|
||||
db database;
|
||||
apps vector<app>;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this); }
|
||||
func destructor() {
|
||||
destructor(this); }
|
||||
|
||||
func init(filename. char) bool {
|
||||
if !this.db->open(filename);
|
||||
return false;
|
||||
this.db->exec(
|
||||
"
|
||||
CREATE TABLE IF NOT EXISTS apps (
|
||||
slot INTEGER PRIMARY KEY,
|
||||
type INTEGER NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
command TEXT NOT NULL,
|
||||
icon TEXT,
|
||||
extra TEXT
|
||||
);
|
||||
"
|
||||
);
|
||||
var stmt database::stmt;
|
||||
if !this.db->prepare(&stmt, "SELECT * FROM apps");
|
||||
return false;
|
||||
while stmt->step() {
|
||||
var app. app = this.apps->new();
|
||||
app.slot = stmt->column_int(0);
|
||||
app.type = stmt->column_int(1);
|
||||
app.title->set(stmt->column_text(2));
|
||||
app.cmd->set(stmt->column_text(3));
|
||||
app.icon->set(stmt->column_text(4));
|
||||
app.extra->set(stmt->column_text(5));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
func for_each(begin int, end int, callback void, arg void) {
|
||||
forvar i size_t = 0, c size_t = this.apps->count(); i < c; i++ {
|
||||
var app. app = this.apps->at(i);
|
||||
if app.slot >= begin and app.slot <= end {
|
||||
proto fn(app void, arg void);
|
||||
fn[callback](app, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func get_app_from_vector(slot int) .app {
|
||||
forvar index size_t = 0, count size_t = this.apps->count(); index < count; index++ {
|
||||
var app. app = this.apps->at(index);
|
||||
if app.slot == slot;
|
||||
return app;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
func remove_app_from_vector(slot int) bool {
|
||||
forvar index size_t = 0, count size_t = this.apps->count(); index < count; index++ {
|
||||
if this.apps->at(index).slot == slot;
|
||||
return this.apps->erase(index);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
func insert(slot int, type int, title. char, cmd. char, icon. char = null, extra. char = null) .app {
|
||||
if !this.db->execf("INSERT INTO apps (slot, type, title, command, icon, extra) VALUES (%d, %d, %Q, %Q, %Q, %Q)",
|
||||
slot, type, title, cmd, icon, extra) {
|
||||
return null;
|
||||
}
|
||||
func = this.apps->new();
|
||||
func.slot = slot;
|
||||
func.type = type;
|
||||
func.title->set(title);
|
||||
func.cmd->set(cmd);
|
||||
func.icon->set(icon);
|
||||
func.extra->set(extra);
|
||||
}
|
||||
|
||||
func update(slot int, type int, title. char, cmd. char, icon. char = null, extra. char = null) .app {
|
||||
if !this.db->execf("UPDATE apps SET type=%d, title=%Q, command=%Q, icon=%Q, extra=%Q WHERE slot=%d",
|
||||
type, title, cmd, icon, extra, slot) {
|
||||
return null;
|
||||
}
|
||||
/*
|
||||
fixme
|
||||
*/
|
||||
if (func = this->get_app_from_vector(slot)) == null;
|
||||
return;
|
||||
func.type = type;
|
||||
func.title->set(title);
|
||||
func.cmd->set(cmd);
|
||||
func.icon->set(icon);
|
||||
func.extra->set(extra);
|
||||
}
|
||||
|
||||
func remove(slot int) bool {
|
||||
this->remove_app_from_vector(slot);
|
||||
/*
|
||||
fixme
|
||||
*/
|
||||
return this.db->execf("DELETE FROM apps WHERE slot=%d", slot);
|
||||
}
|
||||
|
||||
func move(from int, to int) bool {
|
||||
this->remove(to);
|
||||
if !this.db->execf("UPDATE apps SET slot=%d WHERE slot=%d", to, from) {
|
||||
/*
|
||||
fixme
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
using app. app = this->get_app_from_vector(from) {
|
||||
if app ~= null {
|
||||
app.slot = to;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,221 +0,0 @@
|
||||
|
||||
class cfg {
|
||||
|
||||
private import rt::c;
|
||||
|
||||
private alias
|
||||
vector = std::vector,
|
||||
string = std::string;
|
||||
|
||||
struct item {
|
||||
name string;
|
||||
value string;
|
||||
cover char;
|
||||
}
|
||||
|
||||
struct cfg {
|
||||
items vector<item>;
|
||||
filename string;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
func open(filename. char) bool {
|
||||
define {
|
||||
SIZE_LIMIT = 0x1000000;
|
||||
}
|
||||
lambda read(filename. char, file_size& size_t) void [
|
||||
var stream void = fopen(filename, "rb");
|
||||
if stream == null;
|
||||
return null;
|
||||
defer fclose(stream);
|
||||
if fseek(stream, 0, SEEK_END) < 0;
|
||||
return null;
|
||||
var tail long = ftell(stream);
|
||||
if tail < 0 or tail > SIZE_LIMIT;
|
||||
return null;
|
||||
rewind(stream);
|
||||
func = malloc(tail);
|
||||
var offset size_t = 0;
|
||||
var remain size_t = tail;
|
||||
while remain {
|
||||
var size size_t = fread(func + offset, 1, remain, stream);
|
||||
if ferror(stream) {
|
||||
free(func);
|
||||
return null;
|
||||
}
|
||||
offset += size;
|
||||
remain -= size;
|
||||
}
|
||||
file_size = offset;
|
||||
];
|
||||
var size size_t;
|
||||
var buf. char = read(filename, size);
|
||||
if buf == null;
|
||||
return false;
|
||||
defer free(buf);
|
||||
this.items->clear();
|
||||
this.filename->clear();
|
||||
lambda skip_space(buf. char, index& size_t, size size_t) bool [
|
||||
for ; index < size; index++ {
|
||||
if !isspace(buf[index]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
];
|
||||
lambda skip_line(buf. char, index& size_t, size size_t, end& size_t) bool [
|
||||
for ; index < size; index++ {
|
||||
var c char = buf[index];
|
||||
if c == '\r' {
|
||||
end = index;
|
||||
if ++index < size {
|
||||
if buf[index] == '\n' {
|
||||
index++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
elseif c == '\n';
|
||||
end = index++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
end = index;
|
||||
return false;
|
||||
];
|
||||
lambda skip_name(buf. char, index& size_t, size size_t) bool [
|
||||
for ; index < size; index++ {
|
||||
var c char = buf[index];
|
||||
if c == ' ' or c == '\t' or c == '\r' or c == '\n' or c == '=' {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
];
|
||||
lambda skip_until(buf. char, index& size_t, size size_t, end char) bool [
|
||||
for ; index < size; index++ {
|
||||
if buf[index] == end {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
];
|
||||
forvar index size_t = 0 ;; {
|
||||
if !skip_space(buf, index, size);
|
||||
break;
|
||||
var name_offset size_t = index;
|
||||
if !skip_name(buf, index, size);
|
||||
break;
|
||||
var name_size size_t = index - name_offset;
|
||||
if !name_size;
|
||||
return false;
|
||||
if buf[index] ~= '=' {
|
||||
if !skip_space(buf, ++index, size);
|
||||
break;
|
||||
if buf[index] ~= '=';
|
||||
return false;
|
||||
}
|
||||
if !skip_space(buf, ++index, size);
|
||||
break;
|
||||
var value_offset size_t;
|
||||
var value_size size_t;
|
||||
var cover char;
|
||||
if buf[index] == '\'' or
|
||||
buf[index] == '\"' {
|
||||
cover = buf[index];
|
||||
value_offset = ++index;
|
||||
if !skip_until(buf, index, size, cover);
|
||||
break;
|
||||
value_size = index++ - value_offset;
|
||||
else
|
||||
value_offset = index;
|
||||
var end size_t;
|
||||
skip_line(buf, index, size, end);
|
||||
value_size = end - value_offset;
|
||||
cover = 0;
|
||||
}
|
||||
var item. item = this.items->new();
|
||||
item.name->set(buf + name_offset, name_size);
|
||||
if value_size;
|
||||
item.value->set(buf + value_offset, value_size);
|
||||
item.cover = cover;
|
||||
}
|
||||
this.filename->set(filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
func save(filename. char = null) bool {
|
||||
var stream void;
|
||||
if filename == null {
|
||||
if this.filename->empty();
|
||||
return false;
|
||||
stream = fopen(this.filename->ptr(), "w");
|
||||
else
|
||||
stream = fopen(filename, "w");
|
||||
}
|
||||
if stream == null;
|
||||
return false;
|
||||
forvar index size_t = 0, count size_t = this.items->count(); index < count; index++ {
|
||||
var item. item = this.items->at(index);
|
||||
if item.cover {
|
||||
fprintf("%s = %c%s%c\n",
|
||||
item.name->ptr(),
|
||||
item.cover,
|
||||
item.value->ptr(),
|
||||
item.cover);
|
||||
else
|
||||
fprintf("%s = %s\n",
|
||||
item.name->ptr(),
|
||||
item.value->ptr());
|
||||
}
|
||||
}
|
||||
fclose(stream);
|
||||
}
|
||||
|
||||
func find(name. char) .item {
|
||||
var count size_t = this.items->count();
|
||||
while count {
|
||||
var item. item = this.items->at(--count);
|
||||
if !strcasecmp(item.name->ptr(), name) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
func get(name. char) .char {
|
||||
var item. item = this->find(name);
|
||||
if item == null;
|
||||
return null;
|
||||
return item.value->ptr();
|
||||
}
|
||||
|
||||
func set(name. char, value. char) bool {
|
||||
var item. item = this->find(name);
|
||||
if item == null;
|
||||
return false;
|
||||
item.value->set(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
func add(name. char, value. char = null, cover char = '"') bool {
|
||||
var item. item = this->find(name);
|
||||
if item ~= null;
|
||||
return false;
|
||||
item = this.items->new();
|
||||
item.name->set(name);
|
||||
if value ~= null;
|
||||
item.value->set(value);
|
||||
item.cover = cover;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
|
||||
class database+ {
|
||||
|
||||
private import lib::sqlite3;
|
||||
|
||||
struct database {
|
||||
db void;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
this.db = null;
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
func open(filename+ char, flags int =
|
||||
SQLITE_OPEN_READWRITE |
|
||||
SQLITE_OPEN_CREATE) bool {
|
||||
this->close();
|
||||
return sqlite3_open_v2(filename, &this.db, flags, null) == SQLITE_OK;
|
||||
}
|
||||
|
||||
func close() {
|
||||
if this.db ~= null;
|
||||
sqlite3_close_v2(this.db), this.db = null;
|
||||
}
|
||||
|
||||
inline exec(sql+ char) bool {
|
||||
return sqlite3_exec(this.db, sql, null, null, null) == SQLITE_OK;
|
||||
}
|
||||
|
||||
func execf(sql+ char, ...) bool {
|
||||
if (sql = sqlite3_vmprintf(sql, va_start(this))) == null;
|
||||
return false;
|
||||
func = this->exec(sql);
|
||||
sqlite3_free(sql);
|
||||
}
|
||||
|
||||
inline prepare(stmt. stmt, sql+ char) bool {
|
||||
return sqlite3_prepare_v2(this.db, sql, -1, &stmt.obj, null) == SQLITE_OK;
|
||||
}
|
||||
|
||||
func preparef(stmt. stmt, sql+ char, ...) bool {
|
||||
if (sql = sqlite3_vmprintf(sql, va_start(this))) == null;
|
||||
return false;
|
||||
func = this->prepare(stmt, sql);
|
||||
sqlite3_free(sql);
|
||||
}
|
||||
|
||||
func prepare_step(stmt. stmt, sql+ char) bool {
|
||||
if !this->prepare(stmt, sql);
|
||||
return false;
|
||||
return stmt->step();
|
||||
}
|
||||
|
||||
func preparef_step(stmt. stmt, sql+ char, ...) bool {
|
||||
if (sql = sqlite3_vmprintf(sql, va_start(this))) == null;
|
||||
return false;
|
||||
defer sqlite3_free(sql);
|
||||
if !this->prepare(stmt, sql);
|
||||
return false;
|
||||
return stmt->step();
|
||||
}
|
||||
|
||||
inline last_insert_rowid() int64 {
|
||||
return sqlite3_last_insert_rowid(this.db);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
static inline free(ptr void) {
|
||||
sqlite3_free(ptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class database+, stmt {
|
||||
|
||||
private import lib::sqlite3;
|
||||
|
||||
struct stmt {
|
||||
obj void;
|
||||
step_error bool;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
this.obj = null;
|
||||
this.step_error = false;
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
this->finalize();
|
||||
}
|
||||
|
||||
inline bind_blob(index int, blob void, blob_size int, callback void) bool {
|
||||
return sqlite3_bind_blob(this.obj, index, blob, blob_size, callback) == SQLITE_OK;
|
||||
}
|
||||
|
||||
inline bind_double(index int, data double) bool {
|
||||
return sqlite3_bind_double(this.obj, index, data) == SQLITE_OK;
|
||||
}
|
||||
|
||||
inline bind_int(index int, data int) bool {
|
||||
return sqlite3_bind_int(this.obj, index, data) == SQLITE_OK;
|
||||
}
|
||||
|
||||
inline bind_null(index int) bool {
|
||||
return sqlite3_bind_null(this.obj, index) == SQLITE_OK;
|
||||
}
|
||||
|
||||
inline bind_text(index int, text+ char, text_len int, callback void) bool {
|
||||
return sqlite3_bind_text(this.obj, index, text, text_len, callback) == SQLITE_OK;
|
||||
}
|
||||
|
||||
inline bind_text16(index int, text void, text_len int, callback void) bool {
|
||||
return sqlite3_bind_text16(this.obj, index, text, text_len, callback) == SQLITE_OK;
|
||||
}
|
||||
|
||||
inline bind_text64(index int, text+ char, text_len int64, callback void, encoding char) bool {
|
||||
return sqlite3_bind_text64(this.obj, index, text, text_len, callback, encoding) == SQLITE_OK;
|
||||
}
|
||||
|
||||
inline bind_value(index int, value void) bool {
|
||||
return sqlite3_bind_value(this.obj, index, value) == SQLITE_OK;
|
||||
}
|
||||
|
||||
inline bind_zeroblob(index int, size int) bool {
|
||||
return sqlite3_bind_zeroblob(this.obj, index, size) == SQLITE_OK;
|
||||
}
|
||||
|
||||
inline bind_param_count() int {
|
||||
return sqlite3_bind_parameter_count(this.obj);
|
||||
}
|
||||
|
||||
inline bind_param_name(index int) +char {
|
||||
return sqlite3_bind_parameter_name(this.obj, index);
|
||||
}
|
||||
|
||||
inline bind_param_index(name+ char) int {
|
||||
return sqlite3_bind_parameter_index(this.obj, name);
|
||||
}
|
||||
|
||||
inline clear_bind() bool {
|
||||
return sqlite3_clear_bindings(this.obj) == SQLITE_OK;
|
||||
}
|
||||
|
||||
inline data_count() int {
|
||||
return sqlite3_data_count(this.obj);
|
||||
}
|
||||
|
||||
inline column_count() int {
|
||||
return sqlite3_column_count(this.obj);
|
||||
}
|
||||
|
||||
inline column_name(index int) +char {
|
||||
return sqlite3_column_name(this.obj, index);
|
||||
}
|
||||
|
||||
inline column_name16(index int) void {
|
||||
return sqlite3_column_name16(this.obj, index);
|
||||
}
|
||||
|
||||
func step() bool {
|
||||
var result int = sqlite3_step(this.obj);
|
||||
if result ~= SQLITE_ROW {
|
||||
/*
|
||||
SQLITE_BUSY
|
||||
SQLITE_ERROR
|
||||
SQLITE_MISUSE
|
||||
*/
|
||||
this.step_error = result ~= SQLITE_DONE;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline step_error?() bool {
|
||||
return this.step_error;
|
||||
}
|
||||
|
||||
inline reset() bool {
|
||||
return sqlite3_reset(this.obj) == SQLITE_OK;
|
||||
}
|
||||
|
||||
inline column_blob(col int) void {
|
||||
return sqlite3_column_blob(this.obj, col);
|
||||
}
|
||||
|
||||
inline column_double(col int) double {
|
||||
return sqlite3_column_double(this.obj, col);
|
||||
}
|
||||
|
||||
inline column_int(col int) int {
|
||||
return sqlite3_column_int(this.obj, col);
|
||||
}
|
||||
|
||||
inline column_text(col int) +char {
|
||||
return sqlite3_column_text(this.obj, col);
|
||||
}
|
||||
|
||||
inline column_text16(col int) void {
|
||||
return sqlite3_column_text16(this.obj, col);
|
||||
}
|
||||
|
||||
inline column_value(col int) void {
|
||||
return sqlite3_column_value(this.obj, col);
|
||||
}
|
||||
|
||||
inline column_bytes(col int) int {
|
||||
return sqlite3_column_bytes(this.obj, col);
|
||||
}
|
||||
|
||||
inline column_bytes16(col int) int {
|
||||
return sqlite3_column_bytes16(this.obj, col);
|
||||
}
|
||||
|
||||
inline column_type(col int) int {
|
||||
return sqlite3_column_type(this.obj, col);
|
||||
}
|
||||
|
||||
func finalize() bool {
|
||||
if this.obj ~= null {
|
||||
if sqlite3_finalize(this.obj) ~= SQLITE_OK;
|
||||
return false;
|
||||
this.obj = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
|
||||
func exec(file. char, ap void) bool {
|
||||
import rt::c;
|
||||
var pid pid_t = fork();
|
||||
if pid == -1 {
|
||||
return false;
|
||||
elseif pid == 0;
|
||||
execvp(file, ap);
|
||||
return false;
|
||||
else
|
||||
wait(null);
|
||||
/*
|
||||
for some reasons.
|
||||
*/
|
||||
sleep(1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
func exec2(cmd. char) bool {
|
||||
import rt::c;
|
||||
alias
|
||||
dmem = std::dmem,
|
||||
strings = std::strings;
|
||||
var args dmem;
|
||||
var strs strings;
|
||||
enum {
|
||||
mode_none,
|
||||
mode_word,
|
||||
mode_quote,
|
||||
mode_double_quote
|
||||
}
|
||||
var mode int = mode_none;
|
||||
var begin size_t;
|
||||
forvar index size_t = 0, count size_t = strlen(cmd); index < count; index++ {
|
||||
var c char = cmd[index];
|
||||
if c == ' ' or c == '\t' {
|
||||
if mode == mode_word {
|
||||
.args->alloc_t<char*>() =
|
||||
strs->add(cmd + begin, index - begin);
|
||||
mode = mode_none;
|
||||
}
|
||||
elseif c == '\'';
|
||||
if mode == mode_none {
|
||||
begin = index + 1;
|
||||
mode = mode_quote;
|
||||
elseif mode == mode_word;
|
||||
// fixme
|
||||
return false;
|
||||
elseif mode == mode_quote;
|
||||
.args->alloc_t<char*>() =
|
||||
strs->add(cmd + begin, index - begin);
|
||||
mode = mode_none;
|
||||
}
|
||||
elseif c == '\"';
|
||||
if mode == mode_none {
|
||||
begin = index + 1;
|
||||
mode = mode_double_quote;
|
||||
elseif mode == mode_word;
|
||||
// fixme
|
||||
return false;
|
||||
elseif mode == mode_double_quote;
|
||||
.args->alloc_t<char*>() =
|
||||
strs->add(cmd + begin, index - begin);
|
||||
mode = mode_none;
|
||||
}
|
||||
else
|
||||
if mode == mode_none {
|
||||
begin = index;
|
||||
mode = mode_word;
|
||||
}
|
||||
}
|
||||
}
|
||||
if mode == mode_word {
|
||||
.args->alloc_t<char*>() =
|
||||
strs->add(cmd + begin);
|
||||
}
|
||||
if strs->empty() {
|
||||
return false;
|
||||
}
|
||||
.args->alloc_t<char*>() = null;
|
||||
return exec(strs->first_item(), args.ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
fixme
|
||||
*/
|
||||
func exec3(window. game::window, text. char, cmd. char) bool {
|
||||
import lib::sdl2, game;
|
||||
define {
|
||||
PADDING = 10;
|
||||
}
|
||||
var render void = window->get_render();
|
||||
var font texture;
|
||||
font->init(global::uni_font->create_tex(render, text, 0xff000000));
|
||||
var width int = font->get_width();
|
||||
var height int = font->get_height();
|
||||
var rect SDL_Rect = 0;
|
||||
window->get_size(&rect.w, &rect.h);
|
||||
var sub_rect SDL_Rect;
|
||||
sub_rect.x = (rect.w - width) / 2 - PADDING;
|
||||
sub_rect.y = (rect.h - height) / 2 - PADDING;
|
||||
sub_rect.w = width + (PADDING * 2);
|
||||
sub_rect.h = height + (PADDING * 2);
|
||||
var screen texture;
|
||||
screen->init(window->screen_capture2());
|
||||
screen->draw(render, 0, 0);
|
||||
SDL_SetRenderDrawColor(render, 0xff, 0xff, 0xff, 0xff);
|
||||
SDL_RenderFillRect(render, &sub_rect);
|
||||
SDL_SetRenderDrawColor(render, 127, 127, 127, 0xff);
|
||||
SDL_RenderDrawRect(render, &sub_rect);
|
||||
font->draw(render,
|
||||
sub_rect.x + PADDING,
|
||||
sub_rect.y + PADDING);
|
||||
window->present();
|
||||
return exec2(cmd);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
func append_log(format. char, ...) {
|
||||
import rt::c;
|
||||
define {
|
||||
filename = "bean.log";
|
||||
}
|
||||
var stream void = fopen(filename, "a");
|
||||
if stream ~= null {
|
||||
vfprintf(stream, format, va_start(format));
|
||||
fclose(stream);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
|
||||
/*
|
||||
slow
|
||||
*/
|
||||
func find_pid_by_cmdline(cmdline. char) int {
|
||||
import rt::c;
|
||||
alias string = std::string,
|
||||
strings = std::strings;
|
||||
var dir void = opendir("/proc");
|
||||
defer closedir(dir);
|
||||
using ent. struct_dirent {
|
||||
while (ent = readdir(dir)) ~= null {
|
||||
if ent.d_type == DT_DIR {
|
||||
if ent.d_name[0] == '.' and !ent.d_name[1] or
|
||||
ent.d_name[1] == '.' and !ent.d_name[2] {
|
||||
continue;
|
||||
}
|
||||
if isnumeric(&ent.d_name) {
|
||||
lambda pread(cmd. char, lines. strings) bool [
|
||||
var stream void = popen(cmd, "r");
|
||||
if stream == null;
|
||||
return false;
|
||||
defer fclose(stream);
|
||||
var line(0x200) char;
|
||||
while fgets(&line, 0x200, stream) ~= null;
|
||||
lines->add(&line);
|
||||
return true;
|
||||
];
|
||||
static cmd string;
|
||||
static lines strings;
|
||||
lines->clear();
|
||||
if pread(cmd->format("sudo cat /proc/%s/cmdline", &ent.d_name), &lines) {
|
||||
if !lines->empty() {
|
||||
if !strcmp(lines->first_item(), cmdline);
|
||||
return atoi(&ent.d_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -1,411 +0,0 @@
|
||||
|
||||
class wifi+ {
|
||||
|
||||
private import rt::c, lib::dbus;
|
||||
|
||||
struct wifi {
|
||||
conn void;
|
||||
err DBusError;
|
||||
wicd wicd;
|
||||
wicd_wl wicd_wl;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
this.conn = null;
|
||||
dbus_error_init(&this.err);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
dbus_error_free(&this.err);
|
||||
}
|
||||
|
||||
func init() bool {
|
||||
this.conn = dbus_bus_get(DBUS_BUS_SYSTEM, &this.err);
|
||||
if dbus_error_is_set(&this.err);
|
||||
return false;
|
||||
this.wicd->init(this.conn);
|
||||
this.wicd_wl->init(this.conn);
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
func get_signal_strength() int {
|
||||
var iwconfig. char = null;
|
||||
if this.wicd->needs_external_calls() {
|
||||
if (iwconfig = this.wicd_wl->get_iwconfig()) == null;
|
||||
return -1;
|
||||
iwconfig = strdup(iwconfig);
|
||||
}
|
||||
if this.wicd->get_signal_disply_type() == 0 {
|
||||
func = this.wicd_wl->get_cur_signal_strength(iwconfig);
|
||||
else
|
||||
func = this.wicd_wl->get_cur_dbm_strength(iwconfig);
|
||||
}
|
||||
if iwconfig ~= null;
|
||||
free(iwconfig);
|
||||
}
|
||||
|
||||
func is_connecting() bool {
|
||||
return this.wicd_wl->check_if_wireless_connecting();
|
||||
}
|
||||
|
||||
func is_connected(signal_strength. int = null) bool {
|
||||
if this.wicd_wl->check_if_wireless_connecting();
|
||||
return false;
|
||||
var x int = this->get_signal_strength();
|
||||
if x == -1;
|
||||
return false;
|
||||
if signal_strength ~= null;
|
||||
.signal_strength = x;
|
||||
return true;
|
||||
}
|
||||
|
||||
func scan(sync bool = false) {
|
||||
this.wicd_wl->scan(sync);
|
||||
}
|
||||
|
||||
func connect(id int) {
|
||||
this.wicd_wl->connect(id);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
inline get_sys_bus() void {
|
||||
return this.conn;
|
||||
}
|
||||
|
||||
inline get_bus_err() .DBusError {
|
||||
return &this.err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class wifi+, signal_thread {
|
||||
|
||||
private import rt::c, lib::dbus;
|
||||
|
||||
private alias
|
||||
string = std::string,
|
||||
vector = std::vector;
|
||||
|
||||
struct hook {
|
||||
iface. char;
|
||||
sig_name. char;
|
||||
callback void;
|
||||
arg void;
|
||||
}
|
||||
|
||||
struct signal_thread {
|
||||
thread pthread_t;
|
||||
wifi. wifi;
|
||||
hooks vector<hook>;
|
||||
}
|
||||
|
||||
func constructor() {
|
||||
this.thread = null;
|
||||
this.wifi = null;
|
||||
constructor(this);
|
||||
}
|
||||
|
||||
func destructor() {
|
||||
this->stop();
|
||||
destructor(this);
|
||||
}
|
||||
|
||||
func init(wifi. wifi) {
|
||||
this.wifi = wifi;
|
||||
}
|
||||
|
||||
/*
|
||||
callback = lambda(arg void, iter void) [
|
||||
...
|
||||
];
|
||||
*/
|
||||
func hook_signal(iface. char, sig_name. char, callback void, arg void) bool {
|
||||
if this.thread ~= null;
|
||||
return false;
|
||||
var conn void = this.wifi->get_sys_bus();
|
||||
var err void = this.wifi->get_bus_err();
|
||||
using rule string;
|
||||
dbus_bus_add_match(conn,
|
||||
rule->format("type='signal',interface='%s'", iface), err);
|
||||
dbus_connection_flush(conn);
|
||||
if dbus_error_is_set(err);
|
||||
return false;
|
||||
var hook. hook = this.hooks->new();
|
||||
hook.iface = iface;
|
||||
hook.sig_name = sig_name;
|
||||
hook.callback = callback;
|
||||
hook.arg = arg;
|
||||
return true;
|
||||
}
|
||||
|
||||
func start() bool {
|
||||
if this.thread ~= null;
|
||||
return true;
|
||||
if pthread_create(&this.thread, null, lambda(this.signal_thread) void [
|
||||
var conn void = this.wifi->get_sys_bus();
|
||||
while this.thread ~= null {
|
||||
for ;; {
|
||||
dbus_connection_read_write(conn, 0);
|
||||
var msg void = dbus_connection_pop_message(conn);
|
||||
if msg == null;
|
||||
break;
|
||||
forvar index size_t = 0, count size_t = this.hooks->count(); index < count; index++ {
|
||||
var hook. hook = this.hooks->at(index);
|
||||
if dbus_message_is_signal(msg, hook.iface, hook.sig_name) {
|
||||
var iter void;
|
||||
if !dbus_message_iter_init(msg, &iter);
|
||||
iter = null;
|
||||
proto fn(arg void, iter void);
|
||||
fn[hook.callback](hook.arg, iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
], this));
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
func stop() {
|
||||
var thread pthread_t = this.thread;
|
||||
if thread ~= null {
|
||||
this.thread = null;
|
||||
pthread_join(thread, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class wifi+, dbus {
|
||||
|
||||
private import lib::dbus;
|
||||
|
||||
struct dbus {
|
||||
conn void;
|
||||
bus_name. char;
|
||||
path. char;
|
||||
iface. char;
|
||||
}
|
||||
|
||||
func init(conn void, bus_name. char, path. char, iface. char) {
|
||||
this.conn = conn;
|
||||
this.bus_name = bus_name;
|
||||
this.path = path;
|
||||
this.iface = iface;
|
||||
}
|
||||
|
||||
func call(method. char, format. char = null, ...) void {
|
||||
var msg void = dbus_message_new_method_call(this.bus_name, this.path, this.iface, method);
|
||||
if msg == null;
|
||||
return null;
|
||||
defer dbus_message_unref(msg);
|
||||
if format ~= null {
|
||||
var args DBusMessageIter;
|
||||
dbus_message_iter_init_append(msg, &args);
|
||||
forvar ap void = va_start(this) ;; {
|
||||
var type char = .format++;
|
||||
if !type;
|
||||
break;
|
||||
if !dbus_message_iter_append_basic(&args, type, ap);
|
||||
return null;
|
||||
va_next<word>(ap);
|
||||
}
|
||||
}
|
||||
if !dbus_connection_send_with_reply(this.conn, msg, &func, -1);
|
||||
return null;
|
||||
if func ~= null;
|
||||
dbus_connection_flush(this.conn);
|
||||
}
|
||||
|
||||
static func get(pending void, format. char = null, ...) bool {
|
||||
if pending == null;
|
||||
return false;
|
||||
dbus_pending_call_block(pending);
|
||||
var msg void = dbus_pending_call_steal_reply(pending);
|
||||
dbus_pending_call_unref(pending);
|
||||
if msg == null;
|
||||
return false;
|
||||
defer dbus_message_unref(msg);
|
||||
if format ~= null {
|
||||
var args DBusMessageIter;
|
||||
if dbus_message_iter_init(msg, &args) {
|
||||
forvar ap. void = va_start(pending) ;; {
|
||||
var type char = .format++;
|
||||
if !type;
|
||||
break;
|
||||
if dbus_message_iter_get_arg_type(&args) ~= type;
|
||||
return false;
|
||||
dbus_message_iter_get_basic(&args, .ap);
|
||||
if !dbus_message_iter_next(&args);
|
||||
break;
|
||||
va_next<void>(ap);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class wifi+, wicd {
|
||||
|
||||
private import lib::dbus;
|
||||
|
||||
struct wicd {
|
||||
bus dbus;
|
||||
}
|
||||
|
||||
func init(conn void) {
|
||||
this.bus->init(conn,
|
||||
"org.wicd.daemon", "/org/wicd/daemon",
|
||||
"org.wicd.daemon");
|
||||
}
|
||||
|
||||
func format_signal_for_printing(signal int) .char {
|
||||
func = null;
|
||||
this.bus->get(
|
||||
this.bus->call("FormatSignalForPrinting", "i", signal), "s", &func);
|
||||
}
|
||||
|
||||
func get_signal_disply_type() int {
|
||||
func = -1;
|
||||
this.bus->get(
|
||||
this.bus->call("GetSignalDisplayType"), "i", &func);
|
||||
}
|
||||
|
||||
func needs_external_calls() dbus_bool_t {
|
||||
func = 0;
|
||||
this.bus->get(
|
||||
this.bus->call("NeedsExternalCalls"), "b", &func);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class wifi+, wicd_wl {
|
||||
|
||||
private import lib::dbus;
|
||||
|
||||
struct wicd_wl {
|
||||
bus dbus;
|
||||
}
|
||||
|
||||
func init(conn void) {
|
||||
this.bus->init(conn,
|
||||
"org.wicd.daemon", "/org/wicd/daemon/wireless",
|
||||
"org.wicd.daemon.wireless");
|
||||
}
|
||||
|
||||
func check_if_wireless_connecting() dbus_bool_t {
|
||||
func = 0;
|
||||
this.bus->get(
|
||||
this.bus->call("CheckIfWirelessConnecting"), "b", &func);
|
||||
}
|
||||
|
||||
func check_wireless_connecting_msg() .char {
|
||||
func = null;
|
||||
this.bus->get(
|
||||
this.bus->call("CheckWirelessConnectingMessage"), "s", &func);
|
||||
}
|
||||
|
||||
// result?
|
||||
func connect(id int) {
|
||||
this.bus->get(
|
||||
this.bus->call("ConnectWireless", "i", id));
|
||||
}
|
||||
|
||||
func get_cur_dbm_strength(iwconfig. char) int {
|
||||
func = -1;
|
||||
var pending void;
|
||||
if iwconfig == null {
|
||||
pending = this.bus->call("GetCurrentDBMStrength");
|
||||
else
|
||||
pending = this.bus->call("GetCurrentDBMStrength", "s", iwconfig);
|
||||
}
|
||||
this.bus->get(pending, "i", &func);
|
||||
}
|
||||
|
||||
func get_cur_signal_strength(iwconfig. char) int {
|
||||
func = -1;
|
||||
var pending void;
|
||||
if iwconfig == null {
|
||||
pending = this.bus->call("GetCurrentSignalStrength");
|
||||
else
|
||||
pending = this.bus->call("GetCurrentSignalStrength", "s", iwconfig);
|
||||
}
|
||||
this.bus->get(pending, "i", &func);
|
||||
}
|
||||
|
||||
func get_cur_network(iwconfig. char) .char {
|
||||
func = null;
|
||||
var pending void;
|
||||
if iwconfig == null {
|
||||
pending = this.bus->call("GetCurrentNetwork");
|
||||
else
|
||||
pending = this.bus->call("GetCurrentNetwork", "s", iwconfig);
|
||||
}
|
||||
this.bus->get(pending, "s", &func);
|
||||
}
|
||||
|
||||
func get_cur_network_id(iwconfig. char) int {
|
||||
func = -1;
|
||||
var pending void;
|
||||
if iwconfig == null {
|
||||
pending = this.bus->call("GetCurrentNetworkID");
|
||||
else
|
||||
pending = this.bus->call("GetCurrentNetworkID", "s", iwconfig);
|
||||
}
|
||||
this.bus->get(pending, "i", &func);
|
||||
}
|
||||
|
||||
func get_iwconfig() .char {
|
||||
func = null;
|
||||
this.bus->get(
|
||||
this.bus->call("GetIwconfig"), "s", &func);
|
||||
}
|
||||
|
||||
func get_num_of_networks() int {
|
||||
func = -1;
|
||||
this.bus->get(
|
||||
this.bus->call("GetNumberOfNetworks"), "i", &func);
|
||||
}
|
||||
|
||||
func get_wireless_ip(s. char) .char {
|
||||
func = null;
|
||||
var pending void;
|
||||
if s == null {
|
||||
pending = this.bus->call("GetWirelessIP");
|
||||
else
|
||||
pending = this.bus->call("GetWirelessIP", "s", s);
|
||||
}
|
||||
this.bus->get(pending, "s", &func);
|
||||
}
|
||||
|
||||
func get_wireless_prop(id int, prop_name. char) .char {
|
||||
func = null;
|
||||
this.bus->get(
|
||||
this.bus->call("GetWirelessProperty", "is", id, prop_name), "s", &func);
|
||||
}
|
||||
|
||||
// result?
|
||||
func scan(sync dbus_bool_t) {
|
||||
this.bus->get(
|
||||
this.bus->call("Scan", "b", sync));
|
||||
}
|
||||
|
||||
func set_wireless_prop_str(id int, prop_name. char, s. char) bool {
|
||||
return this.bus->get(
|
||||
this.bus->call("SetWirelessProperty", "iss", id, prop_name, s));
|
||||
}
|
||||
|
||||
func set_wireless_prop_int(id int, prop_name. char, i int) bool {
|
||||
return this.bus->get(
|
||||
this.bus->call("SetWirelessProperty", "isi", id, prop_name, i));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user