Skip to content

Commit

Permalink
Main window refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
BojanStipic committed Sep 23, 2019
1 parent f34f84f commit 365a714
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 123 deletions.
4 changes: 2 additions & 2 deletions src/MainWindow.glade
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@
<property name="has_subtitle">False</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkFileChooserButton" id="open_button">
<object class="GtkFileChooserButton" id="open_executable">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="filter">executable_filter</property>
<property name="title" translatable="yes">Open an Executable to Debug</property>
</object>
</child>
<child>
<object class="GtkMenuButton" id="primary_menu">
<object class="GtkMenuButton" id="open_primary_menu">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
Expand Down
306 changes: 185 additions & 121 deletions src/gui.rs
Original file line number Diff line number Diff line change
@@ -1,189 +1,253 @@
#![allow(unused)]
use std::fs;
use std::ops::Drop;
use gtk::prelude::*;
use gtk::{
Application,
Builder,
Window,
Button,
FileChooserButton,
ToggleButton,
SearchBar,
SearchEntry,
};
use gdk::RGBA;
use sourceview::prelude::*;
use sourceview::{
View,
MarkAttributes,
LanguageManager,
StyleSchemeManager,
Buffer,
SearchContext,
SearchSettings,
};

pub struct MainWindow {
ui: Builder,
}

pub struct AboutDialog {
dialog: gtk::AboutDialog,
}

impl AboutDialog {
fn new(parent: &gtk::Window) -> Self {
let glade_src = include_str!("AboutDialog.glade");
let builder = Builder::new_from_string(glade_src);

let dialog: gtk::AboutDialog = builder.get_object("about_dialog").unwrap();
dialog.set_transient_for(Some(parent));
dialog.run();
Self {
dialog
}
}
}

impl Drop for AboutDialog {
fn drop(&mut self) {
self.dialog.destroy();
}
window: gtk::Window,
header_bar: MainHeaderBar,
toolbar: MainToolbar,
source_window: SourceWindow,
execution_window: ExecutionWindow,
}

impl MainWindow {
pub fn new(application: &Application) -> Self {
pub fn new(parent: &gtk::Application) -> Self {
let glade_src = include_str!("MainWindow.glade");
let main_window = Self {
ui: Builder::new_from_string(glade_src),
let builder = gtk::Builder::new_from_string(glade_src);

let window = Self {
window: builder.get_object("main_window").unwrap(),
header_bar: MainHeaderBar::new(&builder),
toolbar: MainToolbar::new(&builder),
source_window: SourceWindow::new(&builder),
execution_window: ExecutionWindow::new(&builder),
};
window.connect_events();
window.window.set_application(Some(parent));
window.window.show_all();

main_window.connect_events();
main_window.build_ui(application);

main_window
}

fn build_ui(&self, application: &Application) {
let window: Window = self.ui.get_object("main_window").unwrap();
window.set_application(Some(application));

// Set default sourceview colorscheme
let source_buffer: Buffer = self.ui.get_object("source_buffer").unwrap();
if let Some(theme) = StyleSchemeManager::new().get_scheme("oblivion") {
source_buffer.set_style_scheme(Some(&theme));
}

// Attributes for breakpoint marks
let source_view: View = self.ui.get_object("source_view").unwrap();
let breakpoint_mark = MarkAttributes::new();
breakpoint_mark.set_icon_name("media-record");
source_view.set_mark_attributes("breakpoint", &breakpoint_mark, 1);

// Attributes for execution marks
let color = source_buffer.get_style_scheme().unwrap()
.get_style("current-line").unwrap()
.get_property_background().unwrap();
let execution_mark = MarkAttributes::new();
execution_mark.set_background(&color.parse::<RGBA>().unwrap());
source_view.set_mark_attributes("execution", &execution_mark, 1);

window.show_all();
window
}

fn connect_events(&self) {
let open_about_dialog: Button = self.ui.get_object("open_about_dialog").unwrap();
let ui = self.ui.clone();
open_about_dialog.connect_clicked(move |_| {
let window: Window = ui.get_object("main_window").unwrap();
AboutDialog::new(&window);
let parent = self.window.clone();
self.header_bar.primary_menu.open_about_dialog.connect_clicked(move |_| {
AboutDialog::new(&parent);
});

let file_chooser: FileChooserButton = self.ui.get_object("open_button").unwrap();
let ui = self.ui.clone();
file_chooser.connect_file_set(move |file_chooser| {
let buffer = self.source_window.buffer.clone();
self.header_bar.open_executable.connect_file_set(move |file_chooser| {
if let Some(filename) = file_chooser.get_filename() {
let file_contents = fs::read_to_string(&filename).unwrap();
let source_buffer: Buffer = ui.get_object("source_buffer").unwrap();
source_buffer.remove_source_marks(
&source_buffer.get_start_iter(),
&source_buffer.get_end_iter(),
buffer.remove_source_marks(
&buffer.get_start_iter(),
&buffer.get_end_iter(),
None,
);
source_buffer.set_text(&file_contents);
buffer.set_text(&file_contents);

if let Some(lang) = LanguageManager::get_default().unwrap()
if let Some(lang) = sourceview::LanguageManager::get_default().unwrap()
.guess_language(Some(filename.to_str().unwrap()), None) {
source_buffer.set_language(Some(&lang));
buffer.set_language(Some(&lang));
};
};
});

let source_view: View = self.ui.get_object("source_view").unwrap();
let ui = self.ui.clone();
source_view.connect_line_mark_activated(move |_, iter, _| {
let source_buffer: Buffer = ui.get_object("source_buffer").unwrap();
let buffer = self.source_window.buffer.clone();
self.source_window.view.connect_line_mark_activated(move |_, iter, _| {
let mut iter = iter.clone();
let marks = source_buffer.get_source_marks_at_iter(&mut iter, Some("breakpoint"));
let marks = buffer.get_source_marks_at_iter(&mut iter, Some("breakpoint"));
if marks.is_empty() {
source_buffer.create_source_mark(None, "breakpoint", &iter).unwrap();
buffer.create_source_mark(None, "breakpoint", &iter).unwrap();
}
else {
source_buffer.remove_source_marks(&iter, &iter, Some("breakpoint"));
buffer.remove_source_marks(&iter, &iter, Some("breakpoint"));
}
});

let search_toggle: ToggleButton = self.ui.get_object("search_toggle").unwrap();
let search_bar: SearchBar = self.ui.get_object("search_bar").unwrap();
let search_toggle_c = search_toggle.clone();
let search_bar_c = search_bar.clone();
search_toggle.connect_toggled(move |search_toggle| {
search_bar_c.set_search_mode(search_toggle.get_active());
let search_bar = self.source_window.search_bar.clone();
self.header_bar.search_toggle.connect_toggled(move |search_toggle| {
search_bar.set_search_mode(search_toggle.get_active());
});
search_bar.connect_property_search_mode_enabled_notify(move |search_bar| {
search_toggle_c.set_active(search_bar.get_search_mode());
let search_toggle = self.header_bar.search_toggle.clone();
self.source_window.search_bar.connect_property_search_mode_enabled_notify(move |search_bar| {
search_toggle.set_active(search_bar.get_search_mode());
});

let search_entry: SearchEntry = self.ui.get_object("search_entry").unwrap();
let ui = self.ui.clone();
search_entry.connect_search_changed(move |search_entry| {
let buffer = self.source_window.buffer.clone();
self.source_window.search_entry.connect_search_changed(move |search_entry| {
let search = match search_entry.get_text() {
Some(s) => s,
None => return,
};
let settings = SearchSettings::new();
let settings = sourceview::SearchSettings::new();
settings.set_search_text(Some(&search));

let buffer: Buffer = ui.get_object("source_buffer").unwrap();
let cursor = buffer.get_insert().unwrap();
let cursor = buffer.get_iter_at_mark(&cursor);

let context = SearchContext::new(&buffer, Some(&settings));
let context = sourceview::SearchContext::new(&buffer, Some(&settings));
if let Some((lhs, rhs, _)) = context.forward2(&cursor) {
buffer.select_range(&lhs, &rhs);
};
});

let ui = self.ui.clone();
search_entry.connect_next_match(move |search_entry| {
let buffer = self.source_window.buffer.clone();
self.source_window.search_entry.connect_next_match(move |search_entry| {
let search = match search_entry.get_text() {
Some(s) => s,
None => return,
};
let settings = SearchSettings::new();
let settings = sourceview::SearchSettings::new();
settings.set_search_text(Some(&search));

let buffer: Buffer = ui.get_object("source_buffer").unwrap();
let cursor = buffer.get_selection_bound().unwrap();
let cursor = buffer.get_iter_at_mark(&cursor);

let context = SearchContext::new(&buffer, Some(&settings));
let context = sourceview::SearchContext::new(&buffer, Some(&settings));
if let Some((lhs, rhs, _)) = context.forward2(&cursor) {
buffer.select_range(&lhs, &rhs);
};
});

search_entry.connect_previous_match(|_| {});
search_entry.connect_stop_search(|_| {});
self.source_window.search_entry.connect_previous_match(|_| {});
self.source_window.search_entry.connect_stop_search(|_| {});
}
}

struct MainHeaderBar {
headerbar: gtk::HeaderBar,
open_executable: gtk::FileChooserButton,
search_toggle: gtk::ToggleButton,
open_primary_menu: gtk::Button,
primary_menu: PrimaryMenu,
}

impl MainHeaderBar {
fn new(builder: &gtk::Builder) -> Self {
Self {
headerbar: builder.get_object("main_header_bar").unwrap(),
open_executable: builder.get_object("open_executable").unwrap(),
search_toggle: builder.get_object("search_toggle").unwrap(),
open_primary_menu: builder.get_object("open_primary_menu").unwrap(),
primary_menu: PrimaryMenu::new(builder),
}
}
}

struct PrimaryMenu {
popover: gtk::Popover,
open_preferences: gtk::Button,
open_about_dialog: gtk::Button,
}

impl PrimaryMenu {
fn new(builder: &gtk::Builder) -> Self {
Self {
popover: builder.get_object("primary_popover").unwrap(),
open_preferences: builder.get_object("open_preferences").unwrap(),
open_about_dialog: builder.get_object("open_about_dialog").unwrap(),
}
}
}

struct MainToolbar {
toolbar: gtk::Toolbar,
run_cmd: gtk::ToolButton,
interrupt_cmd: gtk::ToolButton,
kill_cmd: gtk::ToolButton,
step_cmd: gtk::ToolButton,
next_cmd: gtk::ToolButton,
continue_cmd: gtk::ToolButton,
}

impl MainToolbar {
fn new(builder: &gtk::Builder) -> Self {
Self {
toolbar: builder.get_object("main_toolbar").unwrap(),
run_cmd: builder.get_object("run").unwrap(),
interrupt_cmd: builder.get_object("interrupt").unwrap(),
kill_cmd: builder.get_object("kill").unwrap(),
step_cmd: builder.get_object("step").unwrap(),
next_cmd: builder.get_object("next").unwrap(),
continue_cmd: builder.get_object("continue").unwrap(),
}
}
}

struct SourceWindow {
search_bar: gtk::SearchBar,
search_entry: gtk::SearchEntry,
view: sourceview::View,
buffer: sourceview::Buffer,
}

impl SourceWindow {
fn new(builder: &gtk::Builder) -> Self {
let window = Self {
search_bar: builder.get_object("search_bar").unwrap(),
search_entry: builder.get_object("search_entry").unwrap(),
view: builder.get_object("source_view").unwrap(),
buffer: builder.get_object("source_buffer").unwrap(),
};

// Set default sourceview colorscheme
if let Some(theme) = sourceview::StyleSchemeManager::new().get_scheme("oblivion") {
window.buffer.set_style_scheme(Some(&theme));
}

// Attributes for breakpoint marks
let breakpoint_mark = sourceview::MarkAttributes::new();
breakpoint_mark.set_icon_name("media-record");
window.view.set_mark_attributes("breakpoint", &breakpoint_mark, 1);

// Attributes for execution marks
let color = window.buffer.get_style_scheme().unwrap()
.get_style("current-line").unwrap()
.get_property_background().unwrap();
let execution_mark = sourceview::MarkAttributes::new();
execution_mark.set_background(&color.parse::<RGBA>().unwrap());
window.view.set_mark_attributes("execution", &execution_mark, 1);

window
}
}

struct ExecutionWindow {
view: gtk::TextView,
}

impl ExecutionWindow {
fn new(builder: &gtk::Builder) -> Self {
Self {
view: builder.get_object("execution_window").unwrap(),
}
}
}

struct AboutDialog {
dialog: gtk::AboutDialog,
}

impl AboutDialog {
fn new(parent: &gtk::Window) -> Self {
let glade_src = include_str!("AboutDialog.glade");
let builder = gtk::Builder::new_from_string(glade_src);

let dialog: gtk::AboutDialog = builder.get_object("about_dialog").unwrap();
dialog.set_transient_for(Some(parent));
dialog.run();
Self {
dialog
}
}
}

impl Drop for AboutDialog {
fn drop(&mut self) {
self.dialog.destroy();
}
}

0 comments on commit 365a714

Please sign in to comment.