Compare commits
24 Commits
24b60e74a0
...
62b7036933
Author | SHA1 | Date | |
---|---|---|---|
doryan | 62b7036933 | ||
doryan | 3d896c7061 | ||
doryan | e8c73b75a1 | ||
doryan | b4fb37539c | ||
doryan | f9699180b9 | ||
doryan | 839694edc1 | ||
doryan | cedb844826 | ||
doryan | a7cf11737a | ||
doryan | f78001167a | ||
doryan | 11ba24d7ed | ||
doryan | e9764cf0e8 | ||
doryan | ac9e8953a9 | ||
doryan | 4e872ddcff | ||
doryan | 8e8cecd463 | ||
doryan | cd697b9f5d | ||
doryan | 7116b565de | ||
doryan | 7282045c98 | ||
doryan | f57aed1fb8 | ||
doryan | 2e1f4b6a12 | ||
doryan | d3327a7c36 | ||
doryan | 06439585eb | ||
doryan | 418e916c0d | ||
doryan | 23bfd10e2b | ||
doryan | 269b30312d |
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
controller::view_utils::{hamming_code_input_utils::*, input_utils::*},
|
controller::view_utils::{hamming_code_utils::*, input_utils::*},
|
||||||
model::{models::*, Result},
|
model::{models::*, Result},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ pub fn hamming(raw_input: String, mode: HammingMode) -> Result<String> {
|
||||||
let prepared_input: String = processing_input(&raw_input);
|
let prepared_input: String = processing_input(&raw_input);
|
||||||
|
|
||||||
let (first_condition, second_condition): (bool, bool) =
|
let (first_condition, second_condition): (bool, bool) =
|
||||||
check_correct_binary_code(&raw_input, &prepared_input, length_of_code);
|
check_correct_binary_code(&prepared_input, length_of_code);
|
||||||
|
|
||||||
if raw_input.is_empty() {
|
if raw_input.is_empty() {
|
||||||
Err("Введите код.".into())
|
Err("Введите код.".into())
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
use crate::model::Frequency;
|
||||||
|
|
||||||
|
use gio::{prelude::Cast, ListStore};
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn reactive_resistance_of_capacitor(Cm: f64, L: f64, f: f64) -> f64 {
|
pub fn reactive_resistance_of_capacitor(Cm: f64, L: f64, f: f64) -> f64 {
|
||||||
if f == 0.0 || Cm == 0.0 || L == 0.0 {
|
if f == 0.0 || Cm == 0.0 || L == 0.0 {
|
||||||
|
@ -29,3 +33,19 @@ pub fn coef_of_signal_reduce(Vs: f64, V: f64) -> f64 {
|
||||||
Vs / V
|
Vs / V
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_default_values(model: &ListStore) {
|
||||||
|
for number in (0..=100).step_by(5) {
|
||||||
|
if number == 0 {
|
||||||
|
model.append(&Frequency::new(1.0));
|
||||||
|
} else if (number >= 70 && number % 10 == 0) || (number < 70 && number % 5 == 0) {
|
||||||
|
model.append(&Frequency::new(number as f64));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_by_frequency_value(model: &ListStore, new_elem: &Frequency) -> Option<u32> {
|
||||||
|
model.find_with_equal_func(|elem| {
|
||||||
|
elem.downcast_ref::<Frequency>().unwrap().frequency() == new_elem.frequency()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -25,10 +25,10 @@ pub fn start_hamming_algorithm(input: &TextView, state: bool) -> Result<String>
|
||||||
hamming(parsed_input, operation)
|
hamming(parsed_input, operation)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_correct_binary_code(input: &str, prepared_input: &str, l: usize) -> (bool, bool) {
|
pub fn check_correct_binary_code(prepared_input: &str, l: usize) -> (bool, bool) {
|
||||||
let first_condition: bool = prepared_input.len() % l == 0;
|
let first_condition: bool = prepared_input.len() % l == 0;
|
||||||
|
|
||||||
let second_condition: bool = input.chars().all(|c| c == '1' || c == '0' || c == ' ');
|
let second_condition: bool = prepared_input.chars().all(|c| c == '1' || c == '0');
|
||||||
|
|
||||||
(first_condition, second_condition)
|
(first_condition, second_condition)
|
||||||
}
|
}
|
|
@ -9,8 +9,8 @@ const ASCII_ZERO_CHAR_POSITION: u8 = 48;
|
||||||
pub fn processing_input(input: impl Into<String>) -> String {
|
pub fn processing_input(input: impl Into<String>) -> String {
|
||||||
input
|
input
|
||||||
.into()
|
.into()
|
||||||
.split_ascii_whitespace()
|
.split(&[' ', '\n'][..])
|
||||||
.filter(|&x| !x.is_empty())
|
.filter(|x| !x.is_empty())
|
||||||
.fold(String::new(), |c: String, n: &str| c + n)
|
.fold(String::new(), |c: String, n: &str| c + n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
pub mod hamming_code_input_utils;
|
pub mod hamming_code_utils;
|
||||||
pub mod input_utils;
|
pub mod input_utils;
|
||||||
pub mod signal_reduce_input_utils;
|
pub mod signal_reduce_utils;
|
||||||
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
use gtk4 as gtk;
|
|
||||||
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use gtk::{
|
|
||||||
prelude::{TextBufferExt, TextViewExt},
|
|
||||||
TextBuffer,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
model::{models::SignalReduce, Error, Result},
|
|
||||||
view::components::input::Input,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn get_error_message(error: Error) -> Option<&'static str> {
|
|
||||||
match error.to_string().as_str() {
|
|
||||||
"cannot parse float from empty string" => Some("Вы не ввели данные в поле/-я"),
|
|
||||||
"invalid float literal" => Some("Вы ввели не корректные данные в поле/-я"),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_fields(all_inputs: Vec<Input>) -> Result<SignalReduce> {
|
|
||||||
let mut values: [f64; 6] = [0.0; 6];
|
|
||||||
|
|
||||||
for (i, input) in all_inputs.iter().enumerate() {
|
|
||||||
let input_text_buffer: TextBuffer = input.clone().get_input().buffer();
|
|
||||||
let extracted_value = f64::from_str(
|
|
||||||
input_text_buffer
|
|
||||||
.text(
|
|
||||||
&input_text_buffer.start_iter(),
|
|
||||||
&input_text_buffer.end_iter(),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
.trim(),
|
|
||||||
)?;
|
|
||||||
values[i] = extracted_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(SignalReduce {
|
|
||||||
length: values[0],
|
|
||||||
wire_resistance: values[1],
|
|
||||||
wire_capacity: values[2],
|
|
||||||
source_resistance: values[3],
|
|
||||||
source_voltage: values[4],
|
|
||||||
frequency: values[5],
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
use gtk4 as gtk;
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
model::{models::SignalReduce, Error, Frequency, Result},
|
||||||
|
model_utils::signal_reducer::*,
|
||||||
|
view::components::input::Input,
|
||||||
|
};
|
||||||
|
|
||||||
|
use gtk::{
|
||||||
|
prelude::{Cast, CastNone, EditableExt, ListItemExt, ObjectExt, WidgetExt},
|
||||||
|
ColumnView, Entry, Label, ListItem, SignalListItemFactory,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn get_error_message(error: Error) -> Option<&'static str> {
|
||||||
|
match error.to_string().as_str() {
|
||||||
|
"cannot parse float from empty string" => Some("Вы не ввели данные в поле/-я"),
|
||||||
|
"invalid float literal" => Some("Вы ввели не корректные данные в поле/-я"),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_fields(all_inputs: Vec<Input<Entry>>) -> Result<SignalReduce> {
|
||||||
|
let mut values: [f64; 6] = [0.0; 6];
|
||||||
|
|
||||||
|
for (i, input) in all_inputs.iter().enumerate() {
|
||||||
|
let input_text_buffer = input.get_input();
|
||||||
|
let extracted_value = f64::from_str(input_text_buffer.text().as_str().trim())?;
|
||||||
|
values[i] = extracted_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SignalReduce {
|
||||||
|
length: values[0],
|
||||||
|
wire_resistance: values[1],
|
||||||
|
wire_capacity: values[2],
|
||||||
|
source_resistance: values[3],
|
||||||
|
source_voltage: values[4],
|
||||||
|
frequency: values[5],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn update_column_view(column_view: &ColumnView) {
|
||||||
|
column_view.hide();
|
||||||
|
column_view.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn column_view_setup_factory(_factory: &SignalListItemFactory, list_item: &ListItem) {
|
||||||
|
list_item
|
||||||
|
.downcast_ref::<ListItem>()
|
||||||
|
.expect("Needs to be ListItem")
|
||||||
|
.set_child(Some(&Label::new(None)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn column_view_bind_factory(
|
||||||
|
_factory: &SignalListItemFactory,
|
||||||
|
list_item: &ListItem,
|
||||||
|
values: SignalReduce,
|
||||||
|
label: &str,
|
||||||
|
) {
|
||||||
|
let cell_value = list_item
|
||||||
|
.downcast_ref::<ListItem>()
|
||||||
|
.expect("Needs to be ListItem")
|
||||||
|
.item()
|
||||||
|
.and_downcast::<Frequency>()
|
||||||
|
.expect("The item has to be an `IntegerObject`.");
|
||||||
|
|
||||||
|
let cell_label = list_item
|
||||||
|
.downcast_ref::<ListItem>()
|
||||||
|
.expect("Needs to be ListItem")
|
||||||
|
.child()
|
||||||
|
.and_downcast::<Label>()
|
||||||
|
.expect("The child has to be a `Label`.");
|
||||||
|
|
||||||
|
cell_value
|
||||||
|
.bind_property("frequency", &cell_label, "label")
|
||||||
|
.sync_create()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if cell_value.reactive_resist() == 0.0 {
|
||||||
|
cell_value.set_reactive_resist(reactive_resistance_of_capacitor(
|
||||||
|
values.wire_capacity * 10f64.powi(-12),
|
||||||
|
values.length,
|
||||||
|
cell_value.frequency() * 10f64.powi(6),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if cell_value.full_resistance() == 0.0 {
|
||||||
|
cell_value.set_full_resistance(full_resistance_of_capacitor(
|
||||||
|
cell_value.reactive_resist(),
|
||||||
|
values.source_resistance,
|
||||||
|
values.wire_resistance,
|
||||||
|
values.length,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if cell_value.signal_source_voltage() == 0.0 {
|
||||||
|
cell_value.set_signal_source_voltage(
|
||||||
|
voltage_from_signal_source(
|
||||||
|
values.source_voltage * 10f64.powi(-3),
|
||||||
|
cell_value.reactive_resist(),
|
||||||
|
cell_value.full_resistance(),
|
||||||
|
) * 1000.0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
match label {
|
||||||
|
"f, МГц" => {
|
||||||
|
cell_label.set_label(&cell_value.frequency().to_string());
|
||||||
|
}
|
||||||
|
"Xc, Ом" => {
|
||||||
|
cell_label.set_label(format!("{0:.1$}", cell_value.reactive_resist(), 6).as_str());
|
||||||
|
}
|
||||||
|
"Vп, мВ" => {
|
||||||
|
cell_label
|
||||||
|
.set_label(format!("{0:.1$}", cell_value.signal_source_voltage(), 6).as_str());
|
||||||
|
}
|
||||||
|
"ζ" => {
|
||||||
|
let coef: f64 =
|
||||||
|
coef_of_signal_reduce(values.source_voltage, cell_value.signal_source_voltage());
|
||||||
|
|
||||||
|
cell_label.set_label(format!("{0:.1$}", coef, 6).as_str());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
use gtk4 as gtk;
|
use gtk4 as gtk;
|
||||||
|
|
||||||
|
extern crate gio;
|
||||||
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
|
||||||
mod controller;
|
mod controller;
|
||||||
|
|
|
@ -31,6 +31,12 @@ pub struct SignalReduce {
|
||||||
pub struct Frequency {
|
pub struct Frequency {
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
frequency: Cell<f64>,
|
frequency: Cell<f64>,
|
||||||
|
#[property(get, set)]
|
||||||
|
reactive_resist: Cell<f64>,
|
||||||
|
#[property(get, set)]
|
||||||
|
full_resistance: Cell<f64>,
|
||||||
|
#[property(get, set)]
|
||||||
|
signal_source_voltage: Cell<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::derived_properties]
|
#[glib::derived_properties]
|
||||||
|
|
|
@ -26,8 +26,6 @@ pub struct InfoBarBuilder {
|
||||||
button: ButtonBuilder,
|
button: ButtonBuilder,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Develop a method to safely mutate static.
|
|
||||||
// Not necessary.
|
|
||||||
static mut TASKS_QUEUE: VecDeque<JoinHandle<()>> = VecDeque::new();
|
static mut TASKS_QUEUE: VecDeque<JoinHandle<()>> = VecDeque::new();
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -5,12 +5,46 @@ use gtk::{prelude::*, *};
|
||||||
|
|
||||||
pub type InputLabel = String;
|
pub type InputLabel = String;
|
||||||
|
|
||||||
|
macro_rules! build_for {
|
||||||
|
( $(($comp:ty,$name:ident)),* ) => {
|
||||||
|
$(
|
||||||
|
pub fn $name(self, input_height: Option<i32>) -> Input<$comp> {
|
||||||
|
let input_component = Box::new(Orientation::Vertical, 0);
|
||||||
|
|
||||||
|
let input_label = Label::builder()
|
||||||
|
.halign(self.align.horizontal)
|
||||||
|
.valign(self.align.vertical)
|
||||||
|
.set_margin(self.margins)
|
||||||
|
.label(self.label)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let mut input_builder = <$comp>::builder()
|
||||||
|
.set_margin(MarginData::EqualsMargin(6));
|
||||||
|
|
||||||
|
if let Some(height) = input_height {
|
||||||
|
input_builder = input_builder.height_request(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = input_builder.build();
|
||||||
|
|
||||||
|
input_component.append(&input_label);
|
||||||
|
input_component.append(&input);
|
||||||
|
|
||||||
|
Input {
|
||||||
|
component: input_component,
|
||||||
|
input: input.clone(),
|
||||||
|
input_label: input_label.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Input {
|
pub struct Input<I> {
|
||||||
component: Box,
|
component: Box,
|
||||||
input: TextView,
|
input: I,
|
||||||
input_label: Label,
|
input_label: Label,
|
||||||
input_frame: Frame,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InputBuilder {
|
pub struct InputBuilder {
|
||||||
|
@ -19,7 +53,7 @@ pub struct InputBuilder {
|
||||||
margins: MarginData,
|
margins: MarginData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Product<InputBuilder, Box> for Input {
|
impl<I> Product<InputBuilder, Box> for Input<I> {
|
||||||
fn builder() -> InputBuilder {
|
fn builder() -> InputBuilder {
|
||||||
InputBuilder {
|
InputBuilder {
|
||||||
align: Alignment {
|
align: Alignment {
|
||||||
|
@ -36,13 +70,13 @@ impl Product<InputBuilder, Box> for Input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl<I> Input<I> {
|
||||||
pub fn get_input(&self) -> &TextView {
|
pub fn get_component(&self) -> &Box {
|
||||||
&self.input
|
&self.component
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_frame(&self) -> &Frame {
|
pub fn get_input(&self) -> &I {
|
||||||
&self.input_frame
|
&self.input
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_label(&self) -> &Label {
|
pub fn get_label(&self) -> &Label {
|
||||||
|
@ -69,36 +103,5 @@ impl InputBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self, monospace: bool, wrap_mode: WrapMode, input_height: i32) -> Input {
|
build_for!((TextView, build), (Entry, build_entry));
|
||||||
let input_component = Box::new(Orientation::Vertical, 0);
|
|
||||||
|
|
||||||
let text_view_label = Label::builder()
|
|
||||||
.halign(self.align.horizontal)
|
|
||||||
.valign(self.align.vertical)
|
|
||||||
.set_margin(self.margins)
|
|
||||||
.label(self.label)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let text_view_input = TextView::builder()
|
|
||||||
.monospace(monospace)
|
|
||||||
.height_request(input_height)
|
|
||||||
.set_text_view_margin(MarginData::EqualsMargin(6))
|
|
||||||
.wrap_mode(wrap_mode)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let text_view_input_frame = Frame::builder()
|
|
||||||
.child(&text_view_input)
|
|
||||||
.set_margin(MarginData::MultipleMargin((0, 5, 0, 5)))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
input_component.append(&text_view_label);
|
|
||||||
input_component.append(&text_view_input_frame);
|
|
||||||
|
|
||||||
Input {
|
|
||||||
component: input_component,
|
|
||||||
input: text_view_input.clone(),
|
|
||||||
input_frame: text_view_input_frame.clone(),
|
|
||||||
input_label: text_view_label.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
components::{info_bar::InfoBar, input::Input, wrapper::*},
|
components::{info_bar::InfoBar, input::Input, wrapper::*},
|
||||||
properties::*,
|
properties::*,
|
||||||
},
|
},
|
||||||
view_utils::{hamming_code_input_utils::start_hamming_algorithm, input_utils::clearing},
|
view_utils::{hamming_code_utils::start_hamming_algorithm, input_utils::clearing},
|
||||||
};
|
};
|
||||||
|
|
||||||
use gtk::{glib::clone, prelude::*, *};
|
use gtk::{glib::clone, prelude::*, *};
|
||||||
|
@ -14,20 +14,25 @@ use gtk::{glib::clone, prelude::*, *};
|
||||||
pub fn hamming_code_page(wrapper: &Box) {
|
pub fn hamming_code_page(wrapper: &Box) {
|
||||||
let info_bar = InfoBar::get_instance();
|
let info_bar = InfoBar::get_instance();
|
||||||
|
|
||||||
let input_code = Input::builder()
|
let input_code = Input::<TextView>::builder()
|
||||||
.label("Поле ввода для кода:")
|
.label("Поле ввода для кода:")
|
||||||
.margins(MarginData::EqualsMargin(6))
|
.margins(MarginData::EqualsMargin(6))
|
||||||
.align(Alignment::new(Align::Start, Align::Start))
|
.align(Alignment::new(Align::Start, Align::Start))
|
||||||
.build(true, WrapMode::Word, 64);
|
.build(Some(64));
|
||||||
|
|
||||||
let output_code = Input::builder()
|
let output_code = Input::<TextView>::builder()
|
||||||
.label("Результат:")
|
.label("Результат:")
|
||||||
.margins(MarginData::EqualsMargin(6))
|
.margins(MarginData::EqualsMargin(6))
|
||||||
.align(Alignment::new(Align::Start, Align::Start))
|
.align(Alignment::new(Align::Start, Align::Start))
|
||||||
.build(true, WrapMode::Word, 64);
|
.build(Some(64));
|
||||||
|
|
||||||
output_code.get_input().set_editable(false);
|
output_code.get_input().set_editable(false);
|
||||||
|
|
||||||
|
for input in [&input_code, &output_code] {
|
||||||
|
input.get_input().set_monospace(true);
|
||||||
|
input.get_input().set_wrap_mode(WrapMode::Word);
|
||||||
|
}
|
||||||
|
|
||||||
let clear_input_button = Button::builder()
|
let clear_input_button = Button::builder()
|
||||||
.set_align(Alignment::new(Align::Fill, Align::Fill))
|
.set_align(Alignment::new(Align::Fill, Align::Fill))
|
||||||
.label("Очистка полей")
|
.label("Очистка полей")
|
||||||
|
|
|
@ -1,29 +1,24 @@
|
||||||
use std::cell::Cell;
|
use std::{cell::Cell, rc::Rc};
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
model::{builder_traits::Product, models::SignalReduce, Frequency},
|
model::{builder_traits::Product, models::SignalReduce, Frequency},
|
||||||
model_utils::signal_reducer::{
|
model_utils::signal_reducer::{find_by_frequency_value, set_default_values},
|
||||||
coef_of_signal_reduce, full_resistance_of_capacitor, reactive_resistance_of_capacitor,
|
|
||||||
voltage_from_signal_source,
|
|
||||||
},
|
|
||||||
view::{
|
view::{
|
||||||
components::{info_bar::InfoBar, input::Input},
|
components::{info_bar::InfoBar, input::Input},
|
||||||
properties::*,
|
properties::*,
|
||||||
},
|
},
|
||||||
view_utils::signal_reduce_input_utils::{get_error_message, parse_fields},
|
view_utils::signal_reduce_utils::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use glib::clone;
|
use glib::clone;
|
||||||
|
|
||||||
extern crate gio;
|
|
||||||
|
|
||||||
use gio::ListStore;
|
use gio::ListStore;
|
||||||
|
|
||||||
use gtk::{
|
use gtk::{
|
||||||
prelude::{BoxExt, ButtonExt, Cast, CastNone, GridExt, ListItemExt, ListModelExt, SorterExt},
|
prelude::{BoxExt, ButtonExt, Cast, GridExt, SorterExt},
|
||||||
Align, WrapMode, *,
|
Align, *,
|
||||||
};
|
};
|
||||||
|
|
||||||
use gtk4 as gtk;
|
use gtk4 as gtk;
|
||||||
|
|
||||||
pub fn signal_reducing_page(wrapper: &Box) {
|
pub fn signal_reducing_page(wrapper: &Box) {
|
||||||
|
@ -31,9 +26,6 @@ pub fn signal_reducing_page(wrapper: &Box) {
|
||||||
|
|
||||||
let info_bar = InfoBar::get_instance();
|
let info_bar = InfoBar::get_instance();
|
||||||
|
|
||||||
let (input_height, monospace, input_wrapping): (i32, bool, WrapMode) =
|
|
||||||
(24, true, WrapMode::Word);
|
|
||||||
|
|
||||||
let input_block: Grid = Grid::new();
|
let input_block: Grid = Grid::new();
|
||||||
|
|
||||||
input_block.set_column_homogeneous(true);
|
input_block.set_column_homogeneous(true);
|
||||||
|
@ -46,37 +38,31 @@ pub fn signal_reducing_page(wrapper: &Box) {
|
||||||
|
|
||||||
let input_labels: [&str; 6] = ["l, м:", "Rм, Ом", "Cм, пФ:", "Rи, Ом:", "Vи, мВ", "f, мГц:"];
|
let input_labels: [&str; 6] = ["l, м:", "Rм, Ом", "Cм, пФ:", "Rи, Ом:", "Vи, мВ", "f, мГц:"];
|
||||||
|
|
||||||
let all_inputs: Vec<Input> = input_labels
|
let all_inputs: Vec<Input<Entry>> = input_labels
|
||||||
.iter()
|
.iter()
|
||||||
.map(move |label| {
|
.enumerate()
|
||||||
Input::builder()
|
.map(|(index, label)| {
|
||||||
|
let elem = Input::<Entry>::builder()
|
||||||
.label(label)
|
.label(label)
|
||||||
.margins(MarginData::EqualsMargin(6))
|
.margins(MarginData::EqualsMargin(6))
|
||||||
.align(input_label_alignment)
|
.align(input_label_alignment)
|
||||||
.build(monospace, input_wrapping, input_height)
|
.build_entry(None);
|
||||||
|
|
||||||
|
let row = index as i32 / 3;
|
||||||
|
|
||||||
|
input_block.attach(elem.get(), (index as i32) - (3 * row), row, 1, 1);
|
||||||
|
|
||||||
|
elem
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for (id, elem) in all_inputs.iter().enumerate() {
|
|
||||||
let row = id as i32 / 3;
|
|
||||||
|
|
||||||
input_block.attach(elem.get(), (id as i32) - (3 * row), row, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let calculate_button = Button::builder().label("Расчитать").build();
|
let calculate_button = Button::builder().label("Расчитать").build();
|
||||||
|
|
||||||
let result_table_headers_labels: [&str; 4] = ["f, МГц", "Xc, Ом", "Vп, мВ", "ζ"];
|
let result_table_headers_labels: [&str; 4] = ["f, МГц", "Xc, Ом", "Vп, мВ", "ζ"];
|
||||||
|
|
||||||
let model = ListStore::new::<Frequency>();
|
let model = ListStore::new::<Frequency>();
|
||||||
let model_for_events = model.clone();
|
|
||||||
|
|
||||||
for number in (0..=100).step_by(5) {
|
set_default_values(&model);
|
||||||
if number == 0 {
|
|
||||||
model.append(&Frequency::new(1.0));
|
|
||||||
} else if (number >= 70 && number % 10 == 0) || (number < 70 && number % 5 == 0) {
|
|
||||||
model.append(&Frequency::new(number as f64));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let numeric_sorter = CustomSorter::new(|a, b| {
|
let numeric_sorter = CustomSorter::new(|a, b| {
|
||||||
let a = a.downcast_ref::<Frequency>().unwrap().frequency();
|
let a = a.downcast_ref::<Frequency>().unwrap().frequency();
|
||||||
|
@ -85,12 +71,11 @@ pub fn signal_reducing_page(wrapper: &Box) {
|
||||||
a.total_cmp(&b).into()
|
a.total_cmp(&b).into()
|
||||||
});
|
});
|
||||||
|
|
||||||
let sorted_model = SortListModel::new(Some(model), Some(numeric_sorter.clone()));
|
let sorted_model = SortListModel::new(Some(model.clone()), Some(numeric_sorter.clone()));
|
||||||
|
|
||||||
let selection_model = NoSelection::new(Some(sorted_model));
|
let selection_model = NoSelection::new(Some(sorted_model.clone()));
|
||||||
|
|
||||||
let result_table = ColumnView::builder()
|
let result_table = ColumnView::builder()
|
||||||
.reorderable(true)
|
|
||||||
.show_row_separators(true)
|
.show_row_separators(true)
|
||||||
.model(&selection_model)
|
.model(&selection_model)
|
||||||
.build();
|
.build();
|
||||||
|
@ -98,78 +83,19 @@ pub fn signal_reducing_page(wrapper: &Box) {
|
||||||
result_table.connect_activate(clone!(
|
result_table.connect_activate(clone!(
|
||||||
#[strong]
|
#[strong]
|
||||||
numeric_sorter,
|
numeric_sorter,
|
||||||
move |_, _| {
|
move |_, _| numeric_sorter.changed(SorterChange::Different)
|
||||||
numeric_sorter.changed(SorterChange::Different);
|
|
||||||
}
|
|
||||||
));
|
));
|
||||||
|
|
||||||
for label in result_table_headers_labels {
|
for label in result_table_headers_labels {
|
||||||
let factory = SignalListItemFactory::new();
|
let factory = SignalListItemFactory::new();
|
||||||
|
|
||||||
factory.connect_setup(move |_, list_item| {
|
factory.connect_setup(column_view_setup_factory);
|
||||||
list_item
|
|
||||||
.downcast_ref::<ListItem>()
|
|
||||||
.expect("Needs to be ListItem")
|
|
||||||
.set_child(Some(&Label::new(None)));
|
|
||||||
});
|
|
||||||
|
|
||||||
let values_for_factory = values.clone();
|
factory.connect_bind(clone!(
|
||||||
|
#[strong]
|
||||||
factory.connect_bind(move |_, list_item| {
|
values,
|
||||||
let cell_value = list_item
|
move |factory, list| column_view_bind_factory(factory, list, values.get(), label)
|
||||||
.downcast_ref::<ListItem>()
|
));
|
||||||
.expect("Needs to be ListItem")
|
|
||||||
.item()
|
|
||||||
.and_downcast::<Frequency>()
|
|
||||||
.expect("The item has to be an `IntegerObject`.");
|
|
||||||
|
|
||||||
let cell_label = list_item
|
|
||||||
.downcast_ref::<ListItem>()
|
|
||||||
.expect("Needs to be ListItem")
|
|
||||||
.child()
|
|
||||||
.and_downcast::<Label>()
|
|
||||||
.expect("The child has to be a `Label`.");
|
|
||||||
|
|
||||||
let result_values = values_for_factory.get();
|
|
||||||
|
|
||||||
let reactive_resist: f64 = reactive_resistance_of_capacitor(
|
|
||||||
result_values.wire_capacity * 10f64.powi(-12),
|
|
||||||
result_values.length,
|
|
||||||
cell_value.frequency() * 10f64.powi(6),
|
|
||||||
);
|
|
||||||
|
|
||||||
let full_resistance: f64 = full_resistance_of_capacitor(
|
|
||||||
reactive_resist,
|
|
||||||
result_values.source_resistance,
|
|
||||||
result_values.wire_resistance,
|
|
||||||
result_values.length,
|
|
||||||
);
|
|
||||||
|
|
||||||
let signal_source_voltage: f64 = voltage_from_signal_source(
|
|
||||||
result_values.source_voltage * 10f64.powi(-3),
|
|
||||||
reactive_resist,
|
|
||||||
full_resistance,
|
|
||||||
) * 1000.0;
|
|
||||||
|
|
||||||
match label {
|
|
||||||
"f, МГц" => {
|
|
||||||
cell_label.set_label(&cell_value.frequency().to_string());
|
|
||||||
}
|
|
||||||
"Xc, Ом" => {
|
|
||||||
cell_label.set_label(format!("{0:.1$}", reactive_resist, 6).as_str());
|
|
||||||
}
|
|
||||||
"Vп, мВ" => {
|
|
||||||
cell_label.set_label(format!("{0:.1$}", signal_source_voltage, 6).as_str());
|
|
||||||
}
|
|
||||||
"ζ" => {
|
|
||||||
let coef: f64 =
|
|
||||||
coef_of_signal_reduce(result_values.source_voltage, signal_source_voltage);
|
|
||||||
|
|
||||||
cell_label.set_label(format!("{0:.1$}", coef, 6).as_str());
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let column = ColumnViewColumn::builder()
|
let column = ColumnViewColumn::builder()
|
||||||
.title(label)
|
.title(label)
|
||||||
|
@ -193,28 +119,23 @@ pub fn signal_reducing_page(wrapper: &Box) {
|
||||||
|
|
||||||
calculate_button.connect_clicked(clone!(
|
calculate_button.connect_clicked(clone!(
|
||||||
#[strong]
|
#[strong]
|
||||||
model_for_events,
|
model,
|
||||||
|
#[strong]
|
||||||
|
result_table,
|
||||||
move |_| match parse_fields(all_inputs.clone()) {
|
move |_| match parse_fields(all_inputs.clone()) {
|
||||||
Ok(results) => {
|
Ok(results) => {
|
||||||
values.set(results);
|
values.set(results);
|
||||||
|
|
||||||
let new_elem = &Frequency::new(values.get().frequency);
|
let new_elem = Frequency::new(values.get().frequency);
|
||||||
|
|
||||||
let exist_elem_pos = model_for_events.find_with_equal_func(|elem| {
|
let exist_elem_pos = find_by_frequency_value(&model, &new_elem);
|
||||||
elem.downcast_ref::<Frequency>().unwrap().frequency() == new_elem.frequency()
|
|
||||||
});
|
|
||||||
|
|
||||||
match exist_elem_pos {
|
if exist_elem_pos.is_some() {
|
||||||
Some(_) => {
|
|
||||||
info_bar.set_text_label(Some("Данная частота уже была задана."));
|
info_bar.set_text_label(Some("Данная частота уже была задана."));
|
||||||
info_bar.show_infobar(5u64);
|
info_bar.show_infobar(5u64);
|
||||||
}
|
} else {
|
||||||
None => {
|
model.append(&new_elem);
|
||||||
model_for_events.append(&Frequency::new(values.get().frequency));
|
update_column_view(&result_table)
|
||||||
|
|
||||||
model_for_events.items_changed(0, 0, 1);
|
|
||||||
model_for_events.items_changed(1, 1, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
|
|
@ -23,7 +23,6 @@ pub enum MarginData {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
||||||
pub struct Size {
|
pub struct Size {
|
||||||
pub width: i32,
|
pub width: i32,
|
||||||
pub height: i32,
|
pub height: i32,
|
||||||
|
@ -44,27 +43,6 @@ pub trait Setters {
|
||||||
fn set_align(self, align: Alignment) -> Self;
|
fn set_align(self, align: Alignment) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TextViewSetters {
|
|
||||||
fn set_text_view_margin(self, margin: MarginData) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TextViewSetters for TextViewBuilder {
|
|
||||||
fn set_text_view_margin(self, margin: MarginData) -> Self {
|
|
||||||
match margin {
|
|
||||||
MarginData::EqualsMargin(margin) => self
|
|
||||||
.top_margin(margin)
|
|
||||||
.left_margin(margin)
|
|
||||||
.bottom_margin(margin)
|
|
||||||
.right_margin(margin),
|
|
||||||
MarginData::MultipleMargin(margins) => self
|
|
||||||
.top_margin(margins.0)
|
|
||||||
.left_margin(margins.1)
|
|
||||||
.bottom_margin(margins.2)
|
|
||||||
.right_margin(margins.3),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Macros
|
* Macros
|
||||||
*/
|
*/
|
||||||
|
@ -97,7 +75,7 @@ macro_rules! impl_setters {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_setters! {ButtonBuilder, EntryBuilder, TextViewBuilder,
|
impl_setters! {ButtonBuilder, EntryBuilder, TextViewBuilder,
|
||||||
BoxBuilder, SwitchBuilder, FrameBuilder, LabelBuilder}
|
BoxBuilder, SwitchBuilder, FrameBuilder, LabelBuilder, PasswordEntryBuilder}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl Size {
|
impl Size {
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
@import url("info_bar.css");
|
||||||
|
@import url("text_view.css");
|
|
@ -9,7 +9,8 @@ use gtk::{
|
||||||
|
|
||||||
pub fn load_css() {
|
pub fn load_css() {
|
||||||
let style_provider = CssProvider::new();
|
let style_provider = CssProvider::new();
|
||||||
style_provider.load_from_path(Path::new("./src/view/styles/info_bar.css"));
|
|
||||||
|
style_provider.load_from_path(Path::new("./src/view/styles/base.css"));
|
||||||
|
|
||||||
style_context_add_provider_for_display(
|
style_context_add_provider_for_display(
|
||||||
&Display::default().expect("Could not connect to a display"),
|
&Display::default().expect("Could not connect to a display"),
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
textview {
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 7px 8px;
|
||||||
|
background: #E6E6E6;
|
||||||
|
outline-offset: 2px;
|
||||||
|
outline: 2px solid #81ABDF00;
|
||||||
|
transition-duration: .15s;
|
||||||
|
transition-timing-function: ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
textview:focus-within {
|
||||||
|
outline-offset: -2px;
|
||||||
|
outline: 2px solid #81ABDF;
|
||||||
|
}
|
|
@ -53,8 +53,8 @@ pub fn ui(application: &adw::Application) {
|
||||||
|
|
||||||
let window = ApplicationWindow::builder()
|
let window = ApplicationWindow::builder()
|
||||||
.title("Комплексная программа для лаб. работ")
|
.title("Комплексная программа для лаб. работ")
|
||||||
.width_request(700)
|
.width_request(800)
|
||||||
.height_request(400)
|
.height_request(600)
|
||||||
.application(application)
|
.application(application)
|
||||||
.child(&application_box)
|
.child(&application_box)
|
||||||
.build();
|
.build();
|
||||||
|
|
Loading…
Reference in New Issue