<commit_before>use orbtk::{
    prelude::*,
    shell::Key,
    widgets::themes::theme_orbtk::{colors, material_icons_font},
};

// constants
pub static ID_RECEIVER: &str = "receiver";
pub static ID_RECEIVER_STRING: &str = "Receiver Widget";
pub static ID_RECEIVER_CONTAINER: &str = "reciever_container";
pub static ID_RECEIVER_CONTAINER_MESSAGES: &str = "reciever_container_messages";
pub static ID_RECEIVER_CONTAINER_WIDGET: &str = "reciever_container_widget";
pub static ID_RECEIVER_COUNTER: &str = "receiver_message_counter";
pub static ID_RECEIVER_GRID: &str = "receiver_grid";
pub static ID_RECEIVER_HEADER: &str = "receiver_header";
pub static ID_RECEIVER_PROGRESS_BAR: &str = "receiver_progress_bar";
pub static ID_RECEIVER_TEXT_BLOCK: &str = "receiver_text_block";
pub static ID_RECEIVER_LABEL_COUNTER: &str = "receiver_label_message";
pub static ID_RECEIVER_LABEL_MESSAGE: &str = "receiver_label_message";
pub static ID_RECEIVER_MESSAGE_BLOCK: &str = "receiver_message_block";
pub static ID_RECEIVER_MESSAGE_COUNTER: &str = "receiver_message_counter";
pub static ID_RECEIVER_STACK_COUNTER: &str = "reciever_stack_counter";
pub static ID_RECEIVER_STACK_MESSAGE: &str = "reciever_stack_message";

pub static ID_SENDER: &str = "sender";
pub static ID_SENDER_STRING: &str = "Sender Widget";
pub static ID_SENDER_ACTION_BUTTON_SEND: &str = "sender_action_button_send";
pub static ID_SENDER_ACTION_BUTTON_CLEAR: &str = "sender_action_button_clear";
pub static ID_SENDER_CONTAINER: &str = "sender_container";
pub static ID_SENDER_CONTAINER_ACTION: &str = "sender_container_action";
pub static ID_SENDER_CONTAINER_WIDGET: &str = "sender_container_widget";
pub static ID_SENDER_COUNTER: &str = "sender_message_counter";
pub static ID_SENDER_GRID: &str = "sender_grid";
pub static ID_SENDER_HEADER: &str = "sender_header";
pub static ID_SENDER_STACK: &str = "sender_stack";
pub static ID_SENDER_STACK_ACTION: &str = "sender_stack_action";
pub static ID_SENDER_STACK_COUNTER: &str = "sender_stack_counter";
pub static ID_SENDER_LABEL_COUNTER: &str = "sender_label_message";
pub static ID_SENDER_MESSAGE: &str = "sender_message";
pub static ID_SENDER_TEXT_BOX: &str = "sender_text_box";

// [ReceiverView]

widget!(
    /// The receiver view is a form to present messages.
    ///
    /// The messages are send from the sender view, where
    /// the ReceiverView entity is the message_target.
    ///
    /// See also: [`message_target`](struct@SenderState)
    ReceiverView<ReceiverState> {
        /// Counter of received messages.
        counter_text: String,
        /// The Entity of the widget that will receive the messages.
        message_target: u32,
        /// The amount that will be incremented inside the targeted ProgressBar.
        progross_step: f64
    }
);

impl Template for ReceiverView {
    fn template(self, id: Entity, build_context: &mut BuildContext) -> Self {
        let receiver_header = TextBlock::new()
            .id(ID_RECEIVER_HEADER)
            .font_size(24)
            .text(ID_RECEIVER_STRING)
            .build(build_context);

        let receiver_progress_bar = ProgressBar::new()
            .id(ID_RECEIVER_PROGRESS_BAR)
            .build(build_context);

        let receiver_stack_counter = Container::new()
            .child(
                Stack::new()
                    .id(ID_RECEIVER_STACK_COUNTER)
                    .name(ID_RECEIVER_STACK_COUNTER)
                    .orientation("horizontal")
                    .spacing(5)
                    .h_align("end")
                    .child(
                        TextBlock::new()
                            .name(ID_RECEIVER_LABEL_COUNTER)
                            .text("Messages received:")
                            .build(build_context),
                    )
                    .child(
                        TextBlock::new()
                            .id(ID_RECEIVER_COUNTER)
                            .name(ID_RECEIVER_COUNTER)
                            .text(("counter_text", id))
                            .build(build_context),
                    )
                    .build(build_context),
            )
            .build(build_context);

        let receiver_container_msg = Container::new()
            .id(ID_RECEIVER_CONTAINER_MESSAGES)
            .child(
                Stack::new()
                    .id(ID_RECEIVER_STACK_MESSAGE)
                    .name(ID_RECEIVER_STACK_MESSAGE)
                    .orientation("horizontal")
                    .spacing(4)
                    .child(
                        TextBlock::new()
                            .id(ID_RECEIVER_LABEL_MESSAGE)
                            .name(ID_RECEIVER_LABEL_MESSAGE)
                            .text("Message:")
                            .build(build_context),
                    )
                    .child(
                        TextBlock::new()
                            .id(ID_RECEIVER_MESSAGE_BLOCK)
                            .name(ID_RECEIVER_MESSAGE_BLOCK)
                            .water_mark("Awaiting first message.")
                            .text("")
                            .build(build_context),
                    )
                    .build(build_context),
            )
            .build(build_context);

        self.id(ID_RECEIVER)
            .name(ID_RECEIVER_STRING)
            .counter_text("0")
            .child(
                Container::new()
                    .id(ID_RECEIVER_CONTAINER)
                    .padding(18)
                    .child(
                        Container::new()
                            .id(ID_RECEIVER_CONTAINER_WIDGET)
                            .border_brush(colors::BOMBAY_COLOR)
                            .border_width(2)
                            .padding(18)
                            .child(
                                Stack::new()
                                    .spacing(8)
                                    .child(receiver_header)
                                    .child(receiver_progress_bar)
                                    .child(receiver_stack_counter)
                                    .child(receiver_container_msg)
                                    .build(build_context),
                            )
                            .build(build_context),
                    )
                    .build(build_context),
            )
    }
}

// [ReceiverState]

/// The receiver state structure.
#[derive(Default, AsAny)]
struct ReceiverState {
    /// Entity id of the progress bar.
    progress_bar: Entity,
    /// The message counter.
    message_counter: i32,
    /// Entity id of the reveived message.
    message_block: Entity,
}

impl State for ReceiverState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.progress_bar = ctx
            .entity_of_child(ID_RECEIVER_PROGRESS_BAR)
            .expect("Cannot find 'ID_RECEIVER_PROGRESS_BAR'!");
        self.message_block = ctx
            .entity_of_child(ID_RECEIVER_MESSAGE_BLOCK)
            .expect("Cannot find 'ID_RECEIVER_MESSAGE_BLOCK'!");
    }

    fn messages(
        &mut self,
        mut messages: MessageReader,
        _registry: &mut Registry,
        ctx: &mut Context,
    ) {
        // Evaluate the messages we got from foreign state via `SenderAction`
        for message in messages.read::<SenderAction>() {
            match message {
                SenderAction::ClearMessage => {
                    TextBox::text_mut(&mut ctx.child(ID_RECEIVER_MESSAGE_BLOCK)).clear();
                }
                SenderAction::UpdateProgress(amount) => {
                    let progress_bar = ctx.get_widget(self.progress_bar);
                    let current_progress = progress_bar.clone::<f64>("val");
                    ProgressBar::val_set(
                        &mut ctx.child(ID_RECEIVER_PROGRESS_BAR),
                        current_progress + amount,
                    );
                    println!(
                        "Receiver message: Updating progress bar ({} percent)",
                        &current_progress + &amount
                    );

                    self.message_counter += 1;
                    println!(
                        "Receiver message: Updating received message counter ({} messages)",
                        &self.message_counter
                    );
                    TextBlock::text_set(
                        &mut ctx.child(ID_RECEIVER_COUNTER),
                        self.message_counter.to_string(),
                    );
                }
                SenderAction::UpdateMessage(text) => {
                    TextBlock::text_set(&mut ctx.child(ID_RECEIVER_MESSAGE_BLOCK), text);
                }
                _catch_all => {
                    println!("ReceiverView: message ignored!");
                }
            }
        }
    }
}

// [SenderView]

widget!(
    /// The sender view is a form capturing messages.
    SenderView<SenderState> {
        /// Counter of sended messages.
        counter_text: String,
        /// The Entity of the widget that will receive the messages.
        message_target: u32,
        /// The amount that will be incremented inside the targeted ProgressBar.
        progross_step: f64
    }
);

impl Template for SenderView {
    fn template(self, id: Entity, build_context: &mut BuildContext) -> Self {
        let sender_header = TextBlock::new()
            .id(ID_SENDER_HEADER)
            .font_size(24)
            .text(ID_SENDER_STRING)
            .build(build_context);

        let sender_message = TextBox::new()
            .id(ID_SENDER_TEXT_BOX)
            .name(ID_SENDER_TEXT_BOX)
            .text("")
            .water_mark("Please capture your message ...")
            .on_key_down(move |states, key_event| {
                if key_event.key == Key::Enter {
                    println!("KeyHandler: send action");
                    states.send_message(SenderAction::IncrementMessage, id);
                    states.send_message(
                        SenderAction::UpdateMessage("Default message!".to_string()),
                        id,
                    );
                    states.send_message(SenderAction::UpdateProgress(0.1), id);
                };
                true
            })
            // TODO: combined key handling (eg: Ctrl+s )
            .build(build_context);

        let sender_stack_counter = Stack::new()
            .id(ID_SENDER_STACK_COUNTER)
            .name(ID_SENDER_STACK_COUNTER)
            .orientation("horizontal")
            .spacing(5)
            .h_align("end")
            .child(
                TextBlock::new()
                    .name(ID_SENDER_LABEL_COUNTER)
                    .text("Messages send:")
                    .build(build_context),
            )
            .child(
                TextBlock::new()
                    .id(ID_SENDER_COUNTER)
                    .name(ID_SENDER_COUNTER)
                    .text(("counter_text", id))
                    .build(build_context),
            )
            .build(build_context);

        let sender_container_action = Container::new()
            .id(ID_SENDER_CONTAINER_ACTION)
            .h_align("center")
            .child(
                Stack::new()
                    .id(ID_SENDER_STACK_ACTION)
                    .orientation("horizontal")
                    .spacing(25)
                    .child(
                        Button::new()
                            .name(ID_SENDER_ACTION_BUTTON_CLEAR)
                            .font_size(8)
                            .text("Clear")
                            .icon(material_icons_font::MD_CLEAR)
                            .on_click(move |states, _entity| -> bool {
                                states.send_message(SenderAction::ClearMessage, id);
                                true
                            })
                            .build(build_context),
                    )
                    .child(
                        Button::new()
                            .name(ID_SENDER_ACTION_BUTTON_SEND)
                            .font_size(8)
                            .text("Send")
                            .icon(material_icons_font::MD_SEND)
                            .on_click(move |states, _entity| -> bool {
                                states.send_message(SenderAction::IncrementMessage, id);
                                states.send_message(
                                    SenderAction::UpdateMessage("Default message!".to_string()),
                                    id,
                                );
                                states.send_message(SenderAction::UpdateProgress(0.1), id);
                                true
                            })
                            .build(build_context),
                    )
                    .build(build_context),
            )
            .build(build_context);

        self.id(ID_SENDER).name(ID_SENDER).counter_text("0").child(
            Container::new()
                .id(ID_SENDER_CONTAINER)
                .padding(18)
                .child(
                    Container::new()
                        .id(ID_SENDER_CONTAINER_WIDGET)
                        .border_brush(colors::BOMBAY_COLOR)
                        .border_width(2)
                        .padding(14)
                        .child(
                            Stack::new()
                                .spacing(8)
                                .child(sender_header)
                                .child(sender_message)
                                .child(sender_stack_counter)
                                .child(sender_container_action)
                                .build(build_context),
                        )
                        .build(build_context),
                )
                .build(build_context),
        )
    }
}

// [SenderState]

/// Valid actions handled via [SenderState] messages
enum SenderAction {
    /// Clear the message TextBox.
    ClearMessage,
    /// Increment the message counter.
    IncrementMessage,
    /// The amount, that will be incremented inside a ProgressBar.
    UpdateProgress(f64),
    /// Update the target TextBlock with given message.
    UpdateMessage(String),
}

/// The sender state structure.
#[derive(Default, AsAny)]
struct SenderState {
    /// The message counter.
    message_counter: i32,
    /// Entity id of the message target.
    message_target: Entity,
}

impl State for SenderState {
    fn init(&mut self, _registry: &mut Registry, ctx: &mut Context) {
        self.message_target =
            Entity::from(ctx.widget().try_clone::<u32>("message_target").expect(
                "ERROR: SenderState::init(): expected message target entity id not found!",
            ));
    }

    fn messages(
        &mut self,
        mut messages: MessageReader,
        _registry: &mut Registry,
        ctx: &mut Context,
    ) {
        // Evaluate our own state messages
        for message in messages.read::<SenderAction>() {
            match message {
                SenderAction::ClearMessage => {
                    println!("Sender message: ClearMessage");
                    TextBox::text_mut(&mut ctx.child(ID_SENDER_TEXT_BOX)).clear();
                }
                SenderAction::IncrementMessage => {
                    println!("Sender message: increment message_counter");
                    self.message_counter += 1;
                    TextBlock::text_set(
                        &mut ctx.child(ID_SENDER_COUNTER),
                        self.message_counter.to_string(),
                    );
                    //SenderView::counter_text_set(&mut ctx.widget(), self.message_counter.to_string());
                }
                SenderAction::UpdateProgress(amount) => {
                    ctx.send_message(SenderAction::UpdateProgress(amount), self.message_target);
                    println!(
                        "Sender message: increment target ProgressBar ({} percent)",
                        amount
                    );
                }
                SenderAction::UpdateMessage(message) => {
                    // get text value from SenderView propery ID_SENDER_TEXT_BOX
                    let childs_message = ctx
                        .child(ID_SENDER_TEXT_BOX)
                        .get::<String>("text")
                        .to_string();
                    if childs_message.chars().count() > 0 {
                        println!("Sender message: {:?}", childs_message);
                        ctx.send_message(
                            SenderAction::UpdateMessage(childs_message),
                            self.message_target,
                        );
                    } else {
                        println!("Sender message: {:?}", message);
                        ctx.send_message(SenderAction::UpdateMessage(message), self.message_target);
                    }
                }
            }
        }
    }
}

/// The message handler window.
///
/// This OrbTK example application presents two views:
/// * The [SenderView]: The user will capture a message string. When
///   triggering the send button that message will be send to a target
///   entity, the ReceiverView. Every time a message is send,
///   SenderView will increment a counter to keep track of the amount
///   of sended messages. Beside the message string, a given progress
///   value will be transmitted as well (percent value).
/// * The [ReceiverView]: If a message is triggerd, the view will
///   presents a message area. A ProgressBar renders the received
///   stepping value.
pub fn main() {
    Application::from_name("orbtk_msg_handler");
    Application::new()
        .window(|ctx| {
            let receiver = ReceiverView::new().build(ctx);

            let sender = SenderView::new()
                // the entity of the target (receiver)
                .message_target(receiver.0)
                .build(ctx);

            Window::new()
                .title("OrbTK - Message Handler")
                .position((100.0, 100.0))
                .resizeable(true)
                .size(450.0, 400.0)
                .child(
                    Stack::new()
                        .orientation("vertical")
                        .child(sender)
                        .child(receiver)
                        .build(ctx),
                )
                .build(ctx)
        })
        .run();
}
<commit_msg>orbtk: update msg_handler example<commit_after>use orbtk::{
    prelude::*,
    shell::Key,
    widgets::themes::theme_orbtk::{colors, material_icons_font},
};

// constants
pub static ID_RECEIVER: &str = "receiver";
pub static ID_RECEIVER_STRING: &str = "Receiver Widget";
pub static ID_RECEIVER_CONTAINER: &str = "reciever_container";
pub static ID_RECEIVER_CONTAINER_MESSAGES: &str = "reciever_container_messages";
pub static ID_RECEIVER_CONTAINER_WIDGET: &str = "reciever_container_widget";
pub static ID_RECEIVER_COUNTER: &str = "receiver_message_counter";
pub static ID_RECEIVER_GRID: &str = "receiver_grid";
pub static ID_RECEIVER_HEADER: &str = "receiver_header";
pub static ID_RECEIVER_PROGRESS_BAR: &str = "receiver_progress_bar";
pub static ID_RECEIVER_TEXT_BLOCK: &str = "receiver_text_block";
pub static ID_RECEIVER_LABEL_COUNTER: &str = "receiver_label_message";
pub static ID_RECEIVER_LABEL_MESSAGE: &str = "receiver_label_message";
pub static ID_RECEIVER_MESSAGE_BLOCK: &str = "receiver_message_block";
pub static ID_RECEIVER_MESSAGE_COUNTER: &str = "receiver_message_counter";
pub static ID_RECEIVER_STACK_COUNTER: &str = "reciever_stack_counter";
pub static ID_RECEIVER_STACK_MESSAGE: &str = "reciever_stack_message";

pub static ID_SENDER: &str = "sender";
pub static ID_SENDER_STRING: &str = "Sender Widget";
pub static ID_SENDER_ACTION_BUTTON_SEND: &str = "sender_action_button_send";
pub static ID_SENDER_ACTION_BUTTON_CLEAR: &str = "sender_action_button_clear";
pub static ID_SENDER_CONTAINER: &str = "sender_container";
pub static ID_SENDER_CONTAINER_ACTION: &str = "sender_container_action";
pub static ID_SENDER_CONTAINER_WIDGET: &str = "sender_container_widget";
pub static ID_SENDER_COUNTER: &str = "sender_message_counter";
pub static ID_SENDER_GRID: &str = "sender_grid";
pub static ID_SENDER_HEADER: &str = "sender_header";
pub static ID_SENDER_STACK: &str = "sender_stack";
pub static ID_SENDER_STACK_ACTION: &str = "sender_stack_action";
pub static ID_SENDER_STACK_COUNTER: &str = "sender_stack_counter";
pub static ID_SENDER_LABEL_COUNTER: &str = "sender_label_message";
pub static ID_SENDER_MESSAGE: &str = "sender_message";
pub static ID_SENDER_TEXT_BOX: &str = "sender_text_box";

// [ReceiverView]

widget!(
    /// The receiver view is a form to present messages.
    ///
    /// The messages are send from the sender view, where
    /// the ReceiverView entity is the message_target.
    ///
    /// See also: [`message_target`](struct@SenderState)
    ReceiverView<ReceiverState> {
        /// Counter of received messages.
        counter_text: String,
        /// The Entity of the widget that will receive the messages.
        message_target: u32,
        /// The amount that will be incremented inside the targeted ProgressBar.
        progross_step: f64
    }
);

impl Template for ReceiverView {
    fn template(self, id: Entity, build_context: &mut BuildContext) -> Self {
        let receiver_header = TextBlock::new()
            .id(ID_RECEIVER_HEADER)
            .font_size(24)
            .text(ID_RECEIVER_STRING)
            .build(build_context);

        let receiver_progress_bar = ProgressBar::new()
            .id(ID_RECEIVER_PROGRESS_BAR)
            .build(build_context);

        let receiver_stack_counter = Container::new()
            .child(
                Stack::new()
                    .id(ID_RECEIVER_STACK_COUNTER)
                    .name(ID_RECEIVER_STACK_COUNTER)
                    .orientation("horizontal")
                    .spacing(5)
                    .h_align("end")
                    .child(
                        TextBlock::new()
                            .name(ID_RECEIVER_LABEL_COUNTER)
                            .text("Messages received:")
                            .build(build_context),
                    )
                    .child(
                        TextBlock::new()
                            .id(ID_RECEIVER_COUNTER)
                            .name(ID_RECEIVER_COUNTER)
                            .text(("counter_text", id))
                            .build(build_context),
                    )
                    .build(build_context),
            )
            .build(build_context);

        let receiver_container_msg = Container::new()
            .id(ID_RECEIVER_CONTAINER_MESSAGES)
            .child(
                Stack::new()
                    .id(ID_RECEIVER_STACK_MESSAGE)
                    .name(ID_RECEIVER_STACK_MESSAGE)
                    .orientation("horizontal")
                    .spacing(4)
                    .child(
                        TextBlock::new()
                            .id(ID_RECEIVER_LABEL_MESSAGE)
                            .name(ID_RECEIVER_LABEL_MESSAGE)
                            .text("Message:")
                            .build(build_context),
                    )
                    .child(
                        TextBlock::new()
                            .id(ID_RECEIVER_MESSAGE_BLOCK)
                            .name(ID_RECEIVER_MESSAGE_BLOCK)
                            .water_mark("Awaiting first message.")
                            .text("")
                            .build(build_context),
                    )
                    .build(build_context),
            )
            .build(build_context);

        self.id(ID_RECEIVER)
            .name(ID_RECEIVER_STRING)
            .counter_text("0")
            .child(
                Container::new()
                    .id(ID_RECEIVER_CONTAINER)
                    .padding(18)
                    .child(
                        Container::new()
                            .id(ID_RECEIVER_CONTAINER_WIDGET)
                            .border_brush(colors::BOMBAY_COLOR)
                            .border_width(2)
                            .padding(18)
                            .child(
                                Stack::new()
                                    .spacing(8)
                                    .child(receiver_header)
                                    .child(receiver_progress_bar)
                                    .child(receiver_stack_counter)
                                    .child(receiver_container_msg)
                                    .build(build_context),
                            )
                            .build(build_context),
                    )
                    .build(build_context),
            )
    }
}

// [ReceiverState]

/// The receiver state structure.
#[derive(Default, AsAny)]
struct ReceiverState {
    /// Entity id of the progress bar.
    progress_bar: Entity,
    /// The message counter.
    message_counter: i32,
    /// Entity id of the reveived message.
    message_block: Entity,
}

impl State for ReceiverState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.progress_bar = ctx
            .entity_of_child(ID_RECEIVER_PROGRESS_BAR)
            .expect("Cannot find 'ID_RECEIVER_PROGRESS_BAR'!");
        self.message_block = ctx
            .entity_of_child(ID_RECEIVER_MESSAGE_BLOCK)
            .expect("Cannot find 'ID_RECEIVER_MESSAGE_BLOCK'!");
    }

    fn messages(
        &mut self,
        mut messages: MessageReader,
        _registry: &mut Registry,
        ctx: &mut Context,
    ) {
        // Evaluate the messages we got from foreign state via `SenderAction`
        for message in messages.read::<SenderAction>() {
            match message {
                SenderAction::ClearMessage => {
                    TextBox::text_mut(&mut ctx.child(ID_RECEIVER_MESSAGE_BLOCK)).clear();
                }
                SenderAction::UpdateProgress(amount) => {
                    let progress_bar = ctx.get_widget(self.progress_bar);
                    let current_progress = progress_bar.clone::<f64>("val");
                    ProgressBar::val_set(
                        &mut ctx.child(ID_RECEIVER_PROGRESS_BAR),
                        current_progress + amount,
                    );
                    println!(
                        "Receiver message: Updating progress bar ({} percent)",
                        current_progress + amount
                    );

                    self.message_counter += 1;
                    println!(
                        "Receiver message: Updating received message counter ({} messages)",
                        &self.message_counter
                    );
                    TextBlock::text_set(
                        &mut ctx.child(ID_RECEIVER_COUNTER),
                        self.message_counter.to_string(),
                    );
                }
                SenderAction::UpdateMessage(text) => {
                    TextBlock::text_set(&mut ctx.child(ID_RECEIVER_MESSAGE_BLOCK), text);
                }
                _catch_all => {
                    println!("ReceiverView: message ignored!");
                }
            }
        }
    }
}

// [SenderView]

widget!(
    /// The sender view is a form capturing messages.
    SenderView<SenderState> {
        /// Counter of sended messages.
        counter_text: String,
        /// The Entity of the widget that will receive the messages.
        message_target: u32,
        /// The amount that will be incremented inside the targeted ProgressBar.
        progross_step: f64
    }
);

impl Template for SenderView {
    fn template(self, id: Entity, build_context: &mut BuildContext) -> Self {
        let sender_header = TextBlock::new()
            .id(ID_SENDER_HEADER)
            .font_size(24)
            .text(ID_SENDER_STRING)
            .build(build_context);

        let sender_message = TextBox::new()
            .id(ID_SENDER_TEXT_BOX)
            .name(ID_SENDER_TEXT_BOX)
            .text("")
            .water_mark("Please capture your message ...")
            .on_key_down(move |states, key_event| {
                if key_event.key == Key::Enter {
                    println!("KeyHandler: send action");
                    states.send_message(SenderAction::IncrementMessage, id);
                    states.send_message(
                        SenderAction::UpdateMessage("Default message!".to_string()),
                        id,
                    );
                    states.send_message(SenderAction::UpdateProgress(0.1), id);
                };
                true
            })
            // TODO: combined key handling (eg: Ctrl+s )
            .build(build_context);

        let sender_stack_counter = Stack::new()
            .id(ID_SENDER_STACK_COUNTER)
            .name(ID_SENDER_STACK_COUNTER)
            .orientation("horizontal")
            .spacing(5)
            .h_align("end")
            .child(
                TextBlock::new()
                    .name(ID_SENDER_LABEL_COUNTER)
                    .text("Messages send:")
                    .build(build_context),
            )
            .child(
                TextBlock::new()
                    .id(ID_SENDER_COUNTER)
                    .name(ID_SENDER_COUNTER)
                    .text(("counter_text", id))
                    .build(build_context),
            )
            .build(build_context);

        let sender_container_action = Container::new()
            .id(ID_SENDER_CONTAINER_ACTION)
            .h_align("center")
            .child(
                Stack::new()
                    .id(ID_SENDER_STACK_ACTION)
                    .orientation("horizontal")
                    .spacing(25)
                    .child(
                        Button::new()
                            .name(ID_SENDER_ACTION_BUTTON_CLEAR)
                            .font_size(8)
                            .text("Clear")
                            .icon(material_icons_font::MD_CLEAR)
                            .on_click(move |states, _entity| -> bool {
                                states.send_message(SenderAction::ClearMessage, id);
                                true
                            })
                            .build(build_context),
                    )
                    .child(
                        Button::new()
                            .name(ID_SENDER_ACTION_BUTTON_SEND)
                            .font_size(8)
                            .text("Send")
                            .icon(material_icons_font::MD_SEND)
                            .on_click(move |states, _entity| -> bool {
                                states.send_message(SenderAction::IncrementMessage, id);
                                states.send_message(
                                    SenderAction::UpdateMessage("Default message!".to_string()),
                                    id,
                                );
                                states.send_message(SenderAction::UpdateProgress(0.1), id);
                                true
                            })
                            .build(build_context),
                    )
                    .build(build_context),
            )
            .build(build_context);

        self.id(ID_SENDER).name(ID_SENDER).counter_text("0").child(
            Container::new()
                .id(ID_SENDER_CONTAINER)
                .padding(18)
                .child(
                    Container::new()
                        .id(ID_SENDER_CONTAINER_WIDGET)
                        .border_brush(colors::BOMBAY_COLOR)
                        .border_width(2)
                        .padding(14)
                        .child(
                            Stack::new()
                                .spacing(8)
                                .child(sender_header)
                                .child(sender_message)
                                .child(sender_stack_counter)
                                .child(sender_container_action)
                                .build(build_context),
                        )
                        .build(build_context),
                )
                .build(build_context),
        )
    }
}

// [SenderState]

/// Valid actions handled via [SenderState] messages
enum SenderAction {
    /// Clear the message TextBox.
    ClearMessage,
    /// Increment the message counter.
    IncrementMessage,
    /// The amount, that will be incremented inside a ProgressBar.
    UpdateProgress(f64),
    /// Update the target TextBlock with given message.
    UpdateMessage(String),
}

/// The sender state structure.
#[derive(Default, AsAny)]
struct SenderState {
    /// The message counter.
    message_counter: i32,
    /// Entity id of the message target.
    message_target: Entity,
}

impl State for SenderState {
    fn init(&mut self, _registry: &mut Registry, ctx: &mut Context) {
        self.message_target =
            Entity::from(ctx.widget().try_clone::<u32>("message_target").expect(
                "ERROR: SenderState::init(): expected message target entity id not found!",
            ));
    }

    fn messages(
        &mut self,
        mut messages: MessageReader,
        _registry: &mut Registry,
        ctx: &mut Context,
    ) {
        // Evaluate our own state messages
        for message in messages.read::<SenderAction>() {
            match message {
                SenderAction::ClearMessage => {
                    println!("Sender message: ClearMessage");
                    TextBox::text_mut(&mut ctx.child(ID_SENDER_TEXT_BOX)).clear();
                }
                SenderAction::IncrementMessage => {
                    println!("Sender message: increment message_counter");
                    self.message_counter += 1;
                    TextBlock::text_set(
                        &mut ctx.child(ID_SENDER_COUNTER),
                        self.message_counter.to_string(),
                    );
                    //SenderView::counter_text_set(&mut ctx.widget(), self.message_counter.to_string());
                }
                SenderAction::UpdateProgress(amount) => {
                    ctx.send_message(SenderAction::UpdateProgress(amount), self.message_target);
                    println!(
                        "Sender message: increment target ProgressBar ({} percent)",
                        amount
                    );
                }
                SenderAction::UpdateMessage(message) => {
                    // get text value from SenderView propery ID_SENDER_TEXT_BOX
                    let childs_message = ctx
                        .child(ID_SENDER_TEXT_BOX)
                        .get::<String>("text")
                        .to_string();
                    if childs_message.chars().count() > 0 {
                        println!("Sender message: {:?}", childs_message);
                        ctx.send_message(
                            SenderAction::UpdateMessage(childs_message),
                            self.message_target,
                        );
                    } else {
                        println!("Sender message: {:?}", message);
                        ctx.send_message(SenderAction::UpdateMessage(message), self.message_target);
                    }
                }
            }
        }
    }
}

/// The message handler window.
///
/// This OrbTK example application presents two views:
/// * The [SenderView]: The user will capture a message string. When
///   triggering the send button that message will be send to a target
///   entity, the ReceiverView. Every time a message is send,
///   SenderView will increment a counter to keep track of the amount
///   of sended messages. Beside the message string, a given progress
///   value will be transmitted as well (percent value).
/// * The [ReceiverView]: If a message is triggerd, the view will
///   presents a message area. A ProgressBar renders the received
///   stepping value.
pub fn main() {
    Application::from_name("orbtk_msg_handler");
    Application::new()
        .window(|ctx| {
            let receiver = ReceiverView::new().build(ctx);

            let sender = SenderView::new()
                // the entity of the target (receiver)
                .message_target(receiver.0)
                .build(ctx);

            Window::new()
                .title("OrbTK - Message Handler")
                .position((100.0, 100.0))
                .resizeable(true)
                .size(450.0, 400.0)
                .child(
                    Stack::new()
                        .orientation("vertical")
                        .child(sender)
                        .child(receiver)
                        .build(ctx),
                )
                .build(ctx)
        })
        .run();
}
<|endoftext|>


<commit_before>use core::ops::{Add, Index};
use core::ptr;

use common::{debug, memory};
use common::vec::Vec;

/// A trait for types that can be converted to `String`
pub trait ToString {
    /// Convert the type to strings
    fn to_string(&self) -> String;
}

impl ToString for &'static str {
    /// Convert the type to `String`
    fn to_string(&self) -> String {
        String::from_str(self)
    }
}

/// An iterator over unicode characters
pub struct Chars<'a> {
    /// The string iterating over
    string: &'a String,
    /// The offset of the iterator
    offset: usize,
}

impl <'a> Iterator for Chars<'a> {
    type Item = char;

    fn next(&mut self) -> Option<Self::Item> {
        if self.offset < self.string.len() {
            let ret = Some(self.string[self.offset]);
            self.offset += 1;
            ret
        } else {
            None
        }
    }
}

/// A split
pub struct Split<'a> {
    /// The string being split
    string: &'a String,
    /// The offset of the split
    offset: usize,
    /// The string seperator
    seperator: String,
}

impl <'a> Iterator for Split<'a> {
    type Item = String;
    fn next(&mut self) -> Option<Self::Item> {
        if self.offset < self.string.len() {
            let start = self.offset;
            let mut len = 0;
            for i in start..self.string.len() {
                if self.seperator == self.string.substr(i, self.seperator.len()) {
                    self.offset += self.seperator.len();
                    break;
                } else {
                    self.offset += 1;
                    len += 1;
                }
            }
            Some(self.string.substr(start, len))
        } else {
            None
        }
    }
}

/// A set of lines
pub struct Lines<'a> {
    /// The underlying split
    split: Split<'a>
}

impl <'a> Iterator for Lines<'a> {
    type Item = String;
    fn next(&mut self) -> Option<Self::Item> {
        match self.split.next() {
            Some(string) => if string.ends_with("\r".to_string()) {
                Some(string.substr(0, string.len() - 1))
            } else {
                Some(string)
            },
            None => None
        }
    }
}

/// A heap allocated, owned string.
pub struct String {
    /// The vector of the chars
    pub vec: Vec<char>,
}

impl String {
    /// Create a new empty `String`
    pub fn new() -> Self {
        String { vec: Vec::new() }
    }

    // TODO FromStr trait
    /// Convert a string literal to a `String`
    pub fn from_str(s: &str) -> Self {
        let mut vec: Vec<char> = Vec::new();

        for c in s.chars() {
            vec.push(c);
        }

        String { vec: vec }
    }

    /// Convert a c-style string slice to a String
    pub fn from_c_slice(s: &[u8]) -> Self {
        let mut vec: Vec<char> = Vec::new();

        for b in s {
            let c = *b as char;
            if c == '\0' {
                break;
            }
            vec.push(c);
        }

        String { vec: vec }
    }

    /// Convert a utf8 vector to a string
    // Why &Vec?
    pub fn from_utf8(utf_vec: &Vec<u8>) -> Self {
        let mut vec: Vec<char> = Vec::new();

        //TODO: better UTF support
        for b in utf_vec.iter() {
            let c = *b as char;
            if c == '\0' {
                break;
            }
            vec.push(c);
        }

        String { vec: vec }
    }

    /// Convert a C-style string literal to a `String`
    pub unsafe fn from_c_str(s: *const u8) -> Self {
        let mut vec: Vec<char> = Vec::new();

        let mut i = 0;
        loop {
            let c = ptr::read(s.offset(i)) as char;
            if c == '\0' {
                break;
            }
            vec.push(c);
            i += 1;
        }

        String { vec: vec }
    }

    /// Convert an integer to a String using a given radix
    pub fn from_num_radix(num: usize, radix: usize) -> Self {
        if radix == 0 {
            return String::new();
        }

        let mut vec: Vec<char> = Vec::new();

        let mut digit_num = num;
        loop {
            let mut digit = (digit_num % radix) as u8;
            if digit > 9 {
                digit += 'A' as u8 - 10;
            } else {
                digit += '0' as u8;
            }

            vec.insert(0, digit as char);

            if digit_num < radix {
                break;
            }

            digit_num /= radix;
        }

        String { vec: vec }
    }

    /// Convert a signed integer to a String
    // TODO: Consider using `int` instead of `num`
    pub fn from_num_radix_signed(num: isize, radix: usize) -> Self {
        if num >= 0 {
            String::from_num_radix(num as usize, radix)
        } else {
            "-".to_string() + String::from_num_radix((-num) as usize, radix)
        }
    }

    /// Convert a `char` to a string
    pub fn from_char(c: char) -> Self {
        if c == '\0' {
            return String::new();
        }

        let mut vec: Vec<char> = Vec::new();
        vec.push(c);

        String { vec: vec }
    }

    /// Convert an unsigned integer to a `String` in base 10
    pub fn from_num(num: usize) -> Self {
        String::from_num_radix(num, 10)
    }

    /// Convert a signed int to a `String` in base 10
    pub fn from_num_signed(num: isize) -> Self {
        String::from_num_radix_signed(num, 10)
    }

    /// Get a substring
    // TODO: Consider to use a string slice
    pub fn substr(&self, start: usize, len: usize) -> Self {
        let mut i = start;
        if i > self.len() {
            i = self.len();
        }

        let mut j = i + len;
        if j > self.len() {
            j = self.len();
        }

        let mut vec: Vec<char> = Vec::new();

        for k in i..j {
            vec.push(self[k]);
        }

        String { vec: vec }
    }

    /// Find the index of a substring in a string
    pub fn find(&self, other: Self) -> Option<usize> {
        if self.len() >= other.len() {
            for i in 0..self.len() + 1 - other.len() {
                if self.substr(i, other.len()) == other {
                    return Some(i);
                }
            }
        }
        None
    }

    /// Check if the string starts with a given string
    pub fn starts_with(&self, other: Self) -> bool {
        if self.len() >= other.len() {
            // FIXME: This is inefficient
            self.substr(0, other.len()) == other
        } else {
            false
        }
    }

    /// Check if a string ends with another string
    pub fn ends_with(&self, other: Self) -> bool {
        if self.len() >= other.len() {
            // FIXME: Inefficient
            self.substr(self.len() - other.len(), other.len()) == other
        } else {
            false
        }
    }

    /// Get the length of the string
    pub fn len(&self) -> usize {
        self.vec.len()
    }

    /// Get a iterator over the chars of the string
    pub fn chars(&self) -> Chars {
        Chars {
            string: &self,
            offset: 0,
        }
    }

    /// Get a iterator of the splits of the string (by a seperator)
    pub fn split(&self, seperator: Self) -> Split {
        Split {
            string: &self,
            offset: 0,
            seperator: seperator,
        }
    }

    /// Get a iterator of lines from the string
    pub fn lines(&self) -> Lines {
        Lines {
            split: self.split("\n".to_string())
        }
    }

    /// Convert the string to UTF-8
    pub fn to_utf8(&self) -> Vec<u8> {
        let mut vec: Vec<u8> = Vec::new();

        for c in self.chars() {
            let u = c as usize;
            if u < 0x80 {
                vec.push(u as u8);
            } else if u < 0x800 {
                vec.push(0b11000000 | ((u >> 6) as u8 & 0b00011111));
                vec.push(0b10000000 | (u as u8 & 0b00111111));
            } else if u < 0x10000 {
                vec.push(0b11100000 | ((u >> 12) as u8 & 0b00001111));
                vec.push(0b10000000 | ((u >> 6) as u8 & 0b00111111));
                vec.push(0b10000000 | (u as u8 & 0b00111111));
            } else {
                debug::d("Unhandled to_utf8 code ");
                debug::dh(u);
                debug::dl();
                unsafe {
                    debug::dh(self.vec.as_ptr() as usize);
                }
                debug::d(" ");
                debug::dd(self.vec.len());
                debug::d(" to ");
                unsafe {
                    debug::dh(vec.as_ptr() as usize);
                }
                debug::d(" ");
                debug::dd(vec.len());
                debug::dl();
                break;
            }
        }

        vec
    }

    /// Convert the string to a C-style string
    pub unsafe fn to_c_str(&self) -> *const u8 {
        let length = self.len() + 1;

        let data = memory::alloc(length) as *mut u8;

        for i in 0..self.len() {
            ptr::write(data.offset(i as isize), self[i] as u8);
        }
        ptr::write(data.offset(self.len() as isize), 0);

        data
    }

    /// Parse the string to a integer using a given radix
    pub fn to_num_radix(&self, radix: usize) -> usize {
        if radix == 0 {
            return 0;
        }

        let mut num = 0;
        for c in self.chars() {
            let digit;
            if c >= '0' && c <= '9' {
                digit = c as usize - '0' as usize
            } else if c >= 'A' && c <= 'Z' {
                digit = c as usize - 'A' as usize + 10
            } else if c >= 'a' && c <= 'z' {
                digit = c as usize - 'a' as usize + 10
            } else {
                break;
            }

            if digit >= radix {
                break;
            }

            num *= radix;
            num += digit;
        }

        num
    }

    /// Parse the string as a signed integer using a given radix
    pub fn to_num_radix_signed(&self, radix: usize) -> isize {
        if self[0] == '-' {
            -(self.substr(1, self.len() - 1).to_num_radix(radix) as isize)
        } else {
            self.to_num_radix(radix) as isize
        }
    }

    /// Parse it as a unsigned integer in base 10
    pub fn to_num(&self) -> usize {
        self.to_num_radix(10)
    }

    /// Parse it as a signed integer in base 10
    pub fn to_num_signed(&self) -> isize {
        self.to_num_radix_signed(10)
    }

    /// Debug
    pub fn d(&self) {
        for c in self.chars() {
            debug::dc(c);
        }
    }
}

static NULL_CHAR: char = '\0';

impl Index<usize> for String {
    type Output = char;
    fn index<'a>(&'a self, i: usize) -> &'a Self::Output {
        match self.vec.get(i) {
            Some(c) => c,
            None => &NULL_CHAR,
        }
    }
}

impl PartialEq for String {
    fn eq(&self, other: &Self) -> bool {
        if self.len() == other.len() {
            for i in 0..self.len() {
                if self[i] != other[i] {
                    return false;
                }
            }

            true
        } else {
            false
        }
    }
}

impl Clone for String {
    fn clone(&self) -> Self {
        self.substr(0, self.len())
    }
}

impl<'a> Add<&'a String> for String {
    type Output = String;
    fn add(mut self, other: &'a Self) -> Self {
        self.vec.push_all(&other.vec);
        self
    }
}

impl<'a> Add<&'a mut String> for String {
    type Output = String;
    fn add(mut self, other: &'a mut Self) -> Self {
        self.vec.push_all(&other.vec);
        self
    }
}

impl Add for String {
    type Output = String;
    fn add(mut self, other: Self) -> Self {
        self.vec.push_all(&other.vec);
        self
    }
}

impl<'a> Add<&'a str> for String {
    type Output = String;
    fn add(self, other: &'a str) -> Self {
        self + String::from_str(other)
    }
}

impl Add<char> for String {
    type Output = String;
    fn add(mut self, other: char) -> Self {
        self.vec.push(other);
        self
    }
}

impl Add<usize> for String {
    type Output = String;
    fn add(self, other: usize) -> Self {
        self + String::from_num(other)
    }
}

impl Add<isize> for String {
    type Output = String;
    fn add(self, other: isize) -> Self {
        self + String::from_num_signed(other)
    }
}

// Slightly modified version of the impl_eq found in the std collections String
// Ideally, we'd compare these as arrays. However, we'd need to flesh out String a bit more
macro_rules! impl_chars_eq {
    ($lhs:ty, $rhs: ty) => {
        impl<'a> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a == b) }
            #[inline]
            fn ne(&self, other: &$rhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a != b) }
        }

        impl<'a> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a == b) }
            #[inline]
            fn ne(&self, other: &$lhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a != b) }
        }

    }
}

impl_chars_eq! { String, str }
impl_chars_eq! { String, &'a str }
<commit_msg>Fix ne in string compare<commit_after>use core::ops::{Add, Index};
use core::ptr;

use common::{debug, memory};
use common::vec::Vec;

/// A trait for types that can be converted to `String`
pub trait ToString {
    /// Convert the type to strings
    fn to_string(&self) -> String;
}

impl ToString for &'static str {
    /// Convert the type to `String`
    fn to_string(&self) -> String {
        String::from_str(self)
    }
}

/// An iterator over unicode characters
pub struct Chars<'a> {
    /// The string iterating over
    string: &'a String,
    /// The offset of the iterator
    offset: usize,
}

impl <'a> Iterator for Chars<'a> {
    type Item = char;

    fn next(&mut self) -> Option<Self::Item> {
        if self.offset < self.string.len() {
            let ret = Some(self.string[self.offset]);
            self.offset += 1;
            ret
        } else {
            None
        }
    }
}

/// A split
pub struct Split<'a> {
    /// The string being split
    string: &'a String,
    /// The offset of the split
    offset: usize,
    /// The string seperator
    seperator: String,
}

impl <'a> Iterator for Split<'a> {
    type Item = String;
    fn next(&mut self) -> Option<Self::Item> {
        if self.offset < self.string.len() {
            let start = self.offset;
            let mut len = 0;
            for i in start..self.string.len() {
                if self.seperator == self.string.substr(i, self.seperator.len()) {
                    self.offset += self.seperator.len();
                    break;
                } else {
                    self.offset += 1;
                    len += 1;
                }
            }
            Some(self.string.substr(start, len))
        } else {
            None
        }
    }
}

/// A set of lines
pub struct Lines<'a> {
    /// The underlying split
    split: Split<'a>
}

impl <'a> Iterator for Lines<'a> {
    type Item = String;
    fn next(&mut self) -> Option<Self::Item> {
        match self.split.next() {
            Some(string) => if string.ends_with("\r".to_string()) {
                Some(string.substr(0, string.len() - 1))
            } else {
                Some(string)
            },
            None => None
        }
    }
}

/// A heap allocated, owned string.
pub struct String {
    /// The vector of the chars
    pub vec: Vec<char>,
}

impl String {
    /// Create a new empty `String`
    pub fn new() -> Self {
        String { vec: Vec::new() }
    }

    // TODO FromStr trait
    /// Convert a string literal to a `String`
    pub fn from_str(s: &str) -> Self {
        let mut vec: Vec<char> = Vec::new();

        for c in s.chars() {
            vec.push(c);
        }

        String { vec: vec }
    }

    /// Convert a c-style string slice to a String
    pub fn from_c_slice(s: &[u8]) -> Self {
        let mut vec: Vec<char> = Vec::new();

        for b in s {
            let c = *b as char;
            if c == '\0' {
                break;
            }
            vec.push(c);
        }

        String { vec: vec }
    }

    /// Convert a utf8 vector to a string
    // Why &Vec?
    pub fn from_utf8(utf_vec: &Vec<u8>) -> Self {
        let mut vec: Vec<char> = Vec::new();

        //TODO: better UTF support
        for b in utf_vec.iter() {
            let c = *b as char;
            if c == '\0' {
                break;
            }
            vec.push(c);
        }

        String { vec: vec }
    }

    /// Convert a C-style string literal to a `String`
    pub unsafe fn from_c_str(s: *const u8) -> Self {
        let mut vec: Vec<char> = Vec::new();

        let mut i = 0;
        loop {
            let c = ptr::read(s.offset(i)) as char;
            if c == '\0' {
                break;
            }
            vec.push(c);
            i += 1;
        }

        String { vec: vec }
    }

    /// Convert an integer to a String using a given radix
    pub fn from_num_radix(num: usize, radix: usize) -> Self {
        if radix == 0 {
            return String::new();
        }

        let mut vec: Vec<char> = Vec::new();

        let mut digit_num = num;
        loop {
            let mut digit = (digit_num % radix) as u8;
            if digit > 9 {
                digit += 'A' as u8 - 10;
            } else {
                digit += '0' as u8;
            }

            vec.insert(0, digit as char);

            if digit_num < radix {
                break;
            }

            digit_num /= radix;
        }

        String { vec: vec }
    }

    /// Convert a signed integer to a String
    // TODO: Consider using `int` instead of `num`
    pub fn from_num_radix_signed(num: isize, radix: usize) -> Self {
        if num >= 0 {
            String::from_num_radix(num as usize, radix)
        } else {
            "-".to_string() + String::from_num_radix((-num) as usize, radix)
        }
    }

    /// Convert a `char` to a string
    pub fn from_char(c: char) -> Self {
        if c == '\0' {
            return String::new();
        }

        let mut vec: Vec<char> = Vec::new();
        vec.push(c);

        String { vec: vec }
    }

    /// Convert an unsigned integer to a `String` in base 10
    pub fn from_num(num: usize) -> Self {
        String::from_num_radix(num, 10)
    }

    /// Convert a signed int to a `String` in base 10
    pub fn from_num_signed(num: isize) -> Self {
        String::from_num_radix_signed(num, 10)
    }

    /// Get a substring
    // TODO: Consider to use a string slice
    pub fn substr(&self, start: usize, len: usize) -> Self {
        let mut i = start;
        if i > self.len() {
            i = self.len();
        }

        let mut j = i + len;
        if j > self.len() {
            j = self.len();
        }

        let mut vec: Vec<char> = Vec::new();

        for k in i..j {
            vec.push(self[k]);
        }

        String { vec: vec }
    }

    /// Find the index of a substring in a string
    pub fn find(&self, other: Self) -> Option<usize> {
        if self.len() >= other.len() {
            for i in 0..self.len() + 1 - other.len() {
                if self.substr(i, other.len()) == other {
                    return Some(i);
                }
            }
        }
        None
    }

    /// Check if the string starts with a given string
    pub fn starts_with(&self, other: Self) -> bool {
        if self.len() >= other.len() {
            // FIXME: This is inefficient
            self.substr(0, other.len()) == other
        } else {
            false
        }
    }

    /// Check if a string ends with another string
    pub fn ends_with(&self, other: Self) -> bool {
        if self.len() >= other.len() {
            // FIXME: Inefficient
            self.substr(self.len() - other.len(), other.len()) == other
        } else {
            false
        }
    }

    /// Get the length of the string
    pub fn len(&self) -> usize {
        self.vec.len()
    }

    /// Get a iterator over the chars of the string
    pub fn chars(&self) -> Chars {
        Chars {
            string: &self,
            offset: 0,
        }
    }

    /// Get a iterator of the splits of the string (by a seperator)
    pub fn split(&self, seperator: Self) -> Split {
        Split {
            string: &self,
            offset: 0,
            seperator: seperator,
        }
    }

    /// Get a iterator of lines from the string
    pub fn lines(&self) -> Lines {
        Lines {
            split: self.split("\n".to_string())
        }
    }

    /// Convert the string to UTF-8
    pub fn to_utf8(&self) -> Vec<u8> {
        let mut vec: Vec<u8> = Vec::new();

        for c in self.chars() {
            let u = c as usize;
            if u < 0x80 {
                vec.push(u as u8);
            } else if u < 0x800 {
                vec.push(0b11000000 | ((u >> 6) as u8 & 0b00011111));
                vec.push(0b10000000 | (u as u8 & 0b00111111));
            } else if u < 0x10000 {
                vec.push(0b11100000 | ((u >> 12) as u8 & 0b00001111));
                vec.push(0b10000000 | ((u >> 6) as u8 & 0b00111111));
                vec.push(0b10000000 | (u as u8 & 0b00111111));
            } else {
                debug::d("Unhandled to_utf8 code ");
                debug::dh(u);
                debug::dl();
                unsafe {
                    debug::dh(self.vec.as_ptr() as usize);
                }
                debug::d(" ");
                debug::dd(self.vec.len());
                debug::d(" to ");
                unsafe {
                    debug::dh(vec.as_ptr() as usize);
                }
                debug::d(" ");
                debug::dd(vec.len());
                debug::dl();
                break;
            }
        }

        vec
    }

    /// Convert the string to a C-style string
    pub unsafe fn to_c_str(&self) -> *const u8 {
        let length = self.len() + 1;

        let data = memory::alloc(length) as *mut u8;

        for i in 0..self.len() {
            ptr::write(data.offset(i as isize), self[i] as u8);
        }
        ptr::write(data.offset(self.len() as isize), 0);

        data
    }

    /// Parse the string to a integer using a given radix
    pub fn to_num_radix(&self, radix: usize) -> usize {
        if radix == 0 {
            return 0;
        }

        let mut num = 0;
        for c in self.chars() {
            let digit;
            if c >= '0' && c <= '9' {
                digit = c as usize - '0' as usize
            } else if c >= 'A' && c <= 'Z' {
                digit = c as usize - 'A' as usize + 10
            } else if c >= 'a' && c <= 'z' {
                digit = c as usize - 'a' as usize + 10
            } else {
                break;
            }

            if digit >= radix {
                break;
            }

            num *= radix;
            num += digit;
        }

        num
    }

    /// Parse the string as a signed integer using a given radix
    pub fn to_num_radix_signed(&self, radix: usize) -> isize {
        if self[0] == '-' {
            -(self.substr(1, self.len() - 1).to_num_radix(radix) as isize)
        } else {
            self.to_num_radix(radix) as isize
        }
    }

    /// Parse it as a unsigned integer in base 10
    pub fn to_num(&self) -> usize {
        self.to_num_radix(10)
    }

    /// Parse it as a signed integer in base 10
    pub fn to_num_signed(&self) -> isize {
        self.to_num_radix_signed(10)
    }

    /// Debug
    pub fn d(&self) {
        for c in self.chars() {
            debug::dc(c);
        }
    }
}

static NULL_CHAR: char = '\0';

impl Index<usize> for String {
    type Output = char;
    fn index<'a>(&'a self, i: usize) -> &'a Self::Output {
        match self.vec.get(i) {
            Some(c) => c,
            None => &NULL_CHAR,
        }
    }
}

impl PartialEq for String {
    fn eq(&self, other: &Self) -> bool {
        if self.len() == other.len() {
            for i in 0..self.len() {
                if self[i] != other[i] {
                    return false;
                }
            }

            true
        } else {
            false
        }
    }
}

impl Clone for String {
    fn clone(&self) -> Self {
        self.substr(0, self.len())
    }
}

impl<'a> Add<&'a String> for String {
    type Output = String;
    fn add(mut self, other: &'a Self) -> Self {
        self.vec.push_all(&other.vec);
        self
    }
}

impl<'a> Add<&'a mut String> for String {
    type Output = String;
    fn add(mut self, other: &'a mut Self) -> Self {
        self.vec.push_all(&other.vec);
        self
    }
}

impl Add for String {
    type Output = String;
    fn add(mut self, other: Self) -> Self {
        self.vec.push_all(&other.vec);
        self
    }
}

impl<'a> Add<&'a str> for String {
    type Output = String;
    fn add(self, other: &'a str) -> Self {
        self + String::from_str(other)
    }
}

impl Add<char> for String {
    type Output = String;
    fn add(mut self, other: char) -> Self {
        self.vec.push(other);
        self
    }
}

impl Add<usize> for String {
    type Output = String;
    fn add(self, other: usize) -> Self {
        self + String::from_num(other)
    }
}

impl Add<isize> for String {
    type Output = String;
    fn add(self, other: isize) -> Self {
        self + String::from_num_signed(other)
    }
}

// Slightly modified version of the impl_eq found in the std collections String
// Ideally, we'd compare these as arrays. However, we'd need to flesh out String a bit more
macro_rules! impl_chars_eq {
    ($lhs:ty, $rhs: ty) => {
        impl<'a> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a == b) }
            #[inline]
            fn ne(&self, other: &$rhs) -> bool { ! self.chars().zip(other.chars()).all(|(a,b)| a == b) }
        }

        impl<'a> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a == b) }
            #[inline]
            fn ne(&self, other: &$lhs) -> bool { ! self.chars().zip(other.chars()).all(|(a,b)| a == b) }
        }

    }
}

impl_chars_eq! { String, str }
impl_chars_eq! { String, &'a str }
<|endoftext|>


<commit_before>//! Color items, including everything from rgb, hsb/l/v, lap, alpha, luma and more, provided by the
//! palette crate. See [the palette docs](https://docs.rs/palette) for more details or see the
//! [**named**](./named/index.html) module for a set of provided color constants.

pub mod conv;

pub use self::conv::IntoLinSrgba;
pub use self::named::*;
#[doc(inline)]
pub use palette::*;

/// The default scalar value for working with color components, hues, etc.
pub type DefaultScalar = f32;

/// A color represented as red, green and blue intensities.
///
/// This type is an alias for the `Srgb` type, a type that represents the sRGB color space.
///
/// If you are looking for more advanced control over the RGB space and component type, please see
/// the `palette` crate's generic `Rgb` type.
pub type Rgb<S = DefaultScalar> = Srgb<S>;

/// The same as `Rgb`, but with an alpha value representing opacity.
///
/// This type is an alias for the `Srgba` type, a type that represents the sRGB color space
/// alongside an alpha value.
///
/// If you are looking for more advanced control over the RGB space and component type, please see
/// the `palette` crate's generic `Rgb` type.
pub type Rgba<S = DefaultScalar> = Srgba<S>;

/// A color represented as gray intensity.
///
/// This type is an alias for the `Srgb` type, a type that represents the sRGB color space.
///
/// If you are looking for more advanced control over the RGB space and component type, please see
/// the `palette` crate's generic `Rgb` type.
pub type Gray<S = DefaultScalar> = Srgb<S>;

/// A short-hand constructor for `Rgb::new`.
pub fn rgb<T>(r: T, g: T, b: T) -> Rgb<T>
where
    T: Component,
{
    srgb(r, g, b)
}

/// A short-hand constructor for `Rgb<u8>::new`.
pub fn rgb8(r: u8, g: u8, b: u8) -> Rgb<u8> {
    srgb8(r, g, b)
}

/// A short-hand constructor for `Rgba::new`.
pub fn rgba<T>(r: T, g: T, b: T, a: T) -> Rgba<T>
where
    T: Component,
{
    srgba(r, g, b, a)
}

/// A short-hand constructor for `Rgba<u8>::new`.
pub fn rgba8(r: u8, g: u8, b: u8, a: u8) -> Rgba<u8> {
    srgba8(r, g, b, a)
}

/// A short-hand constructor for `Srgb::new`.
pub fn srgb<T>(r: T, g: T, b: T) -> Srgb<T>
where
    T: Component,
{
    Srgb::new(r, g, b)
}

/// A short-hand constructor for `Srgb<u8>::new`.
pub fn srgb8(r: u8, g: u8, b: u8) -> Srgb<u8> {
    Srgb::new(r, g, b)
}

/// A short-hand constructor for `Srgba::new`.
pub fn srgba<T>(r: T, g: T, b: T, a: T) -> Srgba<T>
where
    T: Component,
{
    Srgba::new(r, g, b, a)
}

/// A short-hand constructor for `Srgba<u8>::new`.
pub fn srgba8(r: u8, g: u8, b: u8, a: u8) -> Srgba<u8> {
    Srgba::new(r, g, b, a)
}

/// A short-hand constructor for `LinSrgb::new`.
pub fn lin_srgb<T>(r: T, g: T, b: T) -> LinSrgb<T>
where
    T: Component,
{
    LinSrgb::new(r, g, b)
}

/// A short-hand constructor for `LinSrgba::new`.
pub fn lin_srgba<T>(r: T, g: T, b: T, a: T) -> LinSrgba<T>
where
    T: Component,
{
    LinSrgba::new(r, g, b, a)
}

/// A short-hand constructor for `Hsl::new(RgbHue::from_degrees(h * 360.0), s, l)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsl(h: f32, s: f32, l: f32) -> Hsl {
    Hsl::new(RgbHue::from_degrees(h * 360.0), s, l)
}

/// A short-hand constructor for `Hsla::new(RgbHue::from_degrees(h * 360.0), s, l, a)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla {
    Hsla::new(RgbHue::from_degrees(h * 360.0), s, l, a)
}

/// A short-hand constructor for `Hsv::new(RgbHue::from_degrees(h * 360.0), s, v)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsv(h: f32, s: f32, v: f32) -> Hsv {
    Hsv::new(RgbHue::from_degrees(h * 360.0), s, v)
}

/// A short-hand constructor for `Hsva::new(RgbHue::from_degrees(h * 360.0), s, v, a)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsva(h: f32, s: f32, v: f32, a: f32) -> Hsva {
    Hsva::new(RgbHue::from_degrees(h * 360.0), s, v, a)
}

/// A short-hand constructor for `Gray::new`.
pub fn gray<T>(g: T) -> Gray<T>
where
    T: Component,
{
    srgb(g, g, g)
}
<commit_msg>add rgb_u32 to create color from hex literal<commit_after>//! Color items, including everything from rgb, hsb/l/v, lap, alpha, luma and more, provided by the
//! palette crate. See [the palette docs](https://docs.rs/palette) for more details or see the
//! [**named**](./named/index.html) module for a set of provided color constants.

pub mod conv;

pub use self::conv::IntoLinSrgba;
pub use self::named::*;
#[doc(inline)]
pub use palette::*;
use crate::ui::color;

/// The default scalar value for working with color components, hues, etc.
pub type DefaultScalar = f32;

/// A color represented as red, green and blue intensities.
///
/// This type is an alias for the `Srgb` type, a type that represents the sRGB color space.
///
/// If you are looking for more advanced control over the RGB space and component type, please see
/// the `palette` crate's generic `Rgb` type.
pub type Rgb<S = DefaultScalar> = Srgb<S>;

/// The same as `Rgb`, but with an alpha value representing opacity.
///
/// This type is an alias for the `Srgba` type, a type that represents the sRGB color space
/// alongside an alpha value.
///
/// If you are looking for more advanced control over the RGB space and component type, please see
/// the `palette` crate's generic `Rgb` type.
pub type Rgba<S = DefaultScalar> = Srgba<S>;

/// A color represented as gray intensity.
///
/// This type is an alias for the `Srgb` type, a type that represents the sRGB color space.
///
/// If you are looking for more advanced control over the RGB space and component type, please see
/// the `palette` crate's generic `Rgb` type.
pub type Gray<S = DefaultScalar> = Srgb<S>;

/// A short-hand constructor for `Rgb::new`.
pub fn rgb<T>(r: T, g: T, b: T) -> Rgb<T>
where
    T: Component,
{
    srgb(r, g, b)
}

/// A short-hand constructor for `Rgb<u8>::new`.
pub fn rgb8(r: u8, g: u8, b: u8) -> Rgb<u8> {
    srgb8(r, g, b)
}

/// A short-hand constructor for `Rgba::new`.
pub fn rgba<T>(r: T, g: T, b: T, a: T) -> Rgba<T>
where
    T: Component,
{
    srgba(r, g, b, a)
}

/// A short-hand constructor for `Rgba<u8>::new`.
pub fn rgba8(r: u8, g: u8, b: u8, a: u8) -> Rgba<u8> {
    srgba8(r, g, b, a)
}

/// A short-hand constructor for `Srgb::new`.
pub fn srgb<T>(r: T, g: T, b: T) -> Srgb<T>
where
    T: Component,
{
    Srgb::new(r, g, b)
}

/// A short-hand constructor for `Srgb<u8>::new`.
pub fn srgb8(r: u8, g: u8, b: u8) -> Srgb<u8> {
    Srgb::new(r, g, b)
}

/// A short-hand constructor for `Srgba::new`.
pub fn srgba<T>(r: T, g: T, b: T, a: T) -> Srgba<T>
where
    T: Component,
{
    Srgba::new(r, g, b, a)
}

/// A short-hand constructor for `Srgba<u8>::new`.
pub fn srgba8(r: u8, g: u8, b: u8, a: u8) -> Srgba<u8> {
    Srgba::new(r, g, b, a)
}

/// A short-hand constructor for `LinSrgb::new`.
pub fn lin_srgb<T>(r: T, g: T, b: T) -> LinSrgb<T>
where
    T: Component,
{
    LinSrgb::new(r, g, b)
}

/// A short-hand constructor for `LinSrgba::new`.
pub fn lin_srgba<T>(r: T, g: T, b: T, a: T) -> LinSrgba<T>
where
    T: Component,
{
    LinSrgba::new(r, g, b, a)
}

/// Create a new color from a hexadecimal int literal
#[inline]
pub fn rgb_u32(c: u32) -> color::Color {
    let blue: u8 = (c & 0xFF) as u8;
    let green: u8 = (( c >> 8 ) & 0xFF) as u8;
    let red: u8 = (( c >> 16 ) & 0xFF) as u8;
    color::rgb_bytes(red, green, blue)
}

/// A short-hand constructor for `Hsl::new(RgbHue::from_degrees(h * 360.0), s, l)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsl(h: f32, s: f32, l: f32) -> Hsl {
    Hsl::new(RgbHue::from_degrees(h * 360.0), s, l)
}

/// A short-hand constructor for `Hsla::new(RgbHue::from_degrees(h * 360.0), s, l, a)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla {
    Hsla::new(RgbHue::from_degrees(h * 360.0), s, l, a)
}

/// A short-hand constructor for `Hsv::new(RgbHue::from_degrees(h * 360.0), s, v)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsv(h: f32, s: f32, v: f32) -> Hsv {
    Hsv::new(RgbHue::from_degrees(h * 360.0), s, v)
}

/// A short-hand constructor for `Hsva::new(RgbHue::from_degrees(h * 360.0), s, v, a)`.
///
/// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
/// 360 degrees (or 2 PI radians).
pub fn hsva(h: f32, s: f32, v: f32, a: f32) -> Hsva {
    Hsva::new(RgbHue::from_degrees(h * 360.0), s, v, a)
}

/// A short-hand constructor for `Gray::new`.
pub fn gray<T>(g: T) -> Gray<T>
where
    T: Component,
{
    srgb(g, g, g)
}

#[test]
fn test_rgb_u32() {
    assert_eq!(rgb_u32(0xFF8000), color::rgb_bytes(255, 128, 0));
}
<|endoftext|>


<commit_before>pub mod display_list;
pub mod export;

use glutin::dpi::PhysicalSize;
use pathfinder_canvas::{Canvas, CanvasFontContext, Path2D, LineCap, LineJoin, FillRule};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::{vec2f, vec2i, Vector2F};
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_resources::embedded::EmbeddedResourceLoader;
use pathfinder_renderer::{
    concurrent::rayon::RayonExecutor,
    concurrent::scene_proxy::SceneProxy,
    options::BuildOptions,
    gpu::{
        renderer::Renderer as PathfinderRenderer,
        options::{DestFramebuffer, RendererOptions},
    },
};

use crate::{Point, Color};

use super::state::DrawingState;

use display_list::{DisplayList, DrawPrim, Line, Polygon};

/// Converts a color from the representation in this crate to the one used in the renderer
fn convert_color(color: Color) -> ColorU {
    let Color {red, green, blue, alpha} = color;
    ColorU {
        r: red.round() as u8,
        g: green.round() as u8,
        b: blue.round() as u8,
        a: (alpha * 255.0).round() as u8,
    }
}

/// Converts a `Point` in logical or "world" coordinates to a `Vector2F` in screen coordinates
///
/// # Parameters
///
/// * `point` is the `Point` to convert to screen coordinates
/// * `dpi_scale` is the high DPI scale factor (>= 0.0)
/// * `center` is the `Point` configured in the drawing that all other `Point`s are relative to.
/// * `fb_center` is the center of the framebuffer in screen coordinates.
///
/// # Coordinate Systems
///
/// * logical or "world" coordinates (cartesian coordinates)
///   * origin is in the center of the framebuffer and can be offset by `center`
///   * x is left to right
///   * y is bottom to top
/// * screen coordinates
///   * origin is the top-left corner of the framebuffer
///   * x is left to right
///   * y is top to bottom
fn to_screen_coords(point: Point, dpi_scale: f64, center: Point, fb_center: Vector2F) -> Vector2F {
    let Point {x, y} = point;
    let Point {x: center_x, y: center_y} = center;
    let fb_center_x = fb_center.x();
    let fb_center_y = fb_center.y();

    vec2f(
        ((x - center_x) * dpi_scale) as f32 + fb_center_x,
        -((y - center_y) * dpi_scale) as f32 + fb_center_y,
    )
}

/// A renderer that draws on the current OpenGL context
pub struct Renderer {
    renderer: PathfinderRenderer<GLDevice>,
    font_context: CanvasFontContext,
    scene: SceneProxy,
    /// Information about DPI scaling: https://docs.rs/glutin/0.24.0/glutin/dpi/index.html
    dpi_scale: f64,
}

impl Renderer {
    /// Creates a new renderer with the given physical size in pixels
    pub fn new(draw_size: PhysicalSize<u32>) -> Self {
        let renderer = PathfinderRenderer::new(
            GLDevice::new(GLVersion::GL3, 0),
            &EmbeddedResourceLoader::new(),
            DestFramebuffer::full_window(vec2i(draw_size.width as i32, draw_size.height as i32)),
            // This background color will be overwritten during the first render
            RendererOptions {
                background_color: Some(ColorU::white().to_f32()),
                ..RendererOptions::default()
            },
        );

        Self {
            renderer,
            font_context: CanvasFontContext::from_system_source(),
            scene: SceneProxy::new(RayonExecutor),
            // Default is 1.0 according to: https://docs.rs/glutin/0.24.0/glutin/dpi/index.html#events
            dpi_scale: 1.0,
        }
    }

    /// Updates the scale factor used during rendering
    pub fn set_scale_factor(&mut self, dpi_scale: f64) {
        self.dpi_scale = dpi_scale;
    }

    /// Draw the given primitives onto a canvas of the given size
    ///
    /// Size is passed in to ensure that it is up-to-date
    pub fn render(&mut self, draw_size: PhysicalSize<u32>, display_list: &DisplayList, drawing: &DrawingState) {
        // Set the current draw size
        self.renderer.replace_dest_framebuffer(
            DestFramebuffer::full_window(vec2i(draw_size.width as i32, draw_size.height as i32))
        );

        // Clear to background color
        self.renderer.set_options(RendererOptions {
            background_color: Some(convert_color(drawing.background).to_f32()),
            ..RendererOptions::default()
        });

        // The size of the framebuffer
        let fb_size = vec2f(draw_size.width as f32, draw_size.height as f32);
        let mut canvas = Canvas::new(fb_size)
            .get_context_2d(self.font_context.clone());

        // Set default options for all operations
        canvas.set_line_cap(LineCap::Round);
        canvas.set_line_join(LineJoin::Round);

        // Draw each primitive
        let dpi_scale = self.dpi_scale;
        let center = drawing.center;
        let fb_center = fb_size / 2.0;
        for prim in display_list.iter() {
            match prim {
                &DrawPrim::Line(Line {start, end, thickness, color}) => {
                    let mut path = Path2D::new();

                    path.move_to(to_screen_coords(start, dpi_scale, center, fb_center));
                    path.line_to(to_screen_coords(end, dpi_scale, center, fb_center));

                    canvas.set_line_width((thickness * dpi_scale) as f32);
                    canvas.set_stroke_style(convert_color(color));
                    canvas.stroke_path(path);
                },

                &DrawPrim::Polygon(Polygon {ref points, fill_color}) => {
                    // Skip obviously degenerate polygons
                    if points.len() <= 2 {
                        continue;
                    }

                    let mut path = Path2D::new();

                    path.move_to(to_screen_coords(points[0], dpi_scale, center, fb_center));
                    for &point in &points[1..] {
                        path.line_to(to_screen_coords(point, dpi_scale, center, fb_center));
                    }

                    path.close_path();

                    canvas.set_fill_style(convert_color(fill_color));
                    canvas.fill_path(path, FillRule::Winding);
                },
            }
        }

        // Build and render scene
        self.scene.replace_scene(canvas.into_canvas().into_scene());
        self.scene.build_and_render(&mut self.renderer, BuildOptions::default());
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn screen_coords() {
        // The origin is always at fb_center as long as center is also the origin
        let screen_coord = to_screen_coords(Point::origin(), 1.0, Point::origin(), vec2f(200.0, 300.0));
        assert_eq!(screen_coord, vec2f(200.0, 300.0));
        // The origin is always at fb_center regardless of DPI scale
        let screen_coord = to_screen_coords(Point::origin(), 2.0, Point::origin(), vec2f(200.0, 300.0));
        assert_eq!(screen_coord, vec2f(200.0, 300.0));

        // The x-axis and y-axis treated distinctly and interpreted as cartesian
        let screen_coord = to_screen_coords(Point {x: 10.0, y: 20.0}, 1.0, Point::origin(), vec2f(200.0, 300.0));
        assert_eq!(screen_coord, vec2f(210.0, 280.0));
        // A different fb_center gives a different final coordinate
        let screen_coord = to_screen_coords(Point {x: 10.0, y: 20.0}, 1.0, Point::origin(), vec2f(300.0, 400.0));
        assert_eq!(screen_coord, vec2f(310.0, 380.0));

        // The center is interpreted as cartesian and points are relative to it
        let screen_coord = to_screen_coords(Point {x: 10.0, y: 20.0}, 1.0, Point {x: 30.0, y: 5.0}, vec2f(200.0, 300.0));
        assert_eq!(screen_coord, vec2f(180.0, 285.0));

        // Negative points work too
        let screen_coord = to_screen_coords(Point {x: -10.0, y: -20.0}, 1.0, Point {x: 30.0, y: -5.0}, vec2f(200.0, 300.0));
        assert_eq!(screen_coord, vec2f(160.0, 315.0));

        // DPI scale > 1.0 causes logical coordinates to scale, but NOT screen coordinates
        let screen_coord = to_screen_coords(Point {x: 10.0, y: 20.0}, 2.0, Point {x: 30.0, y: 5.0}, vec2f(200.0, 300.0));
        assert_eq!(screen_coord, vec2f(160.0, 270.0));
    }
}
<commit_msg>Need to draw *something* every time in order to get pathfinder to render the background<commit_after>pub mod display_list;
pub mod export;

use glutin::dpi::PhysicalSize;
use pathfinder_canvas::{Canvas, CanvasFontContext, Path2D, LineCap, LineJoin, FillRule};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::{vec2f, vec2i, Vector2F};
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_resources::embedded::EmbeddedResourceLoader;
use pathfinder_renderer::{
    concurrent::rayon::RayonExecutor,
    concurrent::scene_proxy::SceneProxy,
    options::BuildOptions,
    gpu::{
        renderer::Renderer as PathfinderRenderer,
        options::{DestFramebuffer, RendererOptions},
    },
};

use crate::{Point, Color};

use super::state::DrawingState;

use display_list::{DisplayList, DrawPrim, Line, Polygon};

/// Converts a color from the representation in this crate to the one used in the renderer
fn convert_color(color: Color) -> ColorU {
    let Color {red, green, blue, alpha} = color;
    ColorU {
        r: red.round() as u8,
        g: green.round() as u8,
        b: blue.round() as u8,
        a: (alpha * 255.0).round() as u8,
    }
}

/// Converts a `Point` in logical or "world" coordinates to a `Vector2F` in screen coordinates
///
/// # Parameters
///
/// * `point` is the `Point` to convert to screen coordinates
/// * `dpi_scale` is the high DPI scale factor (>= 0.0)
/// * `center` is the `Point` configured in the drawing that all other `Point`s are relative to.
/// * `fb_center` is the center of the framebuffer in screen coordinates.
///
/// # Coordinate Systems
///
/// * logical or "world" coordinates (cartesian coordinates)
///   * origin is in the center of the framebuffer and can be offset by `center`
///   * x is left to right
///   * y is bottom to top
/// * screen coordinates
///   * origin is the top-left corner of the framebuffer
///   * x is left to right
///   * y is top to bottom
fn to_screen_coords(point: Point, dpi_scale: f64, center: Point, fb_center: Vector2F) -> Vector2F {
    let Point {x, y} = point;
    let Point {x: center_x, y: center_y} = center;
    let fb_center_x = fb_center.x();
    let fb_center_y = fb_center.y();

    vec2f(
        ((x - center_x) * dpi_scale) as f32 + fb_center_x,
        -((y - center_y) * dpi_scale) as f32 + fb_center_y,
    )
}

/// A renderer that draws on the current OpenGL context
pub struct Renderer {
    renderer: PathfinderRenderer<GLDevice>,
    font_context: CanvasFontContext,
    scene: SceneProxy,
    /// Information about DPI scaling: https://docs.rs/glutin/0.24.0/glutin/dpi/index.html
    dpi_scale: f64,
}

impl Renderer {
    /// Creates a new renderer with the given physical size in pixels
    pub fn new(draw_size: PhysicalSize<u32>) -> Self {
        let renderer = PathfinderRenderer::new(
            GLDevice::new(GLVersion::GL3, 0),
            &EmbeddedResourceLoader::new(),
            DestFramebuffer::full_window(vec2i(draw_size.width as i32, draw_size.height as i32)),
            // This background color will be overwritten during the first render
            RendererOptions {
                background_color: Some(ColorU::white().to_f32()),
                ..RendererOptions::default()
            },
        );

        Self {
            renderer,
            font_context: CanvasFontContext::from_system_source(),
            scene: SceneProxy::new(RayonExecutor),
            // Default is 1.0 according to: https://docs.rs/glutin/0.24.0/glutin/dpi/index.html#events
            dpi_scale: 1.0,
        }
    }

    /// Updates the scale factor used during rendering
    pub fn set_scale_factor(&mut self, dpi_scale: f64) {
        self.dpi_scale = dpi_scale;
    }

    /// Draw the given primitives onto a canvas of the given size
    ///
    /// Size is passed in to ensure that it is up-to-date
    pub fn render(&mut self, draw_size: PhysicalSize<u32>, display_list: &DisplayList, drawing: &DrawingState) {
        // Set the current draw size
        self.renderer.replace_dest_framebuffer(
            DestFramebuffer::full_window(vec2i(draw_size.width as i32, draw_size.height as i32))
        );

        // Clear to background color
        self.renderer.set_options(RendererOptions {
            background_color: Some(convert_color(drawing.background).to_f32()),
            ..RendererOptions::default()
        });

        // The size of the framebuffer
        let fb_size = vec2f(draw_size.width as f32, draw_size.height as f32);
        let mut canvas = Canvas::new(fb_size)
            .get_context_2d(self.font_context.clone());

        // Set default options for all operations
        canvas.set_line_cap(LineCap::Round);
        canvas.set_line_join(LineJoin::Round);

        //TODO: Remove this line once servo/pathfinder#318 is fixed.
        //  Link: https://github.com/servo/pathfinder/issues/318
        // Need to render *something* every time to get pathfinder to even render a background
        canvas.stroke_rect(pathfinder_geometry::rect::RectF::new(vec2f(0.0, 0.0), vec2f(1.0, 1.0)));

        // Draw each primitive
        let dpi_scale = self.dpi_scale;
        let center = drawing.center;
        let fb_center = fb_size / 2.0;
        for prim in display_list.iter() {
            match prim {
                &DrawPrim::Line(Line {start, end, thickness, color}) => {
                    let mut path = Path2D::new();

                    path.move_to(to_screen_coords(start, dpi_scale, center, fb_center));
                    path.line_to(to_screen_coords(end, dpi_scale, center, fb_center));

                    canvas.set_line_width((thickness * dpi_scale) as f32);
                    canvas.set_stroke_style(convert_color(color));
                    canvas.stroke_path(path);
                },

                &DrawPrim::Polygon(Polygon {ref points, fill_color}) => {
                    // Skip obviously degenerate polygons
                    if points.len() <= 2 {
                        continue;
                    }

                    let mut path = Path2D::new();

                    path.move_to(to_screen_coords(points[0], dpi_scale, center, fb_center));
                    for &point in &points[1..] {
                        path.line_to(to_screen_coords(point, dpi_scale, center, fb_center));
                    }

                    path.close_path();

                    canvas.set_fill_style(convert_color(fill_color));
                    canvas.fill_path(path, FillRule::Winding);
                },
            }
        }

        // Build and render scene
        self.scene.replace_scene(canvas.into_canvas().into_scene());
        self.scene.build_and_render(&mut self.renderer, BuildOptions::default());
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn screen_coords() {
        // The origin is always at fb_center as long as center is also the origin
        let screen_coord = to_screen_coords(Point::origin(), 1.0, Point::origin(), vec2f(200.0, 300.0));
        assert_eq!(screen_coord, vec2f(200.0, 300.0));
        // The origin is always at fb_center regardless of DPI scale
        let screen_coord = to_screen_coords(Point::origin(), 2.0, Point::origin(), vec2f(200.0, 300.0));
        assert_eq!(screen_coord, vec2f(200.0, 300.0));

        // The x-axis and y-axis treated distinctly and interpreted as cartesian
        let screen_coord = to_screen_coords(Point {x: 10.0, y: 20.0}, 1.0, Point::origin(), vec2f(200.0, 300.0));
        assert_eq!(screen_coord, vec2f(210.0, 280.0));
        // A different fb_center gives a different final coordinate
        let screen_coord = to_screen_coords(Point {x: 10.0, y: 20.0}, 1.0, Point::origin(), vec2f(300.0, 400.0));
        assert_eq!(screen_coord, vec2f(310.0, 380.0));

        // The center is interpreted as cartesian and points are relative to it
        let screen_coord = to_screen_coords(Point {x: 10.0, y: 20.0}, 1.0, Point {x: 30.0, y: 5.0}, vec2f(200.0, 300.0));
        assert_eq!(screen_coord, vec2f(180.0, 285.0));

        // Negative points work too
        let screen_coord = to_screen_coords(Point {x: -10.0, y: -20.0}, 1.0, Point {x: 30.0, y: -5.0}, vec2f(200.0, 300.0));
        assert_eq!(screen_coord, vec2f(160.0, 315.0));

        // DPI scale > 1.0 causes logical coordinates to scale, but NOT screen coordinates
        let screen_coord = to_screen_coords(Point {x: 10.0, y: 20.0}, 2.0, Point {x: 30.0, y: 5.0}, vec2f(200.0, 300.0));
        assert_eq!(screen_coord, vec2f(160.0, 270.0));
    }
}
<|endoftext|>