note description: "EiffelVision message dialog. Dialogs that always consist of %N% %a pixmap, a text and one or more buttons." legal: "See notice at end of class." status: "See notice at end of class." keywords: "dialog, standard, pixmap, text, button, modal" date: "$Date$" revision: "$Revision$" class EV_MESSAGE_DIALOG inherit EV_DIALOG redefine initialize, create_interface_objects, set_background_color, set_foreground_color, foreground_color, background_color, default_identifier_name, user_can_resize_default_state end EV_DIALOG_CONSTANTS export {NONE} all undefine default_create, copy end create default_create, make_with_text, make_with_text_and_actions feature {NONE} -- Initialization make_with_text (a_text: READABLE_STRING_GENERAL) -- Create `Current' and assign `a_text' to `text'. require a_text_not_void: a_text /= Void do default_create set_text (a_text) end make_with_text_and_actions ( a_text: READABLE_STRING_GENERAL; actions: ARRAY [PROCEDURE] ) -- Create `Current', assign `a_text' to `text' and `actions' to `select_actions' -- of `buttons'. -- (`actions' are added to `buttons' in order.) require a_text_not_void: a_text /= Void actions_not_void: actions /= Void actions_not_empty: actions.count > 0 local i: INTEGER c: CURSOR b: detachable EV_BUTTON do default_create set_text (a_text) c := button_box.cursor from --| We loop through `button_box' instead of `buttons', as --| if we were to loop through `buttons', we would not get --| the buttons in the order they are displayed. button_box.start i := 1 until i > actions.count or button_box.after loop b ?= button_box.item check button_box_contains_only_buttons: b /= Void then end b.select_actions.extend (actions @ i) button_box.forth i := i + 1 end button_box.go_to (c) end create_interface_objects -- local l_stock_colors: EV_STOCK_COLORS do create buttons.make (5) create button_box create pixmap_box create scrollable_area create label create l_stock_colors foreground_color := l_stock_colors.default_foreground_color background_color := l_stock_colors.default_background_color end initialize -- Initialize `Current' to default state. local hb: EV_HORIZONTAL_BOX vb: EV_VERTICAL_BOX hb2: EV_HORIZONTAL_BOX vb2: EV_VERTICAL_BOX l_screen: EV_SCREEN do foreground_color := implementation.foreground_color background_color := implementation.background_color create hb create vb create hb2 create vb2 Precursor create l_screen maximum_label_width := l_screen.width - 200 maximum_label_height := l_screen.height - 200 vb2.extend (pixmap_box) vb2.disable_item_expand (pixmap_box) vb2.extend (create {EV_CELL}) hb.extend (vb2) -- hb.disable_item_expand (vb2) hb.extend (label) hb.set_padding (10) hb2.extend (create {EV_CELL}) hb2.extend (button_box) hb2.disable_item_expand (button_box) hb2.extend (create {EV_CELL}) vb.extend (hb) vb.extend (hb2) vb.disable_item_expand (hb2) vb.set_padding (14) vb.set_border_width (10) label.align_text_left button_box.set_padding (10) extend (vb) set_text ("Use `set_text' to modify this message.") key_press_actions.extend (agent on_key_press) disable_user_resize end feature -- Access pixmap: detachable EV_PIXMAP -- Icon displayed by `Current'. require not_destroyed: not is_destroyed do if pixmap_box.readable then Result ?= pixmap_box.item check Result_not_void: Result /= Void end end end text: STRING_32 -- Message displayed by `Current'. require not_destroyed: not is_destroyed do Result := label.text ensure not_void: Result /= Void end foreground_color: EV_COLOR -- Foreground color of `Current'. background_color: EV_COLOR -- Background color of `Current'. default_identifier_name: STRING_32 -- Default identifier name if no specific name is set. do if title.is_empty then Result := Precursor {EV_DIALOG} else Result := title.as_lower Result.prune_all ('.') end end feature -- Status setting set_background_color (a_color: EV_COLOR) -- Assign `a_color' to `background_color'. local dialog_box: detachable EV_CONTAINER do item.set_background_color (a_color) dialog_box ?= item if dialog_box /= Void then dialog_box.propagate_background_color end background_color.copy (a_color) end set_foreground_color (a_color: EV_COLOR) -- Assign `a_color' to `foreground_color'. local dialog_box: detachable EV_CONTAINER do item.set_foreground_color (a_color) dialog_box ?= item if dialog_box /= Void then dialog_box.propagate_foreground_color end foreground_color.copy (a_color) end set_pixmap (a_pixmap: EV_PIXMAP) -- Assign `a_pixmap' to `pixmap'. require not_destroyed: not is_destroyed a_pixmap_not_void: a_pixmap /= Void local pixmap_clone: EV_PIXMAP do if pixmap /= Void then remove_pixmap end create pixmap_clone pixmap_clone.copy (a_pixmap) pixmap_box.extend (pixmap_clone) pixmap_box.set_minimum_size (pixmap_clone.width, pixmap_clone.height) ensure pixmap_assigned: attached pixmap as l_pixmap and then l_pixmap.is_equal (a_pixmap) end remove_pixmap -- Assign `Void' to `pixmap'. require not_destroyed: not is_destroyed do pixmap_box.wipe_out ensure pixmap_void: pixmap = Void end set_text (a_text: READABLE_STRING_GENERAL) -- Assign `a_text' to `text'. require not_destroyed: not is_destroyed a_text_not_void: a_text /= Void local l_label_width, l_label_height: INTEGER l_scrollbar_needed: BOOLEAN l_dialog_parent: detachable EV_CONTAINER do -- Unparent scrollable area if attached scrollable_area.parent as l_scroll_parent then l_scroll_parent.prune (scrollable_area) scrollable_area.prune (label) l_dialog_parent := l_scroll_parent elseif attached label.parent as l_label_parent then l_label_parent.prune (label) l_dialog_parent := l_label_parent end label.set_text (a_text) l_label_width := label.width l_label_height := label.height if l_label_width > maximum_label_width then l_scrollbar_needed := True scrollable_area.show_horizontal_scroll_bar l_label_width := maximum_label_width else scrollable_area.hide_vertical_scroll_bar end if l_label_height > maximum_label_height then l_scrollbar_needed := True scrollable_area.show_vertical_scroll_bar l_label_height := maximum_label_height else scrollable_area.hide_vertical_scroll_bar end scrollable_area.set_minimum_width (l_label_width) scrollable_area.set_minimum_height (l_label_height) if l_scrollbar_needed then scrollable_area.extend (label) if l_dialog_parent /= Void then l_dialog_parent.extend (scrollable_area) end else if l_dialog_parent /= Void then l_dialog_parent.extend (label) end end ensure assigned: text.same_string_general (a_text) cloned: text /= a_text end remove_text -- Make `text' empty. require not_destroyed: not is_destroyed do set_text ("") ensure text_not_void: text /= Void and text.is_empty end set_buttons (button_labels: ARRAY [READABLE_STRING_GENERAL]) -- Assign new buttons with `button_labels' to `buttons'. require not_destroyed: not is_destroyed button_labels_not_void: button_labels /= Void local i: INTEGER do clean_buttons from i := 1 until i > button_labels.count loop add_button (button_labels @ i) i := i + 1 end button_box.enable_homogeneous end set_buttons_and_actions ( button_labels: ARRAY [READABLE_STRING_GENERAL] actions: ARRAY [detachable PROCEDURE] ) -- Assign new buttons with `button_labels' and `actions' to `buttons'. require not_destroyed: not is_destroyed button_labels_not_void: button_labels /= Void actions_not_void: actions /= Void enough_actions_for_labels: actions.count >= button_labels.count local i: INTEGER do clean_buttons from i := 1 until i > button_labels.count loop if attached actions [i] as l_action then add_button_with_action (button_labels [i], l_action) else add_button (button_labels [i]) end i := i + 1 end end feature -- Status report has_button (a_text: READABLE_STRING_GENERAL): BOOLEAN -- Does `Current' contain a button with `text' `a_text'? require not_destroyed: not is_destroyed a_text_not_void: a_text /= Void do Result := buttons.has (a_text.as_string_32) end button (a_text: READABLE_STRING_GENERAL): EV_BUTTON -- Button that has `a_text'. require not_destroyed: not is_destroyed a_text_not_void: a_text /= Void has_button_with_a_text: has_button (a_text) local l_result: detachable EV_BUTTON do l_result := buttons.item (a_text.as_string_32) check l_result /= Void then end Result := l_result ensure not_void: Result /= Void end selected_button: detachable STRING_32 -- Label of last clicked button. feature {NONE} -- Implementation maximum_label_width: INTEGER -- Maximum width the label can be before scrollbar is enabled. maximum_label_height: INTEGER -- Maximum height the label can be before scrollbar is enabled. user_can_resize_default_state: BOOLEAN = False -- button_box: EV_HORIZONTAL_BOX -- Bar with all buttons of the dialog. scrollable_area: EV_SCROLLABLE_AREA -- Scrollable area in which `label' resides. label: EV_LABEL -- Text label where `text' is displayed. pixmap_box: EV_CELL -- Container to display pixmap in. buttons: HASH_TABLE [EV_BUTTON, STRING_32] -- Lookup-table for the buttons in `Current' based on -- their captions. clean_buttons -- Remove all buttons from `Current'. require not_destroyed: not is_destroyed do if default_push_button /= Void then remove_default_push_button end if default_cancel_button /= Void then remove_default_cancel_button end button_box.wipe_out buttons.wipe_out end add_button (a_text: READABLE_STRING_GENERAL) -- An item has been added to `buttons'. require not_destroyed: not is_destroyed a_text_not_void: a_text /= Void local new_button: EV_BUTTON l_default_button: BOOLEAN do create new_button.make_with_text (a_text) --| We now put the button in the hash-table to give the --| user access to it. buttons.put (new_button, a_text.as_string_32) l_default_button := button_box.is_empty new_button.select_actions.extend (agent on_button_press (a_text)) button_box.extend (new_button) button_box.disable_item_expand (new_button) new_button.set_minimum_width (new_button.minimum_width.max (75)) new_button.align_text_center if l_default_button then set_default_push_button (new_button) end end add_button_with_action (a_text: READABLE_STRING_GENERAL; a_action: PROCEDURE) -- An item has been added to `buttons'. require not_destroyed: not is_destroyed a_text_not_void: a_text /= Void a_action_not_void: a_action /= Void do add_button (a_text) button (a_text).select_actions.extend (a_action) end on_button_press (a_button_text: READABLE_STRING_GENERAL) -- A button with text `a_button_text' has been pressed. do selected_button := a_button_text.as_string_32 if not is_destroyed then destroy end end on_key_press (a_key: EV_KEY) -- Called when user presses a key on the dialog. do if a_key.code = {EV_KEY_CONSTANTS}.key_left then move_to_next_button (-1) elseif a_key.code = {EV_KEY_CONSTANTS}.key_right then move_to_next_button (1) end end move_to_next_button (a_delta: INTEGER) -- Moves focus to next or previous button based on `a_delta'. require valid_delta: a_delta = -1 or a_delta = 1 local l_buttons: like button_box l_cursor: CURSOR l_focused_widget: detachable EV_WIDGET l_focused: BOOLEAN do l_buttons := button_box if l_buttons.count > 1 then l_cursor := l_buttons.cursor from l_buttons.start until l_buttons.after or l_focused loop l_focused_widget := l_buttons.item l_focused := l_focused_widget.has_focus if not l_focused then l_buttons.forth end end if l_focused then if l_focused_widget /= Void then if a_delta = -1 then if l_buttons.first = l_focused_widget then l_buttons.last.set_focus else l_buttons.back l_buttons.item.set_focus end else if l_buttons.last = l_focused_widget then l_buttons.first.set_focus else l_buttons.forth l_buttons.item.set_focus end end end else l_buttons.first.set_focus end l_buttons.go_to (l_cursor) end end note copyright: "Copyright (c) 1984-2013, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software 5949 Hollister Ave., Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" end -- class EV_MESSAGE_DIALOG