Compare commits
No commits in common. "main" and "0.1.0" have entirely different histories.
28
Cargo.toml
|
|
@ -1,31 +1,21 @@
|
||||||
[package]
|
[package]
|
||||||
name = "tarangam"
|
name = "tarangam"
|
||||||
version = "0.3.1"
|
version = "0.1.0"
|
||||||
authors = ["PiyushXCoder <piyush.raj.kit@gmail.com>"]
|
authors = ["PiyushXCoder <piyush.raj.kit@gmail.com>"]
|
||||||
license = "GPL-3.0-only"
|
license = "GPL 3.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "A simple serial plotter. एक सरल सीरीय्ल पलौटर।"
|
documentation = "A simple serial plotter. एक सरल सीरीय्ल पलौटर।"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/PiyushXCoder/Tarangam"
|
repository = "https://github.com/PiyushXCoder/Tarangam"
|
||||||
keywords = ["plotter","serial","serialplotter","arduino","gtk"]
|
keywords = ["plotter","serial","serialplotter","arduino","gtk"]
|
||||||
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tokio = { version = "1.5.0", features = [
|
gtk = "0.9.2"
|
||||||
"rt",
|
gio = "0.9.1"
|
||||||
"rt-multi-thread",
|
glib = "0.10.3"
|
||||||
"macros",
|
png = "0.16.8"
|
||||||
"time",
|
cairo-rs = { version = "0.9.1", features = ["png"] }
|
||||||
"sync",
|
|
||||||
] }
|
|
||||||
gtk = "0.15"
|
|
||||||
gdk = "0.15"
|
|
||||||
gio = "0.15"
|
|
||||||
glib = "0.15"
|
|
||||||
png = "0.17"
|
|
||||||
cairo-rs = { version = "0.15", features = ["png"] }
|
|
||||||
rand = "0.8.1"
|
rand = "0.8.1"
|
||||||
libmath = "0.2.1"
|
libmath = "0.2.1"
|
||||||
serialport = "4.0.1"
|
serialport = "4.0.0"
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
# Tarangam
|
# Tarangam
|
||||||
It is a straightforward application to see the logs from [serial ports](https://wiki.osdev.org/Serial_Ports) and plot information on graph. You can use it with IOT boards ([Arduino](https://www.arduino.cc/), [ESP boards](https://www.espressif.com/),...) in your DIY projects. It gives many basic controls to modify the graph.
|
|
||||||
|
It is a simple application to see log from [serialports](https://wiki.osdev.org/Serial_Ports) and plot information on graph. You can use it with IOT boards([ardino](https://www.arduino.cc/), [esp boards](https://www.espressif.com/),...) in you DIY projects. It gives to many basic controls to control graph.
|
||||||
|
|
||||||
## Interface
|
## Interface
|
||||||

|

|
||||||
|
|
|
||||||
BIN
chitra-small.png
|
Before Width: | Height: | Size: 2.2 KiB |
BIN
chitra.png
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
44
chitra.svg
|
|
@ -1,23 +1,20 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<svg
|
<svg
|
||||||
width="256"
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
height="256"
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="1000"
|
||||||
|
height="1000"
|
||||||
viewBox="0 0 1000 1000"
|
viewBox="0 0 1000 1000"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
id="svg8"
|
id="svg8"
|
||||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
|
||||||
sodipodi:docname="chitra.svg"
|
sodipodi:docname="icon.svg">
|
||||||
inkscape:export-filename="/home/piyush/Projects/tarangam/chitra-small.png"
|
|
||||||
inkscape:export-xdpi="24"
|
|
||||||
inkscape:export-ydpi="24"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
|
||||||
<defs
|
<defs
|
||||||
id="defs2">
|
id="defs2">
|
||||||
<linearGradient
|
<linearGradient
|
||||||
|
|
@ -50,20 +47,19 @@
|
||||||
inkscape:pageopacity="0.0"
|
inkscape:pageopacity="0.0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:zoom="0.35"
|
inkscape:zoom="0.35"
|
||||||
inkscape:cx="607.14286"
|
inkscape:cx="605.76766"
|
||||||
inkscape:cy="250"
|
inkscape:cy="248.85918"
|
||||||
inkscape:document-units="px"
|
inkscape:document-units="px"
|
||||||
inkscape:current-layer="layer1"
|
inkscape:current-layer="layer1"
|
||||||
inkscape:document-rotation="0"
|
inkscape:document-rotation="0"
|
||||||
showgrid="false"
|
showgrid="false"
|
||||||
inkscape:window-width="1920"
|
inkscape:window-width="1214"
|
||||||
inkscape:window-height="1002"
|
inkscape:window-height="757"
|
||||||
inkscape:window-x="0"
|
inkscape:window-x="295"
|
||||||
inkscape:window-y="27"
|
inkscape:window-y="198"
|
||||||
inkscape:window-maximized="1"
|
inkscape:window-maximized="0"
|
||||||
units="px"
|
units="px"
|
||||||
showguides="false"
|
showguides="false">
|
||||||
inkscape:pagecheckerboard="1">
|
|
||||||
<inkscape:grid
|
<inkscape:grid
|
||||||
type="xygrid"
|
type="xygrid"
|
||||||
id="grid869" />
|
id="grid869" />
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 202 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 206 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 174 KiB |
129
src/graph.rs
|
|
@ -20,42 +20,40 @@
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::DrawingArea;
|
use gtk::DrawingArea;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
|
||||||
/// A single line
|
/// A single line
|
||||||
#[derive(Debug)]
|
pub struct Line {
|
||||||
pub(crate) struct Line {
|
pub points: Vec<(f64,f64)>,
|
||||||
pub(crate) points: Vec<(f64, f64)>,
|
pub color: (f64, f64, f64)
|
||||||
pub(crate) color: (f64, f64, f64),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Line {
|
impl Line {
|
||||||
pub(crate) fn new(r: f64, g: f64, b: f64, points: Vec<(f64, f64)>) -> Self {
|
pub fn new(r: f64, g: f64, b: f64, points: Vec<(f64,f64)>) -> Self {
|
||||||
Line {
|
Line {
|
||||||
points,
|
points,
|
||||||
color: (r, g, b),
|
color: (r,g,b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Tools to draw Graph
|
/// Tools to draw Graph
|
||||||
pub(crate) struct Graph {
|
pub struct Graph {
|
||||||
pub(crate) area: DrawingArea,
|
pub area: DrawingArea,
|
||||||
pub(crate) scale_x_start: f64, // start of x on pankti
|
pub scale_x_start: f64, // start of x on pankti
|
||||||
pub(crate) scale_x_size: f64, // size of pankti to show
|
pub scale_x_size: f64, // size of pankti to show
|
||||||
pub(crate) scale_y_start: f64, // start of y on stambh
|
pub scale_y_start: f64, // start of y on stambh
|
||||||
pub(crate) scale_y_size: f64, // size of stambh to show
|
pub scale_y_size: f64, // size of stambh to show
|
||||||
pub(crate) draw_patch: bool, // enable to draw circle spot on line
|
pub draw_patch: bool, // enable to draw circle spot on line
|
||||||
pub(crate) draw_box: bool, // enable to show boxes linke graph paper
|
pub draw_box: bool, // enable to show boxes linke graph paper
|
||||||
pub(crate) draw_baarik_box: bool, // enable to show baarik(similar meaning to smaller) linke graph paper
|
pub draw_baarik_box: bool, // enable to show baarik(similar meaning to smaller) linke graph paper
|
||||||
pub(crate) auto_adjust_y: bool, // enable to automatically adjust y axis
|
pub auto_adjust_y: bool, // enable to automatically adjust y axis
|
||||||
pub(crate) lines: HashMap<String, Line>,
|
pub lines: HashMap<String, Line>,
|
||||||
pub(crate) pankti_sankya: f64, // use used while adding to point in lines to see last count of graphable input
|
pub pankti_sankya: f64 // use used while adding to point in lines to see last count of graphable input
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Graph {
|
impl Graph {
|
||||||
pub(crate) fn new(
|
pub fn new(area: DrawingArea,
|
||||||
area: DrawingArea,
|
|
||||||
scale_x_start: f64,
|
scale_x_start: f64,
|
||||||
scale_x_size: f64,
|
scale_x_size: f64,
|
||||||
scale_y_start: f64,
|
scale_y_start: f64,
|
||||||
|
|
@ -65,8 +63,8 @@ impl Graph {
|
||||||
draw_baarik_box: bool,
|
draw_baarik_box: bool,
|
||||||
auto_adjust_y: bool,
|
auto_adjust_y: bool,
|
||||||
lines: HashMap<String, Line>,
|
lines: HashMap<String, Line>,
|
||||||
pankti_sankya: f64,
|
pankti_sankya: f64) -> Rc<RefCell<Self>> {
|
||||||
) -> Rc<RefCell<Self>> {
|
|
||||||
let graph = Rc::new(RefCell::new(Graph {
|
let graph = Rc::new(RefCell::new(Graph {
|
||||||
area,
|
area,
|
||||||
scale_x_start,
|
scale_x_start,
|
||||||
|
|
@ -78,7 +76,7 @@ impl Graph {
|
||||||
draw_baarik_box,
|
draw_baarik_box,
|
||||||
auto_adjust_y,
|
auto_adjust_y,
|
||||||
lines,
|
lines,
|
||||||
pankti_sankya,
|
pankti_sankya
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let graph_tmp = Rc::clone(&graph);
|
let graph_tmp = Rc::clone(&graph);
|
||||||
|
|
@ -91,14 +89,7 @@ impl Graph {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// used to draw box and baarik box
|
/// used to draw box and baarik box
|
||||||
fn draw_boxes(
|
fn draw_boxes(ctx: &cairo::Context, area_width: f64, area_height: f64, src_x: f64, cell_size: f64, color: f64) {
|
||||||
ctx: &cairo::Context,
|
|
||||||
area_width: f64,
|
|
||||||
area_height: f64,
|
|
||||||
src_x: f64,
|
|
||||||
cell_size: f64,
|
|
||||||
color: f64,
|
|
||||||
) {
|
|
||||||
ctx.set_source_rgb(color, color, color);
|
ctx.set_source_rgb(color, color, color);
|
||||||
ctx.set_line_width(1.0);
|
ctx.set_line_width(1.0);
|
||||||
// lines parallel to stambh
|
// lines parallel to stambh
|
||||||
|
|
@ -113,7 +104,7 @@ impl Graph {
|
||||||
ctx.move_to(src_x, yi);
|
ctx.move_to(src_x, yi);
|
||||||
ctx.line_to(area_width + src_x, yi);
|
ctx.line_to(area_width + src_x, yi);
|
||||||
}
|
}
|
||||||
ctx.stroke().unwrap();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// transform point to show on graph
|
/// transform point to show on graph
|
||||||
|
|
@ -127,25 +118,27 @@ impl Graph {
|
||||||
scale_x_size: f64,
|
scale_x_size: f64,
|
||||||
scale_y_size: f64,
|
scale_y_size: f64,
|
||||||
height: f64,
|
height: f64,
|
||||||
stambh_scale_width: f64,
|
stambh_scale_width: f64) -> (f64, f64){
|
||||||
) -> (f64, f64) {
|
|
||||||
(
|
(
|
||||||
((p - p_start) * aa_dumm_pankti)/scale_x_size + stambh_scale_width,
|
((p - p_start) * aa_dumm_pankti)/scale_x_size + stambh_scale_width,
|
||||||
height - ((s - s_start) * aa_dumm_stambh) / scale_y_size,
|
height - ((s - s_start) * aa_dumm_stambh) / scale_y_size
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// callback of drawing area to draw graph
|
/// callback of drawing area to draw graph
|
||||||
fn draw(area: >k::DrawingArea, ctx: &cairo::Context, graph: &Rc<RefCell<Graph>>) {
|
fn draw(area: >k::DrawingArea,
|
||||||
|
ctx: &cairo::Context,
|
||||||
|
graph: &Rc<RefCell<Graph>>) {
|
||||||
|
|
||||||
let graph = graph.borrow();
|
let graph = graph.borrow();
|
||||||
|
|
||||||
ctx.set_source_rgb(0.1, 0.5, 0.5);
|
ctx.set_source_rgb(0.1, 0.5, 0.5);
|
||||||
ctx.paint().unwrap();
|
ctx.paint();
|
||||||
|
|
||||||
let pankti_scale_height = 50.0;
|
let pankti_scale_height = 50.0;
|
||||||
let stambh_scale_width = 60.0;
|
let stambh_scale_width = 60.0;
|
||||||
let width = area.allocated_width() as f64 - stambh_scale_width;
|
let width = area.get_allocated_width() as f64 - stambh_scale_width;
|
||||||
let height = area.allocated_height() as f64 - pankti_scale_height;
|
let height = area.get_allocated_height() as f64 - pankti_scale_height;
|
||||||
|
|
||||||
let manjusa_maap = 50.0;
|
let manjusa_maap = 50.0;
|
||||||
|
|
||||||
|
|
@ -208,19 +201,14 @@ impl Graph {
|
||||||
ctx.set_source_rgb(line.color.0, line.color.1, line.color.2);
|
ctx.set_source_rgb(line.color.0, line.color.1, line.color.2);
|
||||||
ctx.move_to(bindu_dumm_t.0, bindu_dumm_t.1);
|
ctx.move_to(bindu_dumm_t.0, bindu_dumm_t.1);
|
||||||
ctx.line_to(bindu_t.0, bindu_t.1);
|
ctx.line_to(bindu_t.0, bindu_t.1);
|
||||||
ctx.stroke().unwrap();
|
ctx.stroke();
|
||||||
|
|
||||||
// draw circle over point
|
// draw circle over point
|
||||||
if draw_patch {
|
if draw_patch {
|
||||||
ctx.set_source_rgb(0.0, 0.0, 1.0);
|
ctx.set_source_rgb(0.0, 0.0, 1.0);
|
||||||
ctx.arc(
|
ctx.arc(bindu_dumm_t.0, bindu_dumm_t.1,
|
||||||
bindu_dumm_t.0,
|
5.0, 0.0, std::f64::consts::PI * 2.0);
|
||||||
bindu_dumm_t.1,
|
ctx.stroke();
|
||||||
5.0,
|
|
||||||
0.0,
|
|
||||||
std::f64::consts::PI * 2.0,
|
|
||||||
);
|
|
||||||
ctx.stroke().unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -229,41 +217,33 @@ impl Graph {
|
||||||
ctx.set_source_rgb(0.1, 0.4, 0.4);
|
ctx.set_source_rgb(0.1, 0.4, 0.4);
|
||||||
ctx.rectangle(0.0, 0.0, stambh_scale_width, height + pankti_scale_height);
|
ctx.rectangle(0.0, 0.0, stambh_scale_width, height + pankti_scale_height);
|
||||||
ctx.rectangle(stambh_scale_width, height, width, pankti_scale_height);
|
ctx.rectangle(stambh_scale_width, height, width, pankti_scale_height);
|
||||||
ctx.fill().unwrap();
|
ctx.fill();
|
||||||
|
|
||||||
ctx.set_source_rgb(1.0, 1.0, 1.0);
|
ctx.set_source_rgb(1.0, 1.0, 1.0);
|
||||||
// write numbers on pankti scale
|
// write numbers on pankti scale
|
||||||
for i in 0..(rekha_sankhya_pankti as i32 + 1) {
|
for i in 0..(rekha_sankhya_pankti as i32 + 1) {
|
||||||
let text =
|
let text = math::round::floor(i as f64 * anupat_pankti + graph.scale_x_start, 4).to_string();
|
||||||
math::round::floor(i as f64 * anupat_pankti + graph.scale_x_start, 4).to_string();
|
let f = ctx.text_extents(&text);
|
||||||
let f = ctx.text_extents(&text).expect("Text dimension");
|
ctx.move_to(i as f64 * manjusa_maap - f.width + stambh_scale_width + f.height / 0.866, height + f.width * 0.5 + f.height);
|
||||||
ctx.move_to(
|
ctx.save();
|
||||||
i as f64 * manjusa_maap - f.width + stambh_scale_width + f.height / 0.866,
|
|
||||||
height + f.width * 0.5 + f.height,
|
|
||||||
);
|
|
||||||
ctx.save().unwrap();
|
|
||||||
ctx.rotate(std::f64::consts::PI / -6.0);
|
ctx.rotate(std::f64::consts::PI / -6.0);
|
||||||
ctx.show_text(&text).unwrap();
|
ctx.show_text(&text);
|
||||||
ctx.restore().unwrap();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
// write numbers on stambh scale
|
// write numbers on stambh scale
|
||||||
for i in (0..aa_dumm_stambh as i32 + 1).rev() {
|
for i in (0..aa_dumm_stambh as i32 + 1).rev() {
|
||||||
let text =
|
let text = math::round::floor(i as f64 * anupat_stambh + graph.scale_y_start, 4).to_string();
|
||||||
math::round::floor(i as f64 * anupat_stambh + graph.scale_y_start, 4).to_string();
|
let f = ctx.text_extents(&text);
|
||||||
let f = ctx.text_extents(&text).expect("Text dimension");
|
ctx.move_to(stambh_scale_width - f.width, height - i as f64 * manjusa_maap + f.width * 0.5);
|
||||||
ctx.move_to(
|
ctx.save();
|
||||||
stambh_scale_width - f.width,
|
|
||||||
height - i as f64 * manjusa_maap + f.width * 0.5,
|
|
||||||
);
|
|
||||||
ctx.save().unwrap();
|
|
||||||
ctx.rotate(std::f64::consts::PI / -6.0);
|
ctx.rotate(std::f64::consts::PI / -6.0);
|
||||||
ctx.show_text(&text).unwrap();
|
ctx.show_text(&text);
|
||||||
ctx.restore().unwrap();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adjust stambh and pankti as needed , trim lines and redraws
|
/// Adjust stambh and pankti as needed , trim lines and redraws
|
||||||
pub(crate) fn redraw(&mut self) {
|
pub fn redraw(&mut self) {
|
||||||
let (mx_x, mi_x, mx_y, mi_y) = self.get_extremes();
|
let (mx_x, mi_x, mx_y, mi_y) = self.get_extremes();
|
||||||
|
|
||||||
// stambh
|
// stambh
|
||||||
|
|
@ -286,7 +266,7 @@ impl Graph {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// find minimun and maximum value from all lines
|
/// find minimun and maximum value from all lines
|
||||||
pub(crate) fn get_extremes(&self) -> (f64, f64, f64, f64) {
|
pub fn get_extremes(&self) -> (f64, f64, f64, f64){
|
||||||
// trick to avoid no lines
|
// trick to avoid no lines
|
||||||
if self.lines.len() == 0 {
|
if self.lines.len() == 0 {
|
||||||
return (0.0,0.0,0.0,0.0);
|
return (0.0,0.0,0.0,0.0);
|
||||||
|
|
@ -339,16 +319,17 @@ impl Graph {
|
||||||
|
|
||||||
// tims line form left side of line. Why left?? to avoid wasting time in ponits in range
|
// tims line form left side of line. Why left?? to avoid wasting time in ponits in range
|
||||||
// it skips i point out of screen to keep a non terminating line experience
|
// it skips i point out of screen to keep a non terminating line experience
|
||||||
pub(crate) fn trim_lines(&mut self) {
|
pub fn trim_lines(&mut self) {
|
||||||
for (_, line) in self.lines.iter_mut() {
|
for (_, line) in self.lines.iter_mut() {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < line.points.len() {
|
while i < line.points.len() {
|
||||||
|
|
||||||
match line.points.get(i + 2) {
|
match line.points.get(i + 2) {
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
if line.points[i+1].0 < self.scale_x_start {
|
if line.points[i+1].0 < self.scale_x_start {
|
||||||
line.points.remove(i);
|
line.points.remove(i);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
None => {
|
None => {
|
||||||
if line.points[line.points.len() - 1].0 < self.scale_x_start {
|
if line.points[line.points.len() - 1].0 < self.scale_x_start {
|
||||||
line.points.clear();
|
line.points.clear();
|
||||||
|
|
|
||||||
764
src/lib.rs
|
|
@ -17,338 +17,373 @@
|
||||||
|
|
||||||
//! Feel free to see through codes. Application is not written to be used as a library for other app. :)
|
//! Feel free to see through codes. Application is not written to be used as a library for other app. :)
|
||||||
|
|
||||||
pub(crate) mod graph;
|
mod graph;
|
||||||
pub(crate) mod port_util;
|
|
||||||
pub(crate) mod util;
|
|
||||||
|
|
||||||
use glib::clone;
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::{collections::HashMap, sync::{Arc, Mutex}};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::io::BufReader;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::Ordering;
|
use std::cell::RefCell;
|
||||||
use std::sync::Arc;
|
use std::io::prelude::*;
|
||||||
|
use std::io::BufReader;
|
||||||
|
|
||||||
|
|
||||||
use graph::Graph;
|
use graph::Graph;
|
||||||
use port_util as putil;
|
|
||||||
use util::Properties;
|
|
||||||
|
|
||||||
// Building and propsuring GUI
|
/// Status of Serial reading
|
||||||
|
enum Status {
|
||||||
|
JAGRIT, // Mode of Active
|
||||||
|
SAYAN, // Mode of Sleeping
|
||||||
|
AVRODTIH, // Mode of being stopped
|
||||||
|
PARIVARTIT // Mode of being values modified
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration to read from Serial Port
|
||||||
|
pub struct Config {
|
||||||
|
status: Status,
|
||||||
|
bondrate: u32,
|
||||||
|
port: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn new() -> Config {
|
||||||
|
Config {
|
||||||
|
status: Status::AVRODTIH,
|
||||||
|
bondrate: 9600,
|
||||||
|
port: "".to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For communication between mpsc of graph and serial port
|
||||||
|
enum MessageSerialThread {
|
||||||
|
Msg(String),
|
||||||
|
Status(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Building and configuring GUI
|
||||||
pub fn build_ui(app: >k::Application) {
|
pub fn build_ui(app: >k::Application) {
|
||||||
let props = Arc::new(Properties::default());
|
let config = Arc::new(Mutex::new(Config::new()));
|
||||||
let ui_file = include_str!("ui.glade");
|
let builder = gtk::Builder::from_file(std::env::current_exe().unwrap().parent().unwrap().join("ui.glade"));
|
||||||
let builder = gtk::Builder::from_string(ui_file);
|
|
||||||
|
|
||||||
let win = builder
|
let win = builder.get_object::<gtk::ApplicationWindow>("win").expect("Resource file missing!");
|
||||||
.object::<gtk::ApplicationWindow>("win")
|
|
||||||
.expect("Resource file missing!");
|
|
||||||
win.set_application(Some(app));
|
win.set_application(Some(app));
|
||||||
|
let bar = builder.get_object::<gtk::Statusbar>("status_bar").expect("Resource file missing!");
|
||||||
// Status Bar
|
let log_area = builder.get_object::<gtk::TextView>("log_area").expect("Resource file missing!");
|
||||||
let bar = builder
|
|
||||||
.object::<gtk::Statusbar>("status_bar")
|
|
||||||
.expect("Resource file missing!");
|
|
||||||
|
|
||||||
// Logging Area
|
|
||||||
let log_area = builder
|
|
||||||
.object::<gtk::TextView>("log_area")
|
|
||||||
.expect("Resource file missing!");
|
|
||||||
|
|
||||||
// About Window
|
|
||||||
let about_window = builder
|
|
||||||
.object::<gtk::AboutDialog>("about_window")
|
|
||||||
.expect("Resource file missing!");
|
|
||||||
|
|
||||||
// Save Window
|
|
||||||
let save_window = builder
|
|
||||||
.object::<gtk::FileChooserDialog>("save_window")
|
|
||||||
.expect("Resource file missing!");
|
|
||||||
save_window.set_transient_for(Some(&win));
|
|
||||||
save_window.set_action(gtk::FileChooserAction::Save);
|
|
||||||
save_window.add_button("_Save", gtk::ResponseType::Apply);
|
|
||||||
save_window.add_button("_Cancel", gtk::ResponseType::Cancel);
|
|
||||||
|
|
||||||
let graph = Graph::new(
|
let graph = Graph::new(
|
||||||
builder
|
builder.get_object::<gtk::DrawingArea>("draw_area").expect("Resource file missing!"),
|
||||||
.object::<gtk::DrawingArea>("draw_area")
|
0.0, 100.0,
|
||||||
.expect("Resource file missing!"),
|
0.0, 100.0,
|
||||||
0.0,
|
|
||||||
100.0,
|
|
||||||
0.0,
|
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
0.0,
|
0.0
|
||||||
);
|
);
|
||||||
|
|
||||||
win.show_all();
|
win.show_all();
|
||||||
|
|
||||||
// required by signals
|
// exit_menu
|
||||||
let stambh_1 = builder
|
let exit_menu = builder.get_object::<gtk::MenuItem>("exit_menu").expect("Resource file missing!");
|
||||||
.object::<gtk::Entry>("stambh_1")
|
|
||||||
.expect("Resource file missing!");
|
let tmp_win = win.clone();
|
||||||
let stambh_2 = builder
|
exit_menu.connect_activate(move |_|{
|
||||||
.object::<gtk::Entry>("stambh_2")
|
unsafe {
|
||||||
.expect("Resource file missing!");
|
tmp_win.destroy();
|
||||||
let draw_baarik_box = builder
|
|
||||||
.object::<gtk::CheckButton>("draw_baarik_box")
|
|
||||||
.expect("Resource file missing!");
|
|
||||||
let port = builder
|
|
||||||
.object::<gtk::ComboBoxText>("port")
|
|
||||||
.expect("Resource file missing!");
|
|
||||||
let send_entry = builder
|
|
||||||
.object::<gtk::Entry>("send_entry")
|
|
||||||
.expect("Resource file missing!");
|
|
||||||
// Signals
|
|
||||||
builder.connect_signals(|_, handler_name| {
|
|
||||||
match handler_name {
|
|
||||||
"exit_menu_activate" => Box::new(clone!(@weak win => @default-return None, move |_| {
|
|
||||||
unsafe { win.destroy(); }
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"about_menu_activate" => Box::new(clone!(@weak about_window => @default-return None, move |_| {
|
|
||||||
about_window.show();
|
|
||||||
about_window.present();
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"save_menu_activate" => Box::new(clone!(@weak save_window => @default-return None, move |_| {
|
|
||||||
save_window.show();
|
|
||||||
save_window.present();
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"gtk_main_quit" => Box::new(clone!(@weak save_window => @default-return None, move |_| {
|
|
||||||
save_window.show();
|
|
||||||
save_window.present();
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"pankti_value_changed" => Box::new(clone!(@weak graph => @default-return None, move |a| {
|
|
||||||
let btn = a[0].get::<gtk::SpinButton>().unwrap();
|
|
||||||
let mut tmp_graph = graph.borrow_mut();
|
|
||||||
tmp_graph.scale_x_size = btn.value();
|
|
||||||
tmp_graph.redraw();
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"stambh_1_changed" => Box::new(clone!(@weak graph => @default-return None, move |a| {
|
|
||||||
let entry = a[0].get::<gtk::Entry>().unwrap();
|
|
||||||
let mut tmp_graph = graph.borrow_mut();
|
|
||||||
let val = entry.text().parse::<f64>().unwrap_or(0.0);
|
|
||||||
let purana_y_start = tmp_graph.scale_y_start;
|
|
||||||
let y_size = tmp_graph.scale_y_size;
|
|
||||||
tmp_graph.scale_y_start = val;
|
|
||||||
tmp_graph.scale_y_size = y_size + (purana_y_start - val);
|
|
||||||
tmp_graph.redraw();
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"stambh_2_changed" => Box::new(clone!(@weak graph => @default-return None, move |a| {
|
|
||||||
let entry = a[0].get::<gtk::Entry>().unwrap();
|
|
||||||
let mut tmp_graph = graph.borrow_mut();
|
|
||||||
let val = entry.text().parse::<f64>().unwrap_or(0.0);
|
|
||||||
let y_start = tmp_graph.scale_y_start;
|
|
||||||
tmp_graph.scale_y_size = (val - y_start).abs();
|
|
||||||
tmp_graph.redraw();
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"nimna_stambh_toggled" => Box::new(clone!(@weak graph, @weak stambh_1, @weak stambh_2 => @default-return None, move |a| {
|
|
||||||
let btn = a[0].get::<gtk::CheckButton>().unwrap();
|
|
||||||
graph.borrow_mut().auto_adjust_y = !btn.is_active();
|
|
||||||
stambh_1.set_sensitive(btn.is_active());
|
|
||||||
stambh_2.set_sensitive(btn.is_active());
|
|
||||||
if btn.is_active() {
|
|
||||||
stambh_1.emit_activate();
|
|
||||||
stambh_2.emit_activate();
|
|
||||||
}
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"draw_patches_toggled" => Box::new(clone!(@weak graph => @default-return None, move |a| {
|
|
||||||
let btn = a[0].get::<gtk::CheckButton>().unwrap();
|
|
||||||
let mut tmp_graph = graph.borrow_mut();
|
|
||||||
tmp_graph.draw_patch = btn.is_active();
|
|
||||||
tmp_graph.redraw();
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"draw_box_toggled" => Box::new(clone!(@weak graph, @weak draw_baarik_box => @default-return None, move |a| {
|
|
||||||
let btn = a[0].get::<gtk::CheckButton>().unwrap();
|
|
||||||
let mut tmp_graph = graph.borrow_mut();
|
|
||||||
draw_baarik_box.set_sensitive(btn.is_active());
|
|
||||||
tmp_graph.draw_box = btn.is_active();
|
|
||||||
tmp_graph.redraw();
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"draw_baarik_box_toggled" => Box::new(clone!(@weak graph => @default-return None, move |a| {
|
|
||||||
let btn = a[0].get::<gtk::CheckButton>().unwrap();
|
|
||||||
let mut tmp_graph = graph.borrow_mut();
|
|
||||||
tmp_graph.draw_baarik_box = btn.is_active();
|
|
||||||
tmp_graph.redraw();
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"clear_graph_clicked"=> Box::new(clone!(@weak graph => @default-return None, move |_| {
|
|
||||||
let mut tmp_graph = graph.borrow_mut();
|
|
||||||
tmp_graph.pankti_sankya = 0.0;
|
|
||||||
tmp_graph.lines.clear();
|
|
||||||
tmp_graph.redraw();
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"bondrate_changed" => Box::new(clone!(@weak props => @default-return None, move |a| {
|
|
||||||
let btn = a[0].get::<gtk::ComboBoxText>().unwrap();
|
|
||||||
props.bondrate.store(btn.active_text().unwrap().parse::<u32>().unwrap_or(9600u32), Ordering::SeqCst);
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"port_changed" => Box::new(clone!(@weak props, @weak bar => @default-return None, move |a| {
|
|
||||||
let btn = a[0].get::<gtk::ComboBoxText>().unwrap();
|
|
||||||
if let Some(val) = btn.active_text() {
|
|
||||||
match props.port.lock() {
|
|
||||||
Ok(mut a) => { *a = val.to_string() },
|
|
||||||
Err(_) => { bar.push(1, "Can't set Port"); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"refresh_port_clicked" => Box::new(clone!(@weak port, @weak bar, @weak props => @default-return None, move |_| {
|
|
||||||
port.remove_all();
|
|
||||||
match props.status.lock() {
|
|
||||||
Ok(mut a) => { *a = util::Status::AVRODTIH },
|
|
||||||
Err(_) => { bar.push(1, "Can't Avrodhit"); return None; }
|
|
||||||
}
|
|
||||||
bar.push(1, "Avrodhit");
|
|
||||||
match serialport::available_ports() {
|
|
||||||
Ok(ports) => {
|
|
||||||
if ports.len() == 0 { bar.push(1, "No port found!"); }
|
|
||||||
for p in ports {
|
|
||||||
port.append_text(p.port_name.as_str());
|
|
||||||
}
|
|
||||||
}, Err(_) => {
|
|
||||||
bar.push(1, "No port found!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"jagrit_btn_clicked" => Box::new(clone!(@weak props, @weak graph, @weak bar => @default-return None, move |_| {
|
|
||||||
let mut tmp_graph = graph.borrow_mut();
|
|
||||||
tmp_graph.pankti_sankya = 0.0;
|
|
||||||
tmp_graph.lines.clear();
|
|
||||||
tmp_graph.redraw();
|
|
||||||
bar.push(1, "Jagrit");
|
|
||||||
match props.status.lock() {
|
|
||||||
Ok(mut a) => { *a = util::Status::PARIVARTIT },
|
|
||||||
Err(_) => { bar.push(1, "Can't Jagrit"); }
|
|
||||||
}
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"avrodith_btn_clicked" => Box::new(clone!(@weak props, @weak bar => @default-return None, move |_| {
|
|
||||||
bar.push(1, "Avrodhit");
|
|
||||||
match props.status.lock() {
|
|
||||||
Ok(mut a) => { *a = util::Status::AVRODTIH },
|
|
||||||
Err(_) => { bar.push(1, "Can't Avrodhit"); }
|
|
||||||
}
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"clear_log_clicked" => Box::new(clone!(@weak log_area => @default-return None, move |_| {
|
|
||||||
log_area.buffer().expect("Couldn't get window").set_text("");
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"send_entry_key_press_event" => Box::new(clone!(@weak props, @weak bar => @default-return None, move |a| {
|
|
||||||
let ev = a[1].get::<gdk::Event>().unwrap();
|
|
||||||
let ev: Result<gdk::EventKey,_> = gdk::FromEvent::from(ev);
|
|
||||||
if ev.unwrap().keyval() == gdk::keys::constants::Return {
|
|
||||||
let ent = a[0].get::<gtk::Entry>().unwrap();
|
|
||||||
putil::send_text(&props, &ent, &bar);
|
|
||||||
}
|
|
||||||
Some(false.to_value())
|
|
||||||
})),
|
|
||||||
"send_btn_clicked" => Box::new(clone!(@weak props, @weak bar, @weak send_entry => @default-return None, move |_| {
|
|
||||||
putil::send_text(&props, &send_entry, &bar);
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"about_window_delete" => Box::new(|a| {
|
|
||||||
let win = a[0].get::<gtk::AboutDialog>().unwrap();
|
|
||||||
win.hide();
|
|
||||||
Some(true.to_value())
|
|
||||||
}),
|
|
||||||
"save_window_delete" => Box::new(|a| {
|
|
||||||
let win = a[0].get::<gtk::FileChooserDialog>().unwrap();
|
|
||||||
win.hide();
|
|
||||||
Some(true.to_value())
|
|
||||||
}),
|
|
||||||
"about_window_close" => Box::new(clone!(@weak about_window => @default-return None, move |_| {
|
|
||||||
about_window.hide();
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
"save_window_close" => Box::new(clone!(@weak save_window => @default-return None, move |_| {
|
|
||||||
save_window.hide();
|
|
||||||
None
|
|
||||||
})),
|
|
||||||
_ => Box::new(|_| {None})
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// about_menu
|
||||||
|
let about_menu = builder.get_object::<gtk::MenuItem>("about_menu").expect("Resource file missing!");
|
||||||
|
let about_window = builder.get_object::<gtk::AboutDialog>("about_window").expect("Resource file missing!");
|
||||||
|
about_window.set_transient_for(Some(&win));
|
||||||
|
|
||||||
|
about_window.connect_delete_event(|win,_| {
|
||||||
|
win.hide();
|
||||||
|
Inhibit(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
let a_win = about_window.clone();
|
||||||
|
about_menu.connect_activate(move |_|{
|
||||||
|
a_win.show();
|
||||||
|
a_win.present();
|
||||||
|
});
|
||||||
|
|
||||||
|
// save_log
|
||||||
|
let save_menu = builder.get_object::<gtk::MenuItem>("save_menu").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let save_window = builder.get_object::<gtk::FileChooserDialog>("save_window").expect("Resource file missing!");
|
||||||
|
save_window.set_transient_for(Some(&win));
|
||||||
|
save_window.set_action(gtk::FileChooserAction::Save);
|
||||||
|
|
||||||
|
save_window.connect_delete_event(|win,_| {
|
||||||
|
win.hide();
|
||||||
|
Inhibit(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
save_window.add_button("_Save", gtk::ResponseType::Apply);
|
||||||
|
save_window.add_button("_Cancel", gtk::ResponseType::Cancel);
|
||||||
|
|
||||||
let tmp_log_area = log_area.clone();
|
let tmp_log_area = log_area.clone();
|
||||||
let tmp_bar = bar.clone();
|
let tmp_bar = bar.clone();
|
||||||
save_window.connect_response(move |win, res| match res {
|
save_window.connect_response(move |win, res| {
|
||||||
|
match res {
|
||||||
gtk::ResponseType::Cancel => win.hide(),
|
gtk::ResponseType::Cancel => win.hide(),
|
||||||
gtk::ResponseType::Apply => {
|
gtk::ResponseType::Apply => {
|
||||||
if let Some(path) = win.filename() {
|
if let Some(path) = win.get_filename() {
|
||||||
if let Some(buf) = tmp_log_area.buffer() {
|
if let Some(buf) = tmp_log_area.get_buffer() {
|
||||||
let text = buf
|
let text = buf.get_text(&buf.get_start_iter(), &buf.get_end_iter(), false).unwrap().to_string();
|
||||||
.text(&buf.start_iter(), &buf.end_iter(), false)
|
|
||||||
.unwrap()
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
match std::fs::write(path, text) {
|
match std::fs::write(path, text) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
win.hide();
|
win.hide();
|
||||||
}
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
tmp_bar.push(1, "Failed to save!");
|
tmp_bar.push(1, "Failed to save!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
_ => ()
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
save_menu.connect_activate(move |_|{
|
||||||
Thread to manage Serial Port
|
save_window.show();
|
||||||
|
});
|
||||||
|
|
||||||
The program runs a thread to read and parse the output from serial port and
|
// pankti
|
||||||
send it through mpsc (rx, tx) to a recever. Where it is added to Graph
|
let pankti = builder.get_object::<gtk::SpinButton>("pankti").expect("Resource file missing!");
|
||||||
or Log is added to text area or any status is displayed in bar
|
|
||||||
*/
|
let tmp_graph = Rc::clone(&graph);
|
||||||
|
pankti.connect_value_changed(move |btn| {
|
||||||
|
let mut tmp_graph = tmp_graph.borrow_mut();
|
||||||
|
tmp_graph.scale_x_size = btn.get_value();
|
||||||
|
tmp_graph.redraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
// stambh_1
|
||||||
|
let stambh_1 = builder.get_object::<gtk::Entry>("stambh_1").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_graph = Rc::clone(&graph);
|
||||||
|
stambh_1.connect_activate(move |entry| {
|
||||||
|
let mut tmp_graph = tmp_graph.borrow_mut();
|
||||||
|
let val = entry.get_text().parse::<f64>().unwrap_or(0.0);
|
||||||
|
let purana_y_start = tmp_graph.scale_y_start;
|
||||||
|
let y_size = tmp_graph.scale_y_size;
|
||||||
|
tmp_graph.scale_y_start = val;
|
||||||
|
tmp_graph.scale_y_size = y_size + (purana_y_start - val);
|
||||||
|
tmp_graph.redraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
// stambh_2
|
||||||
|
let stambh_2 = builder.get_object::<gtk::Entry>("stambh_2").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_graph = Rc::clone(&graph);
|
||||||
|
stambh_2.connect_activate(move |entry| {
|
||||||
|
let mut tmp_graph = tmp_graph.borrow_mut();
|
||||||
|
let val = entry.get_text().parse::<f64>().unwrap_or(0.0);
|
||||||
|
let y_start = tmp_graph.scale_y_start;
|
||||||
|
tmp_graph.scale_y_size = (val - y_start).abs();
|
||||||
|
tmp_graph.redraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
// nimna_stambh
|
||||||
|
let nimna_stambh = builder.get_object::<gtk::CheckButton>("nimna_stambh").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_graph = Rc::clone(&graph);
|
||||||
|
nimna_stambh.connect_clicked(move |btn| {
|
||||||
|
tmp_graph.borrow_mut().auto_adjust_y = !btn.get_active();
|
||||||
|
stambh_1.set_sensitive(btn.get_active());
|
||||||
|
stambh_2.set_sensitive(btn.get_active());
|
||||||
|
if btn.get_active() {
|
||||||
|
stambh_1.emit_activate();
|
||||||
|
stambh_2.emit_activate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// draw_patches
|
||||||
|
let draw_patches = builder.get_object::<gtk::CheckButton>("draw_patches").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_graph = Rc::clone(&graph);
|
||||||
|
draw_patches.connect_clicked(move |btn| {
|
||||||
|
let mut tmp_graph = tmp_graph.borrow_mut();
|
||||||
|
tmp_graph.draw_patch = btn.get_active();
|
||||||
|
tmp_graph.redraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
// draw_baarik_box
|
||||||
|
let draw_baarik_box = builder.get_object::<gtk::CheckButton>("draw_baarik_box").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_graph = Rc::clone(&graph);
|
||||||
|
draw_baarik_box.connect_clicked(move |btn| {
|
||||||
|
let mut tmp_graph = tmp_graph.borrow_mut();
|
||||||
|
tmp_graph.draw_baarik_box = btn.get_active();
|
||||||
|
tmp_graph.redraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
// draw_box
|
||||||
|
let draw_box = builder.get_object::<gtk::CheckButton>("draw_box").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_graph = Rc::clone(&graph);
|
||||||
|
draw_box.connect_clicked(move |btn| {
|
||||||
|
draw_baarik_box.set_sensitive(btn.get_active());
|
||||||
|
let mut tmp_graph = tmp_graph.borrow_mut();
|
||||||
|
tmp_graph.draw_box = btn.get_active();
|
||||||
|
tmp_graph.redraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bondrate
|
||||||
|
let bondrate = builder.get_object::<gtk::ComboBoxText>("bondrate").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_bar = bar.clone();
|
||||||
|
let tmp_config = Arc::clone(&config);
|
||||||
|
bondrate.connect_changed(move |cbx| {
|
||||||
|
match tmp_config.lock() {
|
||||||
|
Ok(mut config) => {
|
||||||
|
config.bondrate = match cbx.get_active_text() {
|
||||||
|
Some(txt) => txt.to_string().parse::<u32>().unwrap_or(9600u32),
|
||||||
|
None => 9600
|
||||||
|
};
|
||||||
|
}, Err(_) => {
|
||||||
|
tmp_bar.push(1, "Failed to change bondrate!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// port
|
||||||
|
let refresh_port = builder.get_object::<gtk::ToolButton>("refresh_port").expect("Resource file missing!");
|
||||||
|
let port = builder.get_object::<gtk::ComboBoxText>("port").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_bar = bar.clone();
|
||||||
|
let tmp_port = port.clone();
|
||||||
|
refresh_port.connect_clicked(move |_| {
|
||||||
|
tmp_port.remove_all();
|
||||||
|
match serialport::available_ports() {
|
||||||
|
Ok(ports) => {
|
||||||
|
if ports.len() == 0 { tmp_bar.push(1, "No port found!"); }
|
||||||
|
for p in ports {
|
||||||
|
tmp_port.append_text(p.port_name.as_str());
|
||||||
|
}
|
||||||
|
}, Err(_) => {
|
||||||
|
tmp_bar.push(1, "No port found!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let tmp_bar = bar.clone();
|
||||||
|
let tmp_config = Arc::clone(&config);
|
||||||
|
port.connect_changed(move |cbx| {
|
||||||
|
match tmp_config.lock() {
|
||||||
|
Ok(mut config) => {
|
||||||
|
config.port = match cbx.get_active_text() {
|
||||||
|
Some(txt) => txt.to_string(),
|
||||||
|
None => "".to_owned()
|
||||||
|
};
|
||||||
|
}, Err(_) => {
|
||||||
|
tmp_bar.push(1, "Failed to change port!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// clear_graph
|
||||||
|
let clear_graph = builder.get_object::<gtk::ToolButton>("clear_graph").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_graph = Rc::clone(&graph);
|
||||||
|
clear_graph.connect_clicked(move |_ | {
|
||||||
|
tmp_graph.borrow_mut().pankti_sankya = 0.0;
|
||||||
|
tmp_graph.borrow_mut().lines.clear();
|
||||||
|
tmp_graph.borrow_mut().redraw();
|
||||||
|
});
|
||||||
|
|
||||||
|
// jagrit_btn
|
||||||
|
let jagrit_btn = builder.get_object::<gtk::ToolButton>("jagrit_btn").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_bar = bar.clone();
|
||||||
|
let tmp_config = Arc::clone(&config);
|
||||||
|
let tmp_graph = Rc::clone(&graph);
|
||||||
|
jagrit_btn.connect_clicked(move |_ | {
|
||||||
|
match tmp_config.lock() {
|
||||||
|
Ok(mut config) => {
|
||||||
|
tmp_graph.borrow_mut().pankti_sankya = 0.0;
|
||||||
|
tmp_graph.borrow_mut().lines.clear();
|
||||||
|
tmp_graph.borrow_mut().redraw();
|
||||||
|
tmp_bar.push(1, "Jagrit");
|
||||||
|
config.status = Status::PARIVARTIT;
|
||||||
|
}, Err(_) => {
|
||||||
|
tmp_bar.push(1, "Failed to change port!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// avrodith_btn
|
||||||
|
let avrodith_btn = builder.get_object::<gtk::ToolButton>("avrodith_btn").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_bar = bar.clone();
|
||||||
|
let tmp_config = Arc::clone(&config);
|
||||||
|
avrodith_btn.connect_clicked(move |_| {
|
||||||
|
match tmp_config.lock() {
|
||||||
|
Ok(mut config) => {
|
||||||
|
tmp_bar.push(1, "Avrodhit");
|
||||||
|
config.status = Status::AVRODTIH;
|
||||||
|
}, Err(_) => {
|
||||||
|
tmp_bar.push(1, "Failed to change port!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// clear_log
|
||||||
|
let clear_log = builder.get_object::<gtk::ToolButton>("clear_log").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_log_area = log_area.clone();
|
||||||
|
clear_log.connect_clicked(move |_| {
|
||||||
|
tmp_log_area.get_buffer().expect("Couldn't get window").set_text("");
|
||||||
|
});
|
||||||
|
|
||||||
|
// send_entry
|
||||||
|
let send_entry = builder.get_object::<gtk::Entry>("send_entry").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_bar = bar.clone();
|
||||||
|
let tmp_config = Arc::clone(&config);
|
||||||
|
send_entry.connect_activate(move |ent| {
|
||||||
|
send_text(&tmp_config, ent, &tmp_bar);
|
||||||
|
});
|
||||||
|
|
||||||
|
// send_btn
|
||||||
|
let send_btn = builder.get_object::<gtk::Button>("send_btn").expect("Resource file missing!");
|
||||||
|
|
||||||
|
let tmp_bar = bar.clone();
|
||||||
|
let tmp_config = Arc::clone(&config);
|
||||||
|
send_btn.connect_clicked(move |_| {
|
||||||
|
send_text(&tmp_config, &send_entry, &tmp_bar);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Serial Thread
|
||||||
let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
||||||
|
|
||||||
let tmp_props = Arc::clone(&props);
|
let tmp_config = Arc::clone(&config);
|
||||||
tokio::task::spawn(async move {
|
std::thread::spawn(move || {
|
||||||
let mut bufread: Option<BufReader<Box<dyn serialport::SerialPort>>> = None;
|
let mut bufread: Option<BufReader<Box<dyn serialport::SerialPort>>> = None;
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
loop {
|
loop {
|
||||||
putil::serial_thread_work(&tmp_props, &mut bufread, &sender, &mut buf).await;
|
serial_thread_work(&tmp_config, &mut bufread, &sender, &mut buf);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reciver for MessageSerialThread from the "Thread to manage Serial Port" and works accordingly
|
// Serial Thread Reciver
|
||||||
let full_log = builder
|
let full_log = builder.get_object::<gtk::CheckButton>("full_log").expect("Resource file missing!");
|
||||||
.object::<gtk::CheckButton>("full_log")
|
|
||||||
.expect("Resource file missing!");
|
|
||||||
let graph_data = builder
|
|
||||||
.object::<gtk::TextView>("graph_data")
|
|
||||||
.expect("Resource file missing!");
|
|
||||||
let tmp_graph = Rc::clone(&graph);
|
let tmp_graph = Rc::clone(&graph);
|
||||||
receiver.attach(None, move |msg| {
|
receiver.attach(None, move |msg| {
|
||||||
match msg {
|
match msg {
|
||||||
util::MessageSerialThread::Msg(text, msg_type) => {
|
MessageSerialThread::Msg(text) => {
|
||||||
receiver_for_msg(text, &msg_type, &full_log, &log_area);
|
receiver_for_msg(text, &tmp_graph, &full_log, &log_area);
|
||||||
}
|
},
|
||||||
util::MessageSerialThread::Points(points) => {
|
MessageSerialThread::Status(text) => {
|
||||||
receiver_for_points(points, &tmp_graph, &graph_data);
|
|
||||||
}
|
|
||||||
util::MessageSerialThread::Status(text) => {
|
|
||||||
bar.push(1, &text);
|
bar.push(1, &text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -356,69 +391,148 @@ pub fn build_ui(app: >k::Application) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receives MessageSerialThread from Serial Port managing thread adds message to text area
|
// Controls the thread and read from serial port
|
||||||
fn receiver_for_msg(
|
fn serial_thread_work(
|
||||||
text: String,
|
config: &Arc<Mutex<Config>>,
|
||||||
msg_type: &util::MessageSerialThreadMsgType,
|
bufread: &mut Option<BufReader<Box<dyn serialport::SerialPort>>>,
|
||||||
full_log: >k::CheckButton,
|
sender: &glib::Sender<MessageSerialThread>,
|
||||||
log_area: >k::TextView,
|
buf: &mut String) {
|
||||||
) {
|
let mut do_sleep = false;
|
||||||
if !full_log.is_active() {
|
match config.lock() {
|
||||||
if let util::MessageSerialThreadMsgType::Point = msg_type {
|
Ok(mut config) => {
|
||||||
|
match config.status {
|
||||||
|
Status::AVRODTIH => {
|
||||||
|
*bufread = None;
|
||||||
|
config.status = Status::SAYAN;
|
||||||
|
},
|
||||||
|
Status::JAGRIT => {
|
||||||
|
if let Some(read) = bufread {
|
||||||
|
if let Ok(_) = read.read_line(buf) {
|
||||||
|
sender.send(MessageSerialThread::Msg(buf.clone())).unwrap();
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Status::PARIVARTIT => {
|
||||||
|
let p = match serialport::new(&config.port, config.bondrate).open() {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(_) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
*bufread = Some(BufReader::new(p));
|
||||||
|
config.status = Status::JAGRIT;
|
||||||
|
},
|
||||||
|
Status::SAYAN => {
|
||||||
|
do_sleep = true;
|
||||||
}
|
}
|
||||||
if text.len() <= 0 {
|
}
|
||||||
|
}, Err(_) => {
|
||||||
|
sender.send(MessageSerialThread::Status("Faild prepare for communication!".to_owned())).unwrap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let buf = log_area.buffer().expect("Couldn't get log_area");
|
};
|
||||||
buf.insert(&mut buf.end_iter(), &format!("{}\n", text));
|
|
||||||
log_area.scroll_to_iter(&mut buf.end_iter(), 0.4, true, 0.0, 0.0);
|
// Hack for smooth performance
|
||||||
log_area.queue_draw();
|
if do_sleep {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
} else {
|
||||||
|
std::thread::sleep(std::time::Duration::from_nanos(1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receives MessageSerialThread from Serial Port managing thread and add points to draw on graph
|
// Receives MessageSerialThread from Serial Port managing thread and add points to draw on graph
|
||||||
fn receiver_for_points(
|
fn receiver_for_msg(text: String, graph: &Rc<RefCell<Graph>>, full_log: >k::CheckButton, log_area: >k::TextView) {
|
||||||
points: Vec<(String, f64)>,
|
for text in text.lines() {
|
||||||
graph: &Rc<RefCell<Graph>>,
|
if text.len() == 0 {
|
||||||
graph_data: >k::TextView,
|
return;
|
||||||
) {
|
} else if text.starts_with("#") {
|
||||||
for (line, point) in points {
|
graph.borrow_mut().pankti_sankya += 1.0;
|
||||||
|
for (index, line) in text[1..].split(" ").enumerate() {
|
||||||
|
let part = line.split("=");
|
||||||
|
let part = part.into_iter().collect::<Vec<&str>>();
|
||||||
|
if part.len() == 1 {
|
||||||
|
let num = match part[0].trim().parse::<f64>() {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
let mut gp = graph.borrow_mut();
|
let mut gp = graph.borrow_mut();
|
||||||
|
|
||||||
let sankhya = gp.pankti_sankya;
|
let sankhya = gp.pankti_sankya;
|
||||||
match gp.lines.get_mut(&line) {
|
match gp.lines.get_mut(&index.to_string()) {
|
||||||
Some(val) => {
|
Some(val) => {
|
||||||
val.points.push((sankhya, point));
|
val.points.push((sankhya, num));
|
||||||
}
|
} None => {
|
||||||
None => {
|
let v = vec![(sankhya, num)];
|
||||||
let v = vec![(sankhya, point)];
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
gp.lines.insert(
|
|
||||||
line,
|
|
||||||
graph::Line::new(rng.gen_range(0.0..1.0), 0.0, rng.gen_range(0.0..1.0), v),
|
|
||||||
);
|
|
||||||
let buf = graph_data.buffer().expect("Couldn't get graph_data");
|
|
||||||
buf.set_text("");
|
|
||||||
gp.lines.iter().for_each(|(key, line)| {
|
|
||||||
buf.insert(&mut buf.end_iter(), "##");
|
|
||||||
|
|
||||||
let tag = gtk::TextTag::new(None);
|
let mut rng = rand::thread_rng();
|
||||||
let rgba = gdk::RGBA::new(line.color.0, line.color.1, line.color.2, 1.0);
|
gp.lines.insert(index.to_string(), graph::Line::new(rng.gen_range(0.0..1.0), 0.0, rng.gen_range(0.0..1.0), v));
|
||||||
tag.set_background_rgba(Some(&rgba));
|
}
|
||||||
tag.set_foreground_rgba(Some(&rgba));
|
}
|
||||||
buf.tag_table().unwrap().add(&tag);
|
gp.redraw();
|
||||||
buf.apply_tag(
|
} else if part.len() == 2 {
|
||||||
&tag,
|
let num = match part[1].trim().parse::<f64>() {
|
||||||
&buf.iter_at_offset(buf.end_iter().offset() - 2),
|
Ok(val) => val,
|
||||||
&buf.end_iter(),
|
Err(_) => {
|
||||||
);
|
continue;
|
||||||
buf.insert(&mut buf.end_iter(), &format!(" {}, ", key));
|
}
|
||||||
});
|
};
|
||||||
graph_data.queue_draw();
|
let mut gp = graph.borrow_mut();
|
||||||
|
|
||||||
|
let sankhya = gp.pankti_sankya;
|
||||||
|
match gp.lines.get_mut(part[0]) {
|
||||||
|
Some(val) => {
|
||||||
|
val.points.push((sankhya, num));
|
||||||
|
} None => {
|
||||||
|
let v = vec![(sankhya, num)];
|
||||||
|
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
gp.lines.insert(part[0].to_owned(), graph::Line::new(rng.gen_range(0.0..1.0), 0.0, rng.gen_range(0.0..1.0), v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gp.redraw();
|
gp.redraw();
|
||||||
}
|
}
|
||||||
graph.borrow_mut().pankti_sankya += 1.0;
|
}
|
||||||
|
|
||||||
|
if full_log.get_active(){
|
||||||
|
let buf = log_area.get_buffer()
|
||||||
|
.expect("Couldn't get log_area");
|
||||||
|
buf.insert(&mut buf.get_end_iter(), &format!("{}\n",text));
|
||||||
|
log_area.scroll_to_iter(&mut buf.get_end_iter(), 0.4, true, 0.0, 0.0);
|
||||||
|
log_area.queue_draw();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let buf = log_area.get_buffer()
|
||||||
|
.expect("Couldn't get log_area");
|
||||||
|
buf.insert(&mut buf.get_end_iter(), &format!("{}\n",text));
|
||||||
|
log_area.scroll_to_iter(&mut buf.get_end_iter(), 0.4, true, 0.0, 0.0);
|
||||||
|
log_area.queue_draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_text(config: &Arc<Mutex<Config>>, entry: >k::Entry, bar: >k::Statusbar) {
|
||||||
|
match config.lock() {
|
||||||
|
Ok(config) => {
|
||||||
|
if let Status::JAGRIT = config.status {
|
||||||
|
let mut p = match serialport::new(&config.port, config.bondrate).open() {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(_) => {
|
||||||
|
bar.push(1, "Failed to change port!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
p.write_all(entry.get_text().to_string().as_bytes_mut()).unwrap();
|
||||||
|
}
|
||||||
|
entry.set_text("");
|
||||||
|
}
|
||||||
|
}, Err(_) => {
|
||||||
|
bar.push(1, "Failed to change port!");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
src/main.rs
|
|
@ -12,16 +12,18 @@
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#![windows_subsystem = "windows"]
|
|
||||||
|
|
||||||
use gio::{prelude::*, ApplicationFlags};
|
use gio::prelude::*;
|
||||||
|
use std::env::args;
|
||||||
|
|
||||||
#[tokio::main]
|
fn main() {
|
||||||
async fn main() {
|
let app = gtk::Application::new(Some("sng.tarangm"), Default::default())
|
||||||
let app = gtk::Application::new(Some("sng.tarangm"), ApplicationFlags::default());
|
.expect("Failed to initiate gtk");
|
||||||
|
|
||||||
app.connect_activate(move |app| {
|
app.connect_activate(move |app| {
|
||||||
tarangam::build_ui(app);
|
tarangam::build_ui(app);
|
||||||
});
|
});
|
||||||
app.run();
|
|
||||||
|
app.run(&args().collect::<Vec<_>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
163
src/port_util.rs
|
|
@ -1,163 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Tarangam.
|
|
||||||
|
|
||||||
Tarangam 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.
|
|
||||||
|
|
||||||
Tarangam 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 Tarangam. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
//! Feel free to see through codes. Application is not written to be used as a library for other app. :)
|
|
||||||
|
|
||||||
use gtk::prelude::*;
|
|
||||||
|
|
||||||
use std::io::prelude::*;
|
|
||||||
use std::io::BufReader;
|
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::{util, util::Properties};
|
|
||||||
|
|
||||||
// Controls the thread and read from serial port
|
|
||||||
pub(crate) async fn serial_thread_work(
|
|
||||||
config: &Arc<Properties>,
|
|
||||||
bufread: &mut Option<BufReader<Box<dyn serialport::SerialPort>>>,
|
|
||||||
sender: &glib::Sender<util::MessageSerialThread>,
|
|
||||||
buf: &mut String,
|
|
||||||
) {
|
|
||||||
let status = match config.status.try_lock() {
|
|
||||||
Ok(a) => a.to_owned(),
|
|
||||||
Err(_) => {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match status {
|
|
||||||
util::Status::AVRODTIH => {
|
|
||||||
*bufread = None;
|
|
||||||
match config.status.lock() {
|
|
||||||
Ok(mut a) => *a = util::Status::SAYAN,
|
|
||||||
Err(_) => {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
util::Status::JAGRIT => {
|
|
||||||
if let Some(read) = bufread {
|
|
||||||
if let Ok(_) = read.read_line(buf) {
|
|
||||||
for line in buf.lines() {
|
|
||||||
if line.len() == 0 {
|
|
||||||
continue;
|
|
||||||
} else if line.starts_with("#") {
|
|
||||||
let mut points: Vec<(String, f64)> = Vec::new();
|
|
||||||
for (index, line) in line[1..].split(" ").enumerate() {
|
|
||||||
let part = line.split("=");
|
|
||||||
let part = part.into_iter().collect::<Vec<&str>>();
|
|
||||||
if part.len() == 1 {
|
|
||||||
let num = match part[0].trim().parse::<f64>() {
|
|
||||||
Ok(val) => val,
|
|
||||||
Err(_) => {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
points.push((index.to_string(), num));
|
|
||||||
} else if part.len() == 2 {
|
|
||||||
points.push((
|
|
||||||
part[0].trim().to_owned(),
|
|
||||||
part[1].parse::<f64>().unwrap(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sender
|
|
||||||
.send(util::MessageSerialThread::Points(points))
|
|
||||||
.unwrap();
|
|
||||||
sender
|
|
||||||
.send(util::MessageSerialThread::Msg(
|
|
||||||
line.to_owned(),
|
|
||||||
util::MessageSerialThreadMsgType::Point,
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
} else {
|
|
||||||
sender
|
|
||||||
.send(util::MessageSerialThread::Msg(
|
|
||||||
line.to_owned(),
|
|
||||||
util::MessageSerialThreadMsgType::Log,
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
|
|
||||||
}
|
|
||||||
util::Status::PARIVARTIT => {
|
|
||||||
let port = match config.port.lock() {
|
|
||||||
Ok(a) => a.to_owned(),
|
|
||||||
Err(_) => {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let p = match serialport::new(&port, config.bondrate.load(Ordering::SeqCst)).open() {
|
|
||||||
Ok(p) => p,
|
|
||||||
Err(_) => {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
*bufread = Some(BufReader::new(p));
|
|
||||||
match config.status.try_lock() {
|
|
||||||
Ok(mut a) => *a = util::Status::JAGRIT,
|
|
||||||
Err(_) => {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// // Sends text through Serial Post to device
|
|
||||||
pub(crate) fn send_text(config: &Arc<Properties>, entry: >k::Entry, bar: >k::Statusbar) {
|
|
||||||
let status = match config.status.try_lock() {
|
|
||||||
Ok(a) => a.to_owned(),
|
|
||||||
Err(_) => {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if let util::Status::JAGRIT = status {
|
|
||||||
let port = match config.port.lock() {
|
|
||||||
Ok(a) => a.to_owned(),
|
|
||||||
Err(_) => {
|
|
||||||
bar.push(1, "Failed to set port!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut p = match serialport::new(port, config.bondrate.load(Ordering::SeqCst)).open() {
|
|
||||||
Ok(p) => p,
|
|
||||||
Err(_) => {
|
|
||||||
bar.push(1, "Failed to change port!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
p.write_all(entry.text().to_string().as_bytes_mut())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
entry.set_text("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
61
src/util.rs
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Tarangam.
|
|
||||||
|
|
||||||
Tarangam 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.
|
|
||||||
|
|
||||||
Tarangam 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 Tarangam. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
//! Feel free to see through codes. Application is not written to be used as a library for other app. :)
|
|
||||||
|
|
||||||
use std::sync::{atomic::*, Mutex};
|
|
||||||
|
|
||||||
/// Status of Serial reading
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub(crate) enum Status {
|
|
||||||
AVRODTIH, // Mode of being stopped
|
|
||||||
SAYAN, // Mode of Sleeping
|
|
||||||
JAGRIT, // Mode of Active
|
|
||||||
PARIVARTIT, // Mode of being values modified
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct Properties {
|
|
||||||
pub(crate) bondrate: AtomicU32,
|
|
||||||
pub(crate) port: Mutex<String>,
|
|
||||||
pub(crate) status: Mutex<Status>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// For communication between mpsc of graph and serial port
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) enum MessageSerialThread {
|
|
||||||
Msg(String, MessageSerialThreadMsgType),
|
|
||||||
Points(Vec<(String, f64)>),
|
|
||||||
Status(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) enum MessageSerialThreadMsgType {
|
|
||||||
Point,
|
|
||||||
Log,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Properties {
|
|
||||||
pub(crate) fn default() -> Self {
|
|
||||||
Properties {
|
|
||||||
bondrate: AtomicU32::new(9600),
|
|
||||||
port: Mutex::new(String::new()),
|
|
||||||
status: Mutex::new(Status::AVRODTIH),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn start() {
|
||||||
|
let ports = serialport::available_ports();
|
||||||
|
println!("{:?}",ports);
|
||||||
|
|
||||||
|
let mut p = serialport::new("/dev/ttyUSB1", 9600).timeout(Duration::from_millis(10))
|
||||||
|
.open().expect("Failed to open port");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
p.write_all("buf".to_owned().as_bytes_mut()).unwrap();
|
||||||
|
}
|
||||||
|
let mut read = BufReader::new(p);
|
||||||
|
let mut buf = String::new();
|
||||||
|
loop {
|
||||||
|
match read.read_line(&mut buf) {
|
||||||
|
Ok(_) =>
|
||||||
|
{
|
||||||
|
print!("{}", buf);
|
||||||
|
buf.clear();
|
||||||
|
},
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,9 +5,10 @@
|
||||||
<object class="GtkAboutDialog" id="about_window">
|
<object class="GtkAboutDialog" id="about_window">
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<property name="title" translatable="yes">Tarangam</property>
|
<property name="title" translatable="yes">Tarangam</property>
|
||||||
<property name="icon">chitra-small.png</property>
|
<property name="icon">chitra.svg</property>
|
||||||
<property name="type-hint">dialog</property>
|
<property name="type-hint">dialog</property>
|
||||||
<property name="program-name">Tarangam (तरंगम्)</property>
|
<property name="program-name">Tarangam (तरंगम्)</property>
|
||||||
|
<property name="version">0.1.0</property>
|
||||||
<property name="comments" translatable="yes">A simple serial plotter.
|
<property name="comments" translatable="yes">A simple serial plotter.
|
||||||
एक सरल सीरीय्ल पलौटर।</property>
|
एक सरल सीरीय्ल पलौटर।</property>
|
||||||
<property name="website">https://github.com/PiyushXCoder/Tarangam</property>
|
<property name="website">https://github.com/PiyushXCoder/Tarangam</property>
|
||||||
|
|
@ -15,8 +16,6 @@
|
||||||
<property name="authors">Piyush Mishra(पीयूष मिश्र:)</property>
|
<property name="authors">Piyush Mishra(पीयूष मिश्र:)</property>
|
||||||
<property name="logo">chitra.png</property>
|
<property name="logo">chitra.png</property>
|
||||||
<property name="license-type">gpl-3-0</property>
|
<property name="license-type">gpl-3-0</property>
|
||||||
<signal name="close" handler="about_window_close" swapped="no"/>
|
|
||||||
<signal name="delete-event" handler="about_window_delete" swapped="no"/>
|
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
|
|
@ -45,6 +44,11 @@
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="GtkImage" id="document_save">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="icon-name">document-save</property>
|
||||||
|
</object>
|
||||||
<object class="GtkAdjustment" id="pankti_adjustment">
|
<object class="GtkAdjustment" id="pankti_adjustment">
|
||||||
<property name="lower">5</property>
|
<property name="lower">5</property>
|
||||||
<property name="upper">500</property>
|
<property name="upper">500</property>
|
||||||
|
|
@ -54,12 +58,9 @@
|
||||||
</object>
|
</object>
|
||||||
<object class="GtkFileChooserDialog" id="save_window">
|
<object class="GtkFileChooserDialog" id="save_window">
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<property name="icon">chitra-small.png</property>
|
<property name="icon">chitra.svg</property>
|
||||||
<property name="type-hint">dialog</property>
|
<property name="type-hint">dialog</property>
|
||||||
<property name="action">select-folder</property>
|
<property name="action">select-folder</property>
|
||||||
<signal name="close" handler="save_window_close" swapped="no"/>
|
|
||||||
<signal name="delete-event" handler="save_window_delete" swapped="no"/>
|
|
||||||
<signal name="response" handler="save_window_response" swapped="no"/>
|
|
||||||
<child internal-child="vbox">
|
<child internal-child="vbox">
|
||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
|
|
@ -98,7 +99,7 @@
|
||||||
<property name="title" translatable="yes">Tarangam</property>
|
<property name="title" translatable="yes">Tarangam</property>
|
||||||
<property name="default-width">850</property>
|
<property name="default-width">850</property>
|
||||||
<property name="default-height">600</property>
|
<property name="default-height">600</property>
|
||||||
<property name="icon">chitra-small.png</property>
|
<property name="icon">chitra.svg</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
|
@ -119,11 +120,12 @@
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkMenuItem" id="save_menu">
|
<object class="GtkImageMenuItem" id="save_menu">
|
||||||
|
<property name="label">Save Log</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<property name="label" translatable="yes">Save Log</property>
|
<property name="image">document_save</property>
|
||||||
<signal name="activate" handler="save_menu_activate" swapped="no"/>
|
<property name="use-stock">False</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
|
@ -133,12 +135,12 @@
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkMenuItem" id="exit_menu">
|
<object class="GtkImageMenuItem" id="exit_menu">
|
||||||
|
<property name="label">gtk-quit</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<property name="label" translatable="yes">Exit</property>
|
|
||||||
<property name="use-underline">True</property>
|
<property name="use-underline">True</property>
|
||||||
<signal name="activate" handler="exit_menu_activate" swapped="no"/>
|
<property name="use-stock">True</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -156,12 +158,12 @@
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkMenuItem" id="about_menu">
|
<object class="GtkImageMenuItem" id="about_menu">
|
||||||
|
<property name="label">gtk-about</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<property name="label" translatable="yes">About</property>
|
|
||||||
<property name="use-underline">True</property>
|
<property name="use-underline">True</property>
|
||||||
<signal name="activate" handler="about_menu_activate" swapped="no"/>
|
<property name="use-stock">True</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -187,7 +189,6 @@
|
||||||
<property name="label" translatable="yes">refresh</property>
|
<property name="label" translatable="yes">refresh</property>
|
||||||
<property name="use-underline">True</property>
|
<property name="use-underline">True</property>
|
||||||
<property name="icon-name">view-refresh</property>
|
<property name="icon-name">view-refresh</property>
|
||||||
<signal name="clicked" handler="refresh_port_clicked" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
|
|
@ -202,7 +203,6 @@
|
||||||
<object class="GtkComboBoxText" id="port">
|
<object class="GtkComboBoxText" id="port">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<signal name="changed" handler="port_changed" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -242,7 +242,6 @@
|
||||||
<item translatable="yes">460800</item>
|
<item translatable="yes">460800</item>
|
||||||
<item translatable="yes">921600</item>
|
<item translatable="yes">921600</item>
|
||||||
</items>
|
</items>
|
||||||
<signal name="changed" handler="bondrate_changed" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -258,7 +257,6 @@
|
||||||
<property name="label" translatable="yes">Connect</property>
|
<property name="label" translatable="yes">Connect</property>
|
||||||
<property name="use-underline">True</property>
|
<property name="use-underline">True</property>
|
||||||
<property name="icon-name">media-playback-start</property>
|
<property name="icon-name">media-playback-start</property>
|
||||||
<signal name="clicked" handler="jagrit_btn_clicked" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
|
|
@ -272,7 +270,6 @@
|
||||||
<property name="label" translatable="yes">Stop</property>
|
<property name="label" translatable="yes">Stop</property>
|
||||||
<property name="use-underline">True</property>
|
<property name="use-underline">True</property>
|
||||||
<property name="icon-name">media-playback-stop</property>
|
<property name="icon-name">media-playback-stop</property>
|
||||||
<signal name="clicked" handler="avrodith_btn_clicked" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
|
|
@ -306,7 +303,6 @@
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<property name="label" translatable="yes">Clear</property>
|
<property name="label" translatable="yes">Clear</property>
|
||||||
<property name="use-underline">True</property>
|
<property name="use-underline">True</property>
|
||||||
<signal name="clicked" handler="clear_graph_clicked" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
|
|
@ -324,7 +320,6 @@
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
<property name="receives-default">False</property>
|
<property name="receives-default">False</property>
|
||||||
<property name="draw-indicator">True</property>
|
<property name="draw-indicator">True</property>
|
||||||
<signal name="toggled" handler="draw_patches_toggled" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -345,7 +340,6 @@
|
||||||
<property name="receives-default">False</property>
|
<property name="receives-default">False</property>
|
||||||
<property name="active">True</property>
|
<property name="active">True</property>
|
||||||
<property name="draw-indicator">True</property>
|
<property name="draw-indicator">True</property>
|
||||||
<signal name="toggled" handler="draw_box_toggled" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -365,7 +359,6 @@
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
<property name="receives-default">False</property>
|
<property name="receives-default">False</property>
|
||||||
<property name="draw-indicator">True</property>
|
<property name="draw-indicator">True</property>
|
||||||
<signal name="toggled" handler="draw_baarik_box_toggled" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -414,7 +407,6 @@
|
||||||
<property name="digits">1</property>
|
<property name="digits">1</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
<property name="wrap">True</property>
|
<property name="wrap">True</property>
|
||||||
<signal name="value-changed" handler="pankti_value_changed" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -430,30 +422,6 @@
|
||||||
<property name="position">0</property>
|
<property name="position">0</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<object class="GtkScrolledWindow">
|
|
||||||
<property name="height-request">35</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="vscrollbar-policy">never</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkTextView" id="graph_data">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="editable">False</property>
|
|
||||||
<property name="left-margin">5</property>
|
|
||||||
<property name="top-margin">7</property>
|
|
||||||
<property name="cursor-visible">False</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkDrawingArea" id="draw_area">
|
<object class="GtkDrawingArea" id="draw_area">
|
||||||
<property name="width-request">500</property>
|
<property name="width-request">500</property>
|
||||||
|
|
@ -466,7 +434,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">True</property>
|
||||||
<property name="position">2</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
|
@ -484,7 +452,6 @@
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
<property name="receives-default">False</property>
|
<property name="receives-default">False</property>
|
||||||
<property name="draw-indicator">True</property>
|
<property name="draw-indicator">True</property>
|
||||||
<signal name="toggled" handler="nimna_stambh_toggled" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -523,7 +490,6 @@
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
<property name="width-chars">8</property>
|
<property name="width-chars">8</property>
|
||||||
<property name="text" translatable="yes">0</property>
|
<property name="text" translatable="yes">0</property>
|
||||||
<signal name="changed" handler="stambh_1_changed" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -562,7 +528,6 @@
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
<property name="width-chars">8</property>
|
<property name="width-chars">8</property>
|
||||||
<property name="text" translatable="yes">100</property>
|
<property name="text" translatable="yes">100</property>
|
||||||
<signal name="changed" handler="stambh_2_changed" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -575,7 +540,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">True</property>
|
||||||
<property name="position">3</property>
|
<property name="position">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -599,7 +564,6 @@
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<property name="label" translatable="yes">Clear</property>
|
<property name="label" translatable="yes">Clear</property>
|
||||||
<property name="use-underline">True</property>
|
<property name="use-underline">True</property>
|
||||||
<signal name="clicked" handler="clear_log_clicked" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
|
|
@ -617,7 +581,6 @@
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
<property name="receives-default">False</property>
|
<property name="receives-default">False</property>
|
||||||
<property name="draw-indicator">True</property>
|
<property name="draw-indicator">True</property>
|
||||||
<signal name="toggled" handler="full_log_toggled" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
@ -663,7 +626,6 @@
|
||||||
<object class="GtkEntry" id="send_entry">
|
<object class="GtkEntry" id="send_entry">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
<signal name="key-press-event" handler="send_entry_key_press_event" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
|
|
@ -678,7 +640,6 @@
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
<property name="receives-default">True</property>
|
<property name="receives-default">True</property>
|
||||||
<property name="image">send_image</property>
|
<property name="image">send_image</property>
|
||||||
<signal name="clicked" handler="send_btn_clicked" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||