#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
use std::{env, path::PathBuf, str::FromStr};
use bincode::{Decode, Encode};
use cloning::CloningInsertData;
use copypasta::ClipboardProvider;
use eframe::{
self,
egui::{self},
};
use file_io::save::{QUICKSAVE_FILE, load_import};
use gui::navigation::{Page, PageSeq};
use na_seq::{AaIdent, Nucleotide, Seq, restriction_enzyme::RestrictionEnzyme};
use state::State;
use crate::{
backbones::BackboneFilters,
file_io::{FileDialogs, save::DEFAULT_PREFS_FILE},
gui::{
WINDOW_HEIGHT, WINDOW_WIDTH,
navigation::{PageSeqTop, Tab},
},
misc_types::{FeatureDirection, FeatureType},
pcr::PcrUi,
primer::TM_TARGET,
util::{RangeIncl, get_window_title},
};
mod alignment;
mod alignment_map;
mod backbones;
mod cloning;
mod external_websites;
mod feature_db_load;
mod file_io;
mod gui;
mod melting_temp_calcs;
mod misc_types;
mod pcr;
mod portions;
mod primer;
mod primer_metrics;
mod protein;
mod reading_frame;
mod save_compat;
mod solution_helper;
mod state;
mod tags;
mod toxic_proteins;
mod util;
type Color = (u8, u8, u8);
const PREFS_SAVE_INTERVAL: u64 = 60;
#[derive(Default, Encode, Decode)]
struct StateFeatureAdd {
start_posit: usize,
end_posit: usize,
feature_type: FeatureType,
direction: FeatureDirection,
label: String,
color: Option<Color>,
}
#[derive(Clone, Encode, Decode)]
struct SeqVisibility {
show_res: bool,
show_primers: bool,
show_features: bool,
show_reading_frame: bool,
}
impl Default for SeqVisibility {
fn default() -> Self {
Self {
show_res: true,
show_primers: true,
show_features: true,
show_reading_frame: false,
}
}
}
pub struct ReUi {
res_selected: Vec<RestrictionEnzyme>,
tabs_selected: Vec<usize>,
unique_cutters_only: bool,
sticky_ends_only: bool,
multiple_seqs: bool,
}
impl Default for ReUi {
fn default() -> Self {
Self {
res_selected: Default::default(),
tabs_selected: Default::default(),
unique_cutters_only: true,
sticky_ends_only: false,
multiple_seqs: true,
}
}
}
struct StateUi {
page: Page,
page_seq: PageSeq,
page_seq_top: PageSeqTop,
seq_input: String, pcr: PcrUi,
feature_add: StateFeatureAdd,
feature_hover: Option<usize>, selected_item: Selection,
seq_visibility: SeqVisibility,
hide_map_feature_editor: bool,
cursor_pos: Option<(f32, f32)>,
cursor_seq_i: Option<usize>,
file_dialogs: FileDialogs,
show_origin_change: bool,
new_origin: usize,
text_cursor_i: Option<usize>,
click_pending_handle: bool,
dblclick_pending_handle: bool,
cloning_insert: CloningInsertData,
nt_chars_per_row: usize,
search_input: String,
highlight_search_input: bool,
text_edit_active: bool,
dragging: bool,
text_selection: Option<RangeIncl>,
quick_feature_add_name: String,
quick_feature_add_dir: FeatureDirection,
aa_ident_disp: AaIdent,
pdb_error_received: bool,
re: ReUi,
backbone_filters: BackboneFilters,
seq_edit_lock: bool,
ab1_start_i: usize,
}
impl Default for StateUi {
fn default() -> Self {
Self {
page: Default::default(),
page_seq: Default::default(),
page_seq_top: Default::default(),
seq_input: Default::default(),
pcr: Default::default(),
feature_add: Default::default(),
feature_hover: Default::default(),
selected_item: Default::default(),
seq_visibility: Default::default(),
hide_map_feature_editor: true,
cursor_pos: Default::default(),
cursor_seq_i: Default::default(),
file_dialogs: Default::default(),
show_origin_change: Default::default(),
new_origin: Default::default(),
text_cursor_i: Some(0),
click_pending_handle: Default::default(),
dblclick_pending_handle: Default::default(),
cloning_insert: Default::default(),
nt_chars_per_row: Default::default(),
search_input: Default::default(),
highlight_search_input: Default::default(),
text_edit_active: Default::default(),
dragging: Default::default(),
text_selection: Default::default(),
quick_feature_add_name: Default::default(),
quick_feature_add_dir: Default::default(),
aa_ident_disp: AaIdent::OneLetter,
pdb_error_received: false,
re: Default::default(),
backbone_filters: Default::default(),
seq_edit_lock: true,
ab1_start_i: Default::default(),
}
}
}
#[derive(Clone, Copy, PartialEq, Debug, Encode, Decode)]
pub enum Selection {
Feature(usize), Primer(usize),
None,
}
impl Default for Selection {
fn default() -> Self {
Self::None
}
}
fn main() {
let mut state = State::default();
state.load_prefs(&PathBuf::from_str(DEFAULT_PREFS_FILE).unwrap());
let mut loaded_from_arg = false;
let (path, window_title_initial) = {
let mut p = PathBuf::from_str(QUICKSAVE_FILE).unwrap();
let args: Vec<String> = env::args().collect();
if args.len() > 1 {
let temp = &args[1];
p = PathBuf::from_str(temp).unwrap();
loaded_from_arg = true;
}
let window_title = get_window_title(&p);
(p, window_title)
};
let mut prev_paths_loaded = false;
for tab in &state.tabs_open {
if tab.path.is_some() {
prev_paths_loaded = true;
}
}
if loaded_from_arg || !prev_paths_loaded {
println!("Loading from quicksave or arg: {:?}", path);
if let Some(loaded) = load_import(&path) {
state.load(&loaded);
}
}
state.sync_seq_related(None);
state.reset_selections();
let icon_bytes: &[u8] = include_bytes!("resources/icon.png");
let icon_data = eframe::icon_data::from_png_bytes(icon_bytes);
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([WINDOW_WIDTH, WINDOW_HEIGHT])
.with_icon(icon_data.unwrap()),
..Default::default()
};
eframe::run_native(
&window_title_initial,
options,
Box::new(|_cc| Ok(Box::new(state))),
)
.unwrap();
}