-
Notifications
You must be signed in to change notification settings - Fork 323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Lazy Table Visualisation UI integration. #5806
Implement Lazy Table Visualisation UI integration. #5806
Conversation
3588df0
to
b4489af
Compare
const PADDING_TEXT: f32 = 5.0; | ||
|
||
const TEXT_PADDING: f32 = 1.5; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could use docs--the difference between these is not obvious.
/// Position of the cell in the table in columns and rows. | ||
pub cell: GridPosition, | ||
/// Position of the chunk in the cell in chunk index and lines. | ||
pub chunk: GridPosition, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a ChunkCoordinate
?
} | ||
} | ||
|
||
/// Position and size of a sub-grid within a grid. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docs should distinguish this from GridWindow
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved, with some comments.
As I understand it, we are calculating what text we need based on Unicode character counts, although the displayed size of the text depends on the number of resulting glyphs. Please check & document behavior when the number of glyphs is very different from the number of characters, particularly when the input contains many Unicode combining characters.
color::Lcha::new(0.95, 0.0, 0.0, 1.0), | ||
_ => color::Lcha::new(1.0, 0.0, 0.0, 0.0), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These could be constants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They should probably be taken form the theme. Changed it to that.
@@ -264,12 +386,14 @@ impl<T: TextProvider + 'static> TextGrid<T> { | |||
theme_update <- all(init, font_name, font_size); | |||
text_grid.set_entries_params <+ theme_update.map( | |||
f!([dom_entry_root]((_, font_name, font_size)) { | |||
let font_name = font_name.clone(); | |||
let font_size = *font_size; | |||
let parent = Some(dom_entry_root.clone_ref()); | |||
|
|||
dom_entry_root.set_style_or_warn("font-family", font_name.clone()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Not new code, but) this can be passed by reference.
visualization::Definition::new( | ||
visualization::Signature::new( | ||
path, | ||
"Standard.Table.Data.Table.Table", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Named constant.
@@ -18,10 +19,50 @@ use std::fmt::Write; | |||
// === Model === | |||
// ============= | |||
|
|||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra line.
pub content: Content, | ||
pub bg_color: color::Rgba, | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra line.
+ chunk.x as usize; | ||
let chunk_y = | ||
self.rows.iter().take(row).fold(0, |acc, x| acc + x.unwrap_or(0)) + chunk.y as usize; | ||
// error!("Converting {table_position:?} to {chunk_x} {chunk_y}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented code.
|
||
/// Return the table item at the given position in the grid. The given grid coordinates address | ||
/// the grid in chunks/lines. | ||
pub fn grid_view_position_to_table_item( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is called for every displayed cell, and it performs O(rows + cols)
string-scans and allocations. What about caching the results of the iter_row_items_per_line
and iter_column_items_per_chunk
operations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't usually have too many cells at once (probably a few dozen or a few hundreds at most). And keeping the cache correct could be a bit tricky as we can get updates to the table layout, so we need to carefully consider the cache invalidation there. Not a huge issue, but a bit of extra work for sure.
So, while this is a good comment, I think before implementing this, we should profile the actual impact of this.
fn try_from(data: serde_json::Value) -> Result<Self, Self::Error> { | ||
Ok(serde_json::from_value(data.clone()).unwrap_or_else(|_| { | ||
let data_str = serde_json::to_string_pretty(&data); | ||
let data_str = data_str.unwrap_or_else(|e| format!("<Cannot render data: {e}.>")); | ||
data_str.into() | ||
})) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why return Ok
if the input can't be deserialized?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole implementation is actually no longer needed. Removed it.
@@ -335,11 +991,61 @@ fn fill_emtpy_chunks(chunks: Vec<Chunk>) -> Vec<Chunk> { | |||
.collect() | |||
} | |||
|
|||
// ========================= |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing newlines.
Err(visualization::DataError::BinaryNotSupported) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing newlines after.
That is a pretty good point that has not been accounted for in the current design for both lazy table and lazy text. What we need to consider are graphemes. We can assume that we use as fixed width font, so all graphemes should be the same size. But on both the backend and the frontend we need to work with chunks of graphemes, to not split something up between chunks. I think this is mostly a “bookkeeping” issue for chunking and retrieving the data. Rendering them should then not be any different. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just approving the slight Enso changes.
On the library side, grapheme clusters are first-class citizens for Enso strings - i.e. by default |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks good, however I miss important information in the docs here and there.
use text_provider::BackendTextProvider; | ||
use text_provider::TextProvider; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think some of those are imported with full crate::...
path, and here are short paths. Or is text_provider
also a crate?
|
||
/// Position of a chunk in a table. Addressed by table cell first, then by chunk index/line within | ||
/// the cell. | ||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] | ||
pub struct TablePosition { | ||
/// Position of the cell in the table in columns and rows. | ||
pub cell: GridPosition, | ||
/// Position of the chunk in the cell in chunk index and lines. | ||
pub chunk: ChunkCoordinate, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is a table in this context? The module documentation mentions grid only. Is Table same as Grid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the module docs. "Table" in this context refers to the data in the backend, which consists of strings organized in rows/columns.
/// Column Width in lines | ||
type RowHeight = usize; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copied docs.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Copy)] | ||
/// A table item and its position. Only used for working on the layout, not for individual cells | ||
/// or accessing content. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We usually put docs before derives.
/// Iterate over the item in the table. Only returns the actual content items. Does not return | ||
/// the dividers or the headings. | ||
fn iter_content_columns(&self) -> impl Iterator<Item = TableItem> + '_ { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation does not explain the method's name.
/// Iterate over the item in the table. Only returns the actual content items. Does not return | ||
/// the dividers or the headings. | ||
fn iter_content_rows(&self) -> impl Iterator<Item = TableItem> + '_ { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
/// Convert the given cell / chunk position from the backend data into a chunk position for the | ||
/// text cache. | ||
pub fn backend_table_position_to_grid_content_position( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be a good idea to add information about time complexity - here and in next methods. We iterate over all columns on the left (if I understand the code correctly), and that might be substantial.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or are those displayed columns only? If yes, then I miss that important information here or in the structure's docs.
type RowIndex = usize; | ||
|
||
/// Specification of a table layout. Contains the column and row widths, as well as the column and | ||
/// row names. Provides methods for updating the specification and for accessing layout properties. | ||
/// We allow for a table specification to be partially specified, i.e., some of the information may | ||
/// be `None`. This is used to allow for lazy initialisation of the layout and incremental updates | ||
/// as the table is updated. | ||
#[derive(Clone, Debug, Deserialize, Serialize, Default)] | ||
pub struct TableSpecification { | ||
/// The width of each column in characters. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make subsection for TableSpecification, and the subsection for define_endpoints_2
below.
impl Model { | ||
/// Get the content of the model. | ||
pub fn text(&self, width: usize) -> String { | ||
match &self.content { | ||
Content::Text { content, .. } => content.to_string(), | ||
_ => " ".repeat(width), | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is width
exactly? Why once we return string of given width, but in other case return content without adjusting width?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the parameter. This was used earlier for some formatting but is not needed any more. The current use is obsolete and can return an empty string instead.
…ion_UI_Integration_5002 # Conflicts: # CHANGELOG.md # app/gui/view/graph-editor/Cargo.toml
What's the status of this PR? :) |
Fixing bugs and then QA is still to be done AFAIK |
…r/Lazy_Table_Visualisation_UI_Integration_5002 # Conflicts: # CHANGELOG.md
Michael Mauderer reports a new STANDUP for the provided date (2023-03-17): Progress: Worked on cleaning up code for the Lazy Table PR after fixing a regression affecting the Lazy Text visualization and doing additional testing. It should be finished by 2023-03-20. Next Day: Next day I will be working on the #5931 task. Start on the "A drop-down that allows changing the execution mode" task. |
…r/Lazy_Table_Visualisation_UI_Integration_5002 # Conflicts: # CHANGELOG.md
Michael Mauderer reports a new STANDUP for today (2023-03-20): Progress: Finished the bug fixes and cleanup on the Lazy Table PR. Will now go James for testing. Starting on "A drop-down that allows changing the execution mode". It should be finished by 2023-03-20. Next Day: Next day I will be working on the #5931 task. Continue work on setting up all the entities for a demo scene with the new dropdown menu. |
QA Report 🔴Unfortunately, I found some issues. When opening lazy vis, it does not display most of the entriesIt only displays a field of a single entry, and you need to scroll for a while to allow the rest of the entries to load. This does not happen when you reload the project, though – so if the lazy vis was open, it displays a full list after it's loaded. The way to reproduce it is to switch between the lazy vis and the legacy table. 2023-04-04.17-56-51.mp4Scrolling feels more laggy than legacy visIt takes a while to load new entries when I scroll. 2023-04-04.17-54-48.mp4For comparison, legacy vis works more smoothly: 2023-04-04.17-55-52.mp4Scrolling with two fingers on the touchpad does not workOnly dragging the scrollbar works. I can't see any scrollbars in full-screen mode, so it's impossible to scroll fullscreen vis without a scroll wheel. When opening the full-screen vis, part of the entries is not displayed2023-04-04.18-00-43.mp4In full-screen vis, nodes are scrolled when you scrollMost definitely not the issue of this particular PR. It requires clicking on the visualization before scrolling to trigger this behavior. |
@MichaelMauderer what's the status on this PR and what's the holdup? |
It's not currently scheduled to be worked on due to other tasks being prioritized. Once it gets picked up again, it will need to be updated to develop and QA feedback needs to be addressed. |
Obsolete now, closing. |
Pull Request Description
Adds a new table visualization that is lazily retrieving data from the engine. Closes #5002.
Peek.2023-03-03.14-08.mp4
Important Notes
Checklist
Please include the following checklist in your PR:
Scala,
Java,
and
Rust
style guides.
./run ide build
and./run ide watch
.