2017-09-01 15:24:32 +03:00
/*
2017-09-07 23:00:08 +03:00
* meli - bin . rs
2017-09-01 15:24:32 +03:00
*
2018-07-16 15:26:06 +03:00
* Copyright 2017 - 2018 Manos Pitsidianakis
2017-09-07 23:00:08 +03:00
*
2017-09-01 15:24:32 +03:00
* This file is part of meli .
*
* meli is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* meli is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with meli . If not , see < http ://www.gnu.org/licenses/>.
* /
2018-07-18 10:42:52 +03:00
/*! This crate contains the frontend stuff of the application. The application entry way on `src / bin.rs` creates an event loop and passes input to the `ui` module.
The mail handling stuff is done in the ` melib ` crate which includes all backend needs . The split is done to theoretically be able to create different frontends with the same innards .
* /
2017-09-07 23:00:08 +03:00
extern crate melib ;
2018-07-20 12:15:06 +03:00
extern crate ui ;
2018-07-16 11:08:04 +03:00
use ui ::* ;
2018-07-11 18:58:57 +03:00
pub use melib ::* ;
2017-09-01 15:24:32 +03:00
2017-09-28 18:06:35 +03:00
use std ::thread ;
2018-07-11 17:07:51 +03:00
use std ::io ::{ stdout , stdin , } ;
2017-09-28 18:06:35 +03:00
2018-07-16 13:36:28 +03:00
#[ macro_use ]
extern crate chan ;
extern crate chan_signal ;
use chan_signal ::Signal ;
2017-07-23 14:01:17 +03:00
fn main ( ) {
2018-07-11 17:07:51 +03:00
/* Lock all stdios */
let _stdout = stdout ( ) ;
let mut _stdout = _stdout . lock ( ) ;
let stdin = stdin ( ) ;
let stdin = stdin ;
/*
2018-07-13 18:38:57 +03:00
let _stderr = stderr ( ) ;
let mut _stderr = _stderr . lock ( ) ;
* /
2018-07-11 17:07:51 +03:00
2018-07-16 15:26:06 +03:00
/* Catch SIGWINCH to handle terminal resizing */
2018-07-16 13:36:28 +03:00
let signal = chan_signal ::notify ( & [ Signal ::WINCH ] ) ;
2018-07-16 15:26:06 +03:00
/* Create a channel to communicate with other threads. The main process is the sole receiver.
* * /
2018-07-16 13:36:28 +03:00
let ( sender , receiver ) = chan ::sync ( ::std ::mem ::size_of ::< ThreadEvent > ( ) ) ;
2017-09-28 18:06:35 +03:00
{
let sender = sender . clone ( ) ;
2018-07-11 17:07:51 +03:00
thread ::Builder ::new ( ) . name ( " input-thread " . to_string ( ) ) . spawn ( move | | {
2018-07-16 13:36:28 +03:00
get_events ( stdin , move | k | { sender . send ( ThreadEvent ::Input ( k ) ) ;
2018-07-13 18:38:57 +03:00
} ) } ) . unwrap ( ) ;
2017-09-28 18:06:35 +03:00
}
2018-07-16 15:26:06 +03:00
/* Create the application State. This is the 'System' part of an ECS architecture */
let mut state = State ::new ( _stdout , sender ) ;
2018-07-11 17:07:51 +03:00
2018-07-16 15:26:06 +03:00
/* Register some reasonably useful interfaces */
2018-07-14 21:41:38 +03:00
let menu = Entity { component : Box ::new ( AccountMenu ::new ( & state . context . accounts ) ) } ;
2018-07-16 15:26:06 +03:00
let listing = MailListing ::new ( ) ;
2018-07-11 17:07:51 +03:00
let b = Entity { component : Box ::new ( listing ) } ;
2018-07-17 17:16:16 +03:00
let window = Entity { component : Box ::new ( VSplit ::new ( menu , b , 80 ) ) } ;
2018-07-14 15:04:42 +03:00
let status_bar = Entity { component : Box ::new ( StatusBar ::new ( window ) ) } ;
state . register_entity ( status_bar ) ;
2018-07-13 18:38:57 +03:00
2018-07-17 17:16:16 +03:00
let xdg_notifications = Entity { component : Box ::new ( ui ::components ::notifications ::XDGNotifications { } ) } ;
state . register_entity ( xdg_notifications ) ;
2018-07-16 15:26:06 +03:00
/* Keep track of the input mode. See ui::UIMode for details */
2018-07-15 01:27:13 +03:00
let mut mode : UIMode = UIMode ::Normal ;
2017-09-16 15:05:28 +03:00
' main : loop {
2018-07-14 21:41:38 +03:00
state . render ( ) ;
2017-07-23 14:01:17 +03:00
2017-09-16 15:05:28 +03:00
' inner : loop {
2018-07-16 15:26:06 +03:00
/* Check if any entities have sent reply events to State. */
2018-07-16 11:08:04 +03:00
let events : Vec < UIEvent > = state . context . get_replies ( ) ;
for e in events {
state . rcv_event ( e ) ;
}
state . redraw ( ) ;
2018-07-16 15:26:06 +03:00
/* Poll on all channels. Currently we have the input channel for stdin, watching events and the signal watcher. */
2018-07-16 13:36:28 +03:00
chan_select! {
receiver . recv ( ) -> r = > {
match r . unwrap ( ) {
ThreadEvent ::Input ( k ) = > {
match mode {
UIMode ::Normal = > {
match k {
Key ::Char ( 'q' ) | Key ::Char ( 'Q' ) = > {
2018-07-17 17:16:16 +03:00
drop ( state ) ;
2018-07-16 13:36:28 +03:00
break 'main ;
} ,
Key ::Char ( ';' ) = > {
mode = UIMode ::Execute ;
state . rcv_event ( UIEvent { id : 0 , event_type : UIEventType ::ChangeMode ( mode ) } ) ;
state . redraw ( ) ;
}
key = > {
state . rcv_event ( UIEvent { id : 0 , event_type : UIEventType ::Input ( key ) } ) ;
state . redraw ( ) ;
} ,
}
2018-07-15 01:27:13 +03:00
} ,
2018-07-16 13:36:28 +03:00
UIMode ::Execute = > {
match k {
Key ::Char ( '\n' ) | Key ::Esc = > {
mode = UIMode ::Normal ;
state . rcv_event ( UIEvent { id : 0 , event_type : UIEventType ::ChangeMode ( mode ) } ) ;
state . redraw ( ) ;
} ,
k @ Key ::Char ( _ ) = > {
state . rcv_event ( UIEvent { id : 0 , event_type : UIEventType ::ExInput ( k ) } ) ;
state . redraw ( ) ;
} ,
_ = > { } ,
}
2018-07-16 11:08:04 +03:00
} ,
2018-07-15 01:27:13 +03:00
}
2018-07-13 18:38:57 +03:00
} ,
2018-07-16 13:36:28 +03:00
ThreadEvent ::RefreshMailbox { name : n } = > {
2018-07-17 17:16:16 +03:00
state . rcv_event ( UIEvent { id : 0 , event_type : UIEventType ::Notification ( n . clone ( ) ) } ) ;
state . redraw ( ) ;
2018-07-16 15:26:06 +03:00
/* Don't handle this yet. */
2018-07-16 13:36:28 +03:00
eprintln! ( " Refresh mailbox {} " , n ) ;
} ,
ThreadEvent ::UIEventType ( e ) = > {
state . rcv_event ( UIEvent { id : 0 , event_type : e } ) ;
state . render ( ) ;
2018-07-13 18:38:57 +03:00
} ,
2017-09-28 18:06:35 +03:00
}
2017-09-01 15:24:32 +03:00
} ,
2018-07-16 13:36:28 +03:00
signal . recv ( ) -> signal = > {
if let Some ( Signal ::WINCH ) = signal {
state . update_size ( ) ;
state . render ( ) ;
state . redraw ( ) ;
}
2018-07-13 18:38:57 +03:00
} ,
2017-07-23 14:01:17 +03:00
}
}
}
}