forked from 1b-agent/opencadstudio-upstream
1 parent
4af141ebec
commit
c9aab122f0
10 files changed
+814
-7
No files matched your search
@@ -1078,13 +1078,7 @@ impl OpenCADStudio {
|
||||
// FIND <search> REPLACE <rep> — replace first occurrence (case-insensitive)
|
||||
// FINDALL <search> REPLACE <rep> — replace all occurrences
|
||||
"FIND" => {
|
||||
use crate::command::ValuePromptCommand;
|
||||
let c = ValuePromptCommand::new(
|
||||
"FIND",
|
||||
"FIND text to find (add REPLACE <text> by typing):",
|
||||
);
|
||||
self.command_line.push_info(&c.prompt());
|
||||
self.tabs[self.active_tab].active_cmd = Some(Box::new(c));
|
||||
return Some(Task::done(Message::FindReplaceOpen));
|
||||
}
|
||||
"FINDALL" => {
|
||||
use crate::command::ValuePromptCommand;
|
||||
|
||||
@@ -0,0 +1,462 @@
|
||||
use super::{FindMatchKey, Message, OpenCADStudio};
|
||||
use crate::entities::traits::EntityTypeOps;
|
||||
use acadrust::EntityType;
|
||||
use iced::Task;
|
||||
|
||||
impl OpenCADStudio {
|
||||
pub(super) fn open_find_replace(&mut self) -> Task<Message> {
|
||||
self.find_replace.current_match = None;
|
||||
self.find_replace.status.clear();
|
||||
self.active_modal = Some(super::ModalKind::FindReplace);
|
||||
self.modal_offset = iced::Vector::ZERO;
|
||||
self.modal_resize = iced::Vector::ZERO;
|
||||
iced::widget::operation::focus(iced::widget::Id::new(
|
||||
crate::ui::window::find_replace::FIND_INPUT_ID,
|
||||
))
|
||||
}
|
||||
|
||||
pub(super) fn find_replace_search_changed(&mut self, value: String) {
|
||||
self.find_replace.search = value;
|
||||
self.find_replace.current_match = None;
|
||||
self.find_replace.status.clear();
|
||||
}
|
||||
|
||||
pub(super) fn find_replace_replacement_changed(&mut self, value: String) {
|
||||
self.find_replace.replacement = value;
|
||||
}
|
||||
|
||||
pub(super) fn find_replace_next(&mut self) {
|
||||
let i = self.active_tab;
|
||||
let matches = self.find_navigation_matches(i);
|
||||
if matches.is_empty() {
|
||||
self.find_replace.current_match = None;
|
||||
self.find_replace.status = no_match_status(&self.find_replace.search);
|
||||
return;
|
||||
}
|
||||
|
||||
let start = self
|
||||
.find_replace
|
||||
.current_match
|
||||
.and_then(|current| matches.iter().position(|candidate| *candidate == current))
|
||||
.map_or(0, |current| (current + 1) % matches.len());
|
||||
for offset in 0..matches.len() {
|
||||
let index = (start + offset) % matches.len();
|
||||
let target = matches[index];
|
||||
let centered = match target {
|
||||
FindMatchKey::Entity(handle) => {
|
||||
self.tabs[i].scene.center_camera_on_entity(handle)
|
||||
}
|
||||
FindMatchKey::BlockEntityInInsert { entity, insert } => self.tabs[i]
|
||||
.scene
|
||||
.center_camera_on_block_entity(insert, entity),
|
||||
FindMatchKey::InsertAttribute { insert, index } => {
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.center_camera_on_insert_attribute(insert, index)
|
||||
}
|
||||
};
|
||||
if !centered {
|
||||
continue;
|
||||
}
|
||||
|
||||
self.find_replace.current_match = Some(target);
|
||||
self.find_replace.status = format!(
|
||||
"{} of {} — {}",
|
||||
index + 1,
|
||||
matches.len(),
|
||||
match_label(target)
|
||||
);
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.select_entity(match_owner_handle(target), false);
|
||||
self.refresh_properties();
|
||||
return;
|
||||
}
|
||||
|
||||
self.find_replace.current_match = None;
|
||||
self.find_replace.status = no_match_status(&self.find_replace.search);
|
||||
}
|
||||
|
||||
pub(super) fn find_replace_one(&mut self) {
|
||||
let i = self.active_tab;
|
||||
let matches = self.find_text_matches(i);
|
||||
let Some(target) = self
|
||||
.find_replace
|
||||
.current_match
|
||||
.filter(|current| {
|
||||
matches.iter().any(|candidate| {
|
||||
match_document_handle(*candidate) == match_document_handle(*current)
|
||||
})
|
||||
})
|
||||
.or_else(|| matches.first().copied())
|
||||
else {
|
||||
self.find_replace.current_match = None;
|
||||
self.find_replace.status = no_match_status(&self.find_replace.search);
|
||||
return;
|
||||
};
|
||||
|
||||
let search = self.find_replace.search.clone();
|
||||
let replacement = self.find_replace.replacement.clone();
|
||||
self.push_undo_snapshot(i, "FIND/REPLACE");
|
||||
let replaced = replace_match_text(
|
||||
&mut self.tabs[i].scene.document,
|
||||
target,
|
||||
&search,
|
||||
&replacement,
|
||||
false,
|
||||
);
|
||||
if replaced == 0 {
|
||||
self.discard_last_undo_entry(i);
|
||||
self.find_replace.status = no_match_status(&search);
|
||||
return;
|
||||
}
|
||||
|
||||
let handle = match_document_handle(target);
|
||||
if self.tabs[i]
|
||||
.scene
|
||||
.entity_belongs_to_active_space(handle)
|
||||
{
|
||||
self.invalidate_property_targets(i, &[handle]);
|
||||
} else {
|
||||
// A block-definition edit must rebuild the definition cache; an
|
||||
// entity-only delta would leave every visible INSERT showing the
|
||||
// old text until some unrelated full rebuild.
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
self.find_replace.current_match = None;
|
||||
let remaining = self.find_text_matches(i).len();
|
||||
self.find_replace.status = format!(
|
||||
"Replaced 1 occurrence in {}; {remaining} matching object(s) remain.",
|
||||
match_label(target)
|
||||
);
|
||||
self.command_line.push_output(&format!(
|
||||
"FIND/REPLACE: replaced 1 occurrence of \"{search}\"."
|
||||
));
|
||||
self.refresh_properties();
|
||||
}
|
||||
|
||||
pub(super) fn find_replace_all(&mut self) {
|
||||
let i = self.active_tab;
|
||||
let matches = self.find_text_matches(i);
|
||||
if matches.is_empty() {
|
||||
self.find_replace.current_match = None;
|
||||
self.find_replace.status = no_match_status(&self.find_replace.search);
|
||||
return;
|
||||
}
|
||||
|
||||
let search = self.find_replace.search.clone();
|
||||
let replacement = self.find_replace.replacement.clone();
|
||||
self.push_undo_snapshot(i, "FIND/REPLACE ALL");
|
||||
let mut replaced = 0usize;
|
||||
let mut changed = Vec::new();
|
||||
let mut changed_outside_active_space = false;
|
||||
for target in matches {
|
||||
let count = replace_match_text(
|
||||
&mut self.tabs[i].scene.document,
|
||||
target,
|
||||
&search,
|
||||
&replacement,
|
||||
true,
|
||||
);
|
||||
if count > 0 {
|
||||
replaced += count;
|
||||
let handle = match_document_handle(target);
|
||||
changed_outside_active_space |= !self.tabs[i]
|
||||
.scene
|
||||
.entity_belongs_to_active_space(handle);
|
||||
if !changed.contains(&handle) {
|
||||
changed.push(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
if changed.is_empty() {
|
||||
self.discard_last_undo_entry(i);
|
||||
self.find_replace.status = no_match_status(&search);
|
||||
return;
|
||||
}
|
||||
|
||||
if changed_outside_active_space {
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
} else {
|
||||
self.invalidate_property_targets(i, &changed);
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
self.find_replace.current_match = None;
|
||||
self.find_replace.status = format!(
|
||||
"Replaced {replaced} occurrence(s) in {} object(s).",
|
||||
changed.len()
|
||||
);
|
||||
self.command_line.push_output(&format!(
|
||||
"FIND/REPLACE: replaced {replaced} occurrence(s) of \"{search}\"."
|
||||
));
|
||||
self.refresh_properties();
|
||||
}
|
||||
|
||||
fn find_text_matches(&self, i: usize) -> Vec<FindMatchKey> {
|
||||
let search = self.find_replace.search.trim();
|
||||
if search.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
let mut visible = Vec::new();
|
||||
let mut definitions = Vec::new();
|
||||
for entity in self.tabs[i].scene.document.entities() {
|
||||
if let Some(text) = entity.text_content() {
|
||||
if find_case_insensitive_range(&text, search, 0).is_some() {
|
||||
let target = FindMatchKey::Entity(entity.common().handle);
|
||||
if self.tabs[i]
|
||||
.scene
|
||||
.entity_belongs_to_active_space(entity.common().handle)
|
||||
{
|
||||
visible.push(target);
|
||||
} else {
|
||||
definitions.push(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let EntityType::Insert(insert) = entity {
|
||||
for (index, attribute) in insert.attributes.iter().enumerate() {
|
||||
if find_case_insensitive_range(attribute.get_value(), search, 0).is_some() {
|
||||
let target = FindMatchKey::InsertAttribute {
|
||||
insert: insert.common.handle,
|
||||
index,
|
||||
};
|
||||
if self.tabs[i]
|
||||
.scene
|
||||
.entity_belongs_to_active_space(insert.common.handle)
|
||||
{
|
||||
visible.push(target);
|
||||
} else {
|
||||
definitions.push(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
visible.extend(definitions);
|
||||
visible
|
||||
}
|
||||
|
||||
fn find_navigation_matches(&self, i: usize) -> Vec<FindMatchKey> {
|
||||
let scene = &self.tabs[i].scene;
|
||||
let mut matches = Vec::new();
|
||||
for target in self.find_text_matches(i) {
|
||||
let owner = match_owner_handle(target);
|
||||
if scene.entity_belongs_to_active_space(owner) {
|
||||
matches.push(target);
|
||||
continue;
|
||||
}
|
||||
|
||||
let FindMatchKey::Entity(entity) = target else {
|
||||
continue;
|
||||
};
|
||||
for candidate in scene.document.entities() {
|
||||
let EntityType::Insert(insert) = candidate else {
|
||||
continue;
|
||||
};
|
||||
if !scene.entity_belongs_to_active_space(insert.common.handle) {
|
||||
continue;
|
||||
}
|
||||
let mut visited = Vec::new();
|
||||
if block_contains_entity(
|
||||
&scene.document,
|
||||
&insert.block_name,
|
||||
entity,
|
||||
&mut visited,
|
||||
) {
|
||||
matches.push(FindMatchKey::BlockEntityInInsert {
|
||||
entity,
|
||||
insert: insert.common.handle,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
matches
|
||||
}
|
||||
}
|
||||
|
||||
fn no_match_status(search: &str) -> String {
|
||||
if search.trim().is_empty() {
|
||||
"Enter text to find.".to_string()
|
||||
} else {
|
||||
format!("\"{search}\" was not found.")
|
||||
}
|
||||
}
|
||||
|
||||
fn replace_entity_text(
|
||||
entity: &mut EntityType,
|
||||
search: &str,
|
||||
replacement: &str,
|
||||
replace_all: bool,
|
||||
) -> usize {
|
||||
let Some(value) = entity.text_content() else {
|
||||
return 0;
|
||||
};
|
||||
let (value, count) = replace_case_insensitive(&value, search, replacement, replace_all);
|
||||
if count == 0 {
|
||||
return 0;
|
||||
}
|
||||
match entity {
|
||||
EntityType::Text(text) => text.value = value,
|
||||
EntityType::MText(text) => text.value = value,
|
||||
EntityType::AttributeDefinition(attribute) => attribute.default_value = value,
|
||||
EntityType::AttributeEntity(attribute) => attribute.set_value(value),
|
||||
_ => return 0,
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
fn replace_match_text(
|
||||
document: &mut acadrust::CadDocument,
|
||||
target: FindMatchKey,
|
||||
search: &str,
|
||||
replacement: &str,
|
||||
replace_all: bool,
|
||||
) -> usize {
|
||||
match target {
|
||||
FindMatchKey::Entity(handle) | FindMatchKey::BlockEntityInInsert { entity: handle, .. } => {
|
||||
document.get_entity_mut(handle).map_or(0, |entity| {
|
||||
replace_entity_text(entity, search, replacement, replace_all)
|
||||
})
|
||||
}
|
||||
FindMatchKey::InsertAttribute { insert, index } => {
|
||||
let Some(EntityType::Insert(entity)) = document.get_entity_mut(insert) else {
|
||||
return 0;
|
||||
};
|
||||
let Some(attribute) = entity.attributes.get_mut(index) else {
|
||||
return 0;
|
||||
};
|
||||
let (value, count) = replace_case_insensitive(
|
||||
attribute.get_value(),
|
||||
search,
|
||||
replacement,
|
||||
replace_all,
|
||||
);
|
||||
if count > 0 {
|
||||
attribute.set_value(value);
|
||||
}
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn match_owner_handle(target: FindMatchKey) -> acadrust::Handle {
|
||||
match target {
|
||||
FindMatchKey::Entity(handle) => handle,
|
||||
FindMatchKey::BlockEntityInInsert { insert, .. } => insert,
|
||||
FindMatchKey::InsertAttribute { insert, .. } => insert,
|
||||
}
|
||||
}
|
||||
|
||||
fn match_document_handle(target: FindMatchKey) -> acadrust::Handle {
|
||||
match target {
|
||||
FindMatchKey::Entity(handle) => handle,
|
||||
FindMatchKey::BlockEntityInInsert { entity, .. } => entity,
|
||||
FindMatchKey::InsertAttribute { insert, .. } => insert,
|
||||
}
|
||||
}
|
||||
|
||||
fn match_label(target: FindMatchKey) -> String {
|
||||
match target {
|
||||
FindMatchKey::Entity(handle) => format!("handle {:X}", handle.value()),
|
||||
FindMatchKey::BlockEntityInInsert { entity, insert } => {
|
||||
format!(
|
||||
"block {:X}, text {:X}",
|
||||
insert.value(),
|
||||
entity.value()
|
||||
)
|
||||
}
|
||||
FindMatchKey::InsertAttribute { insert, index } => {
|
||||
format!("block {:X}, attribute {}", insert.value(), index + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn block_contains_entity(
|
||||
document: &acadrust::CadDocument,
|
||||
block_name: &str,
|
||||
target: acadrust::Handle,
|
||||
visited: &mut Vec<String>,
|
||||
) -> bool {
|
||||
if visited
|
||||
.iter()
|
||||
.any(|name| name.eq_ignore_ascii_case(block_name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
let Some(record) = document
|
||||
.block_records
|
||||
.iter()
|
||||
.find(|record| record.name.eq_ignore_ascii_case(block_name))
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
visited.push(record.name.clone());
|
||||
let found = record.entity_handles.iter().any(|handle| {
|
||||
if *handle == target {
|
||||
return true;
|
||||
}
|
||||
matches!(
|
||||
document.get_entity(*handle),
|
||||
Some(EntityType::Insert(insert))
|
||||
if block_contains_entity(document, &insert.block_name, target, visited)
|
||||
)
|
||||
});
|
||||
visited.pop();
|
||||
found
|
||||
}
|
||||
|
||||
fn replace_case_insensitive(
|
||||
value: &str,
|
||||
search: &str,
|
||||
replacement: &str,
|
||||
replace_all: bool,
|
||||
) -> (String, usize) {
|
||||
if search.is_empty() {
|
||||
return (value.to_string(), 0);
|
||||
}
|
||||
|
||||
let mut result = String::with_capacity(value.len());
|
||||
let mut cursor = 0usize;
|
||||
let mut count = 0usize;
|
||||
while let Some((start, end)) = find_case_insensitive_range(value, search, cursor) {
|
||||
result.push_str(&value[cursor..start]);
|
||||
result.push_str(replacement);
|
||||
cursor = end;
|
||||
count += 1;
|
||||
if !replace_all {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if count == 0 {
|
||||
return (value.to_string(), 0);
|
||||
}
|
||||
result.push_str(&value[cursor..]);
|
||||
(result, count)
|
||||
}
|
||||
|
||||
fn find_case_insensitive_range(value: &str, search: &str, from: usize) -> Option<(usize, usize)> {
|
||||
let needle = search.to_lowercase();
|
||||
if needle.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
for (start, _) in value.char_indices().filter(|(index, _)| *index >= from) {
|
||||
let ends = value[start..]
|
||||
.char_indices()
|
||||
.skip(1)
|
||||
.map(|(offset, _)| start + offset)
|
||||
.chain(std::iter::once(value.len()));
|
||||
for end in ends {
|
||||
let candidate = value[start..end].to_lowercase();
|
||||
if candidate == needle {
|
||||
return Some((start, end));
|
||||
}
|
||||
if candidate.len() > needle.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -8,6 +8,7 @@ mod command_driver;
|
||||
pub(crate) mod commands;
|
||||
mod document;
|
||||
mod expr_eval;
|
||||
mod find_replace;
|
||||
mod helpers;
|
||||
mod history;
|
||||
mod layers;
|
||||
@@ -160,6 +161,27 @@ pub struct QSelectState {
|
||||
pub value: String,
|
||||
pub append: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub(crate) struct FindReplaceState {
|
||||
pub search: String,
|
||||
pub replacement: String,
|
||||
pub status: String,
|
||||
pub current_match: Option<FindMatchKey>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum FindMatchKey {
|
||||
Entity(acadrust::Handle),
|
||||
BlockEntityInInsert {
|
||||
entity: acadrust::Handle,
|
||||
insert: acadrust::Handle,
|
||||
},
|
||||
InsertAttribute {
|
||||
insert: acadrust::Handle,
|
||||
index: usize,
|
||||
},
|
||||
}
|
||||
use crate::snap::Snapper;
|
||||
use crate::ui::{CommandLine, Ribbon, StatusBar};
|
||||
use acadrust::types::{Color as AcadColor, LineWeight};
|
||||
@@ -470,6 +492,8 @@ pub(super) struct OpenCADStudio {
|
||||
/// The open in-canvas modal dialog, if any (Plan B: shared overlay instead
|
||||
/// of OS windows).
|
||||
active_modal: Option<ModalKind>,
|
||||
/// FIND dialog inputs and current result cursor.
|
||||
find_replace: FindReplaceState,
|
||||
/// Set once the user acknowledges the AEC-drop warning, so re-entering the
|
||||
/// save path proceeds instead of re-showing the warning.
|
||||
aec_drop_acknowledged: bool,
|
||||
@@ -1345,6 +1369,7 @@ pub enum ModalKind {
|
||||
Unsaved,
|
||||
SaveDialog,
|
||||
Options,
|
||||
FindReplace,
|
||||
AecDropWarning,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
FileInUse,
|
||||
@@ -1480,6 +1505,13 @@ pub enum Message {
|
||||
/// Ctrl/Cmd+A — select all layer rows when the Layer Manager is open, or all
|
||||
/// drawing objects otherwise (#236).
|
||||
SelectAllShortcut,
|
||||
/// Open the shared Find and Replace dialog (Ctrl/Cmd+F or Ctrl/Cmd+H).
|
||||
FindReplaceOpen,
|
||||
FindReplaceSearchChanged(String),
|
||||
FindReplaceReplacementChanged(String),
|
||||
FindReplaceNext,
|
||||
FindReplaceOne,
|
||||
FindReplaceAll,
|
||||
/// System-clipboard text read for the MText editor (`None` = empty/denied).
|
||||
MTextPasteClip(Option<String>),
|
||||
/// System-clipboard text read for the single-line TEXT editor.
|
||||
@@ -2685,6 +2717,7 @@ impl OpenCADStudio {
|
||||
main_window: None,
|
||||
color_pick_target: None,
|
||||
active_modal: None,
|
||||
find_replace: FindReplaceState::default(),
|
||||
aec_drop_acknowledged: false,
|
||||
aec_drop_count: 0,
|
||||
layer_delete_pending: None,
|
||||
|
||||
@@ -35,6 +35,7 @@ fn is_modal_blocked_key_msg(msg: &Message) -> bool {
|
||||
| Message::SaveAs
|
||||
| Message::Undo
|
||||
| Message::Redo
|
||||
| Message::FindReplaceOpen
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3235,6 +3236,27 @@ impl OpenCADStudio {
|
||||
self.dispatch_command("SELECTALL")
|
||||
}
|
||||
}
|
||||
Message::FindReplaceOpen => self.open_find_replace(),
|
||||
Message::FindReplaceSearchChanged(value) => {
|
||||
self.find_replace_search_changed(value);
|
||||
Task::none()
|
||||
}
|
||||
Message::FindReplaceReplacementChanged(value) => {
|
||||
self.find_replace_replacement_changed(value);
|
||||
Task::none()
|
||||
}
|
||||
Message::FindReplaceNext => {
|
||||
self.find_replace_next();
|
||||
Task::none()
|
||||
}
|
||||
Message::FindReplaceOne => {
|
||||
self.find_replace_one();
|
||||
Task::none()
|
||||
}
|
||||
Message::FindReplaceAll => {
|
||||
self.find_replace_all();
|
||||
Task::none()
|
||||
}
|
||||
Message::MTextPasteClip(text) => {
|
||||
if let Some(text) = text.filter(|t| !t.is_empty()) {
|
||||
// CR/LF arrive as line breaks; MText keeps "\n", drop "\r".
|
||||
|
||||
@@ -1586,6 +1586,7 @@ impl OpenCADStudio {
|
||||
About => (440, 360),
|
||||
Shortcuts => (720, 520),
|
||||
Options => (520, 500),
|
||||
FindReplace => (560, 190),
|
||||
PluginManager => {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
@@ -1889,6 +1890,7 @@ impl OpenCADStudio {
|
||||
"z" if !shift => Some(Message::Undo),
|
||||
"z" if shift => Some(Message::Redo),
|
||||
"y" => Some(Message::Redo),
|
||||
"f" | "h" => Some(Message::FindReplaceOpen),
|
||||
// Ctrl/Cmd+A: select all layer rows when the
|
||||
// Layer Manager is open, else all objects. The
|
||||
// update handler branches on the active modal.
|
||||
|
||||
@@ -17,6 +17,7 @@ impl OpenCADStudio {
|
||||
Some(K::Shortcuts) => "Keyboard Shortcuts",
|
||||
Some(K::Aliases) => "Command Aliases",
|
||||
Some(K::Options) => "Options",
|
||||
Some(K::FindReplace) => "Find and Replace",
|
||||
Some(K::PluginManager) => "Plugin Manager",
|
||||
Some(K::UpdateNotice) => "Update Available",
|
||||
Some(K::Layers) => "Layer Manager",
|
||||
@@ -102,6 +103,15 @@ impl OpenCADStudio {
|
||||
)
|
||||
},
|
||||
),
|
||||
super::super::ModalKind::FindReplace => sized(
|
||||
crate::ui::window::find_replace::view_window(
|
||||
&self.find_replace.search,
|
||||
&self.find_replace.replacement,
|
||||
&self.find_replace.status,
|
||||
),
|
||||
560,
|
||||
190,
|
||||
),
|
||||
super::super::ModalKind::PluginManager => {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user