# # $Id: dropdown.icn,v 1.11 2004/11/11 19:56:12 rparlett Exp $ # # This file is in the public domain. # # Author: Robert Parlett (parlett@dial.pipex.com) # package gui link graphics $include "guih.icn" class DropDownTextList : TextList(drag_flag) # # Determine an appropriate size for the drop-down list. # # @p method set_ideal_size(min_w, max_w, min_h, max_h) local fh, mw, s fh := WAttrib(self.cwin, "fheight") # # Compute longest line # mw := get_subject_width() # # Set the width needed, ensuring within min/max dimensions requested # self.w_spec := mw + 2 * get_view_x_padding() self.w_spec <:= min_w self.w_spec >:= max_w # # Set the height needed, checking for presence of HSB # if self.w_spec - 2 * get_view_x_padding() >= mw then self.h_spec := *self.contents * fh + 2 * get_view_y_padding() else self.h_spec := *self.contents * fh + 2 * get_view_y_padding() + SB_SIZE self.h_spec <:= min_h self.h_spec >:= max_h end # # This solves a problem whereby clicking on the button and moving slightlty # would start the ticker. Therefore, ignore drags until the point where the # cursor has crossed a line. # # @p method handle_drag(e) if get_line_under_pointer() then self.drag_flag := 1 /self.drag_flag | self.TextList.handle_drag(e) end end # # This class is just a superclass of {List} and {EditList}. # class DropDown : Component( b, selection, # selection_list, # tl, # temp_win # ) # # Set the list selection items to the list x. # @param The list of items # method set_selection_list(x) return self.selection_list := x end # # Set the selected item. # @param x An index into the list of selectable items. # method set_selection(x) self.selection := x apply_selection() end # # Return an integer corresponding to the item in the list # presently selected. # method get_selection() return self.selection end method on_button(ev) if \tl then { if ev.get_type() === BUTTON_PRESS_EVENT then { # # Button pressed whilst list open; just close # self.close_textlist() self.unique_end(1) } else if ev.get_type() === BUTTON_RELEASE_EVENT then { self.tl.is_held := &null self.tl.drag_flag := 1 } } else { if ev.get_type() === BUTTON_PRESS_EVENT then { # # Button pressed whilst no list; open list # self.open_textlist() self.tl.is_held := 1 self.unique_start() } } end method on_textlist_selection(ev) local tmp # # Selection in list - close textlist, amend label, return event. # tmp := tl.get_selections()[1] self.close_textlist() self.unique_end(1) go_to(\tmp, ev) end method go_up(e) if self.selection = 1 then set_selection(*self.selection_list) else self.set_selection(self.selection - 1) fire(SELECTION_CHANGED_EVENT, e) end method go_down(e) set_selection(1 + self.selection % *self.selection_list) fire(SELECTION_CHANGED_EVENT, e) end method go_to(x, e) set_selection(x) fire(SELECTION_CHANGED_EVENT, e) end abstract method apply_selection() method open_textlist() local lno # # Initialize and open a list, saving window area below in a temp window. # self.tl := DropDownTextList() self.tl.connect(self, "on_textlist_selection", SELECTION_CHANGED_EVENT) self.tl.set_contents(self.selection_list) self.tl.set_pos(0, self.h) self.tl.set_parent(self) self.tl.set_draggable_cursor() self.tl.set_motion_cursor() self.tl.init() self.tl.set_ideal_size(self.w, WAttrib(self.get_parent_win(), "width") - self.x - 10, 0, WAttrib(self.get_parent_win(), "height") - self.y - self.h - 10) self.tl.set_select_one() self.tl.resize() self.tl.firstly() self.temp_win := WOpen("canvas=hidden", "size=" || self.tl.w || "," || self.tl.h) CopyArea(self.cwin, self.temp_win, self.tl.x, self.tl.y, self.tl.w, self.tl.h, 0, 0) self.tl.clear_selection_on_key_moves() self.tl.set_cursor(self.selection) lno := self.selection - self.tl.get_max_lines() / 2 lno <:= 1 self.tl.goto_pos(lno) self.tl.got_focus() self.add(tl) end method close_textlist() # # Close list, restore window # self.tl.finally() EraseRectangle(self.cwin, self.tl.x, self.tl.y, self.tl.w, self.tl.h) CopyArea(self.temp_win, self.cwin, 0, 0, self.tl.w, self.tl.h, self.tl.x, self.tl.y) WClose(self.temp_win) self.remove(tl) self.tl := &null end method finally() # # Disposed with text list showing, just get rid of it # if \self.tl then { self.close_textlist() self.unique_end() } self.Component.finally() end method handle_event(e) if \tl then { b.handle_event(e) (\tl).handle_event(e) if \tl & ((e === "\e") | ((e === (&lpress | &rpress | &mpress)) & not(tl.in_region()))) then { # # Mouse click outside textlist. Close. # self.close_textlist() self.unique_end() } } else { self.Component.handle_event(e) } end method set_one(attr, val) case attr of { "selection_list" : set_selection_list(val) default: self.Component.set_one(attr, val) } end initially() self.Component.initially() self.b := IconButton() self.b.set_parent(self) self.b.connect(self, "on_button") self.b.toggle_draw_border() self.b.set_img(img_style("arrow_down")) self.b.clear_accepts_focus() self.add(b) self.selection := 1 end