Module: gtk-duim Synopsis: GTK gadget implementation Author: Andy Armstrong, Scott McKay Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// Useful constants define constant $default-label = ""; define constant $button-box-x-spacing = 3; define constant $button-box-y-spacing = 3; /// GTK gadgets define class () end class ; define open abstract class (, ) // sealed constant each-subclass slot %gtk-fixed-width? :: = #f, // init-keyword: gtk-fixed-width?:; // sealed constant each-subclass slot %gtk-fixed-height? :: = #f, // init-keyword: gtk-fixed-height?:; end class ; define open generic %gtk-fixed-width? (gadget :: ) => (fixed? :: ); define method %gtk-fixed-width? (gadget :: ) => (fixed? :: ); #f; end method; define open generic %gtk-fixed-height? (gadget :: ) => (fixed? :: ); define method %gtk-fixed-height? (gadget :: ) => (fixed? :: ); #f; end method; define method gadget-widget (sheet :: ) => (widget) let mirror = sheet-mirror(sheet); let widget = mirror & mirror-widget(mirror); widget end; // /*---*** Not used yet! define method widget-attributes (_port :: , gadget :: ) => (foreground, background, font) let foreground :: = get-default-foreground(_port, gadget); let background :: = get-default-background(_port, gadget); let text-style = get-default-text-style(_port, gadget); let foreground = if (default-foreground(gadget)) vector(foreground:, allocate-color(foreground, port-default-palette(_port))) else #[] end; let background = if (default-background(gadget)) vector(background:, allocate-color(background, port-default-palette(_port))) else #[] end; let font = if (default-text-style(gadget)) vector(text-style:, text-style-mapping(_port, text-style).%font-name) else #[] end; values(foreground, background, font) end method widget-attributes; // */ define method do-compose-space (gadget :: , #key width, height) => (space-req :: ) // debug-message("do-compose-space(%= , %d, %d)", gadget, width, height); let mirror = sheet-direct-mirror(gadget); if (mirror) let widget = GTK-WIDGET(mirror-widget(mirror)); gtk-space-requirements(gadget, widget) else gtk-debug("Composing space on an unmirrored gadget!"); default-space-requirement(gadget, width: width, height: height) end end method do-compose-space; // We take the values suggested by GTK as the default sizes define method gtk-space-requirements (gadget :: , widget :: ) => (space-req :: ) let (width, height) = widget-size(widget); let max-width = if (gadget.%gtk-fixed-width?) width else $fill end; let max-height = if (gadget.%gtk-fixed-height?) height else $fill end; make(, min-width: width, width: width, max-width: max-width, min-height: height, height: height, max-height: max-height) end method gtk-space-requirements; define method widget-size (widget :: ) => (width :: , height :: ) with-stack-structure (request :: ) gtk-widget-size-request(widget, request); values(request.GtkRequisition-width, request.GtkRequisition-height) end end method widget-size; define sealed method defaulted-gadget-label (gadget :: ) => (label) gadget-label(gadget) | $default-label end method defaulted-gadget-label; define sealed method note-gadget-label-changed (gadget :: ) => () next-method(); let mirror = sheet-direct-mirror(gadget); mirror & update-mirror-label(gadget, mirror) end method note-gadget-label-changed; define sealed method update-mirror-label (gadget :: , mirror :: ) => () let widget = mirror-widget(sheet-direct-mirror(gadget)); let label = defaulted-gadget-label(gadget); let label :: = if (instance?(label, )) label else "" end; // xt/XtSetValues(widget, label-string: label) ignoring("update-mirror-label") end method update-mirror-label; define sealed method text-or-image-from-gadget-label (gadget :: ) => (text :: false-or(), image :: false-or(), mnemonic :: false-or(), index :: false-or()); let label = defaulted-gadget-label(gadget); let (label, mnemonic, index) = compute-mnemonic-from-label(gadget, label); let mnemonic = mnemonic & as-uppercase(gesture-character(mnemonic)); select (label by instance?) => values(add-gadget-label-postfix(gadget, label), #f, mnemonic, index); /*---*** Not ready yet! , => values(if (mnemonic) as(, vector(mnemonic)) else "" end, label, mnemonic, index); */ => //---*** Decode the image and return a pixmap or something values("", #f, mnemonic, index); end end method text-or-image-from-gadget-label; define sealed method note-gadget-enabled (client, gadget :: ) => () ignore(client); next-method(); let widget = GTK-WIDGET(gadget-widget(gadget)); gtk-widget-set-sensitive(widget, $true) end method note-gadget-enabled; define sealed method note-gadget-disabled (client, gadget :: ) => () ignore(client); next-method(); let widget = GTK-WIDGET(gadget-widget(gadget)); gtk-widget-set-sensitive(widget, $false) end method note-gadget-disabled; //---*** DO WE NEED THIS? define sealed method activate-gtk-gadget (gadget :: ) => (activated? :: ) when (gadget-activate-callback(gadget)) distribute-activate-callback(gadget); #t end end method activate-gtk-gadget; //---*** DO WE NEED THIS? define sealed method activate-gtk-gadget (gadget :: ) => (activated? :: ) handle-text-gadget-changed(gadget); next-method() end method activate-gtk-gadget; /// Exit, cancel, default button, etc. /*---*** Do we need any of this? define method handle-command-for-id (sheet :: , id :: ) => (handled? :: ) let frame = sheet-frame(sheet); select (id) $IDOK => duim-debug-message("Handling IDOK for %=", sheet); activate-default-button(frame); $IDCANCEL => duim-debug-message("Handling IDCANCEL for %=", sheet); handle-cancel(frame); otherwise => let gadget = id->gadget(sheet, id); if (gadget) handle-gadget-activation(gadget) else handle-id-activation(frame, id) end; end end method handle-command-for-id; define sealed method handle-gadget-activation (gadget :: ) => (handled? :: ) duim-debug-message("Ignoring activation command for gadget %=", gadget); #f end method handle-gadget-activation; // This handles IDOK commands for more than just buttons... define method activate-default-button (frame :: ) => (activated? :: ) let gadget = gtk-sheet-with-focus(); duim-debug-message(" Handling IDOK: focus currently %=", gadget); let activated? = instance?(gadget, ) & gadget-enabled?(gadget) & activate-gtk-gadget(gadget); // If we didn't activate the gadget, try to activate the default button unless (activated?) let button = frame-default-button(frame); // Don't activate an upmapped or disabled default button... when (button & sheet-mapped?(button) & gadget-enabled?(button)) handle-gadget-activation(button) end end end method activate-default-button; define function gtk-sheet-with-focus () => (sheet :: false-or()) let handle = GetFocus(); let mirror = gadget-mirror(handle); when (mirror) let sheet = mirror-sheet(mirror); if (instance?(sheet, )) subgadget-owner(sheet) else sheet end end end function gtk-sheet-with-focus; define function handle-cancel (frame :: ) => (handled? :: ) let gadget = gtk-sheet-with-focus(); duim-debug-message(" Handling IDCANCEL: focus currently %=", gadget); if (instance?(gadget, ) & cancel-gadget(gadget)) #t else cancel-frame(frame) end end function handle-cancel; define sealed method cancel-frame (frame :: ) => (handled? :: ) //---*** We should handle ESCAPE as canceling popups by default, //---*** for example in combo boxes. #f end method cancel-frame; define sealed method cancel-gadget (gadget :: ) => (handled? :: ) #f end method cancel-gadget; */ //---*** What do we do about setting the color and font of a gadget? /// Labels define sealed class (,