.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.42) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Widgets::Tutorial::Creation 3pm" .TH Widgets::Tutorial::Creation 3pm "2022-06-12" "perl v5.34.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Curses::Widget::Tutorial::Creation \-\- Widget Creation Tutorial .SH "POD VERSION" .IX Header "POD VERSION" \&\f(CW$Id:\fR Creation.pod,v 0.3 2002/11/04 00:45:06 corliss Exp corliss $ .SH "DESCRIPTION" .IX Header "DESCRIPTION" Creating a custom widget is as easy as creating a descendant class of \&\fBCurses::Widget\fR and defining as few as four methods: .PP .Vb 10 \& Method Purpose \& ==================================================== \& _conf Validates configurations options and \& initialises the internal state/data \& _content Renders the widget according to the \& current state \& _cursor Renders the widget cursor according to the \& current state \& input_key Updates the state information according \& to the passed character input .Ve .SS "\s-1BASIC MODULE STRUCTURE\s0" .IX Subsection "BASIC MODULE STRUCTURE" A decent code template for custom widgets would start with the following (we'll call our new widget \fBMyWidget\fR): .PP .Vb 1 \& package MyWidget; \& \& use strict; \& use vars qw($VERSION @ISA); \& use Curses; \& use Curses::Widget; \& \& ($VERSION) = (q$Revision: 0.3 $ =~ /(\ed+(?:\e.(\ed+))+)/); \& @ISA = qw(Curses::Widget); .Ve .PP Please note that the \fBuse Curses::Widget;\fR statment provides more than just a base class to inherit methods from, it also imports standard functions for use in the module: .PP .Vb 11 \& Function Purpose \& =========================================================== \& select_colour Initialises new colour pairs, and returns \& the appropriate colour pair number, for use \& with $wh\->attrset(COLOR_PAIR($n)) calls. \& select_color, the American English spelling, \& also works. \& scankey This blocks until a key is pressed, and that \& key returned. \& textwrap Splits the text given into lines no longer \& than the column limit specified. .Ve .PP See the \fBCurses::Widget\fR pod for the specific syntax. .PP Descendent classes will automatically know the following fields (as used by the \fBnew\fR or \fBget/setField\fR methods): .PP .Vb 12 \& Field Type Description \& =========================================================== \& Y int Y coordinate of upper left corner of widget \& X int X coordinate of upper left corner of widget \& LINES int Number of lines in the content area of the widget \& COLUMNS int Number of columsn inthe content area \& BORDER boolean Whether to surround the widget with a box \& CAPTION string Caption to display on top of border \& FOREGROUND string Default foreground colour \& BACKGROUND string Default background colour \& BORDERCOL string Default border foreground colour \& CAPTIONCOL string Default caption foreground colour .Ve .PP The colours, if not specified during widget instantiation, will default to the colours in colour pair 0 (the terminal default). Borders will only be drawn if \s-1BORDER\s0 is true, and that decision is made in the default \fB_border\fR method, not in the \fBdraw\fR method. The \fB_caption\fR method also decides internally whether or not to draw itself according to the value of \s-1BORDER.\s0 .SS "\s-1METHOD SEMANTICS\s0" .IX Subsection "METHOD SEMANTICS" The _conf method is called by the class constructor (provided by \&\fBCurses::Widget\fR, unless you override it here as well). Widget objects should be created with all configuration options passed in a hash ref: .PP .Vb 5 \& $widget = Curses::Widget::MyWidget\->new({ \& OPTION1 => $value1, \& OPTION2 => $value2, \& [. . .] \& }); .Ve .PP The configuration hash is dereferenced and passed as arguments to the _conf method inside of the \fBnew\fR constructor: .PP .Vb 1 \& $rv = $self\->_conf(%$conf); .Ve .PP Because of this, the _conf method should probably begin along these lines: .PP .Vb 9 \& sub _conf { \& my $self = shift; \& my %conf = ( \& OPTION1 => default1, \& OPTION2 => default2, \& [. . .], \& @_ \& ); \& my $err = 0; \& \& # Validate and initialise the widget\*(Aqs state \& # and store in the %conf hash \& \& # Always include the following \& $err = 1 unless $self\->SUPER::_conf(%conf); \& \& return ($err == 0) ? 1 : 0; \& } .Ve .PP You should perform any initialisation and validation of the configuration options here. This routine is expected to return a true or false value, depending on whether or not any critical errors were found. A false value will prevent the \fBnew\fR constructor from returning an object reference, causing the instantiation request to fail. .PP The last two lines of code should always be included in this subroutine. The call to the parent class' _conf method stores the final initialised state information in \f(CW%conf\fR in the object field \fB\s-1CONF\s0\fR, after initialising many of the standard colour fields, should they have been left undefined. You can retrieve and update the state information via \f(CW$self\fR\->{\s-1CONF\s0}. A copy of that state information will be stored in \f(CW$self\fR\->{\s-1OCONF\s0}, and can be restored with a call to \fBreset\fR, a method provided by \fBCurses::Widgets\fR. .PP The second method you should override is the \fB_content\fR method. This method, as mentioned above, is responsible for rendering the widget according to its state information. This method should handle one arguments: .PP .Vb 1 \& $widget\->_content($cwh); .Ve .PP The argument will be a window handle to the \fIcontent area\fR of the widget. You should always layout your widget with the upper left corner as (0, 0), since the \fBdraw\fR method is responsible for allocating any extra space needed for borders and captions. .PP If your widget doesn't support borders and/or captions you can do one of two things: override those methods (\fB_border\fR and \fB_caption\fR) to immediately return without doing anything, or override the \fBdraw\fR method to exclude those calls. Typically, the former method of handling this would be preferred. .PP The third method you need to override is the \fB_cursor\fR method. This accepts the same window handle as the \fB_content\fR method. The default \fBdraw\fR method will only call this method if it was called with a true \fIactive\fR argument. .PP Neither of these two methods will need to allocate, refresh, or destroy window handles, just print the content. The windows will already be erased and initialised to specified foreground/background pairs, and those settings saved via the \fB_save\fR method. If at any time you need to reset the window handle's current cursor back to those settings you can call \fB_restore\fR: .PP .Vb 1 \& $self\->_restore($dwh); .Ve .PP In fact, in order to make the state of the window handle more predictable for descendent classes you should probably call _restore at the end of each of these methods. .PP The final method that should be overridden is the input_key method. This expects a single argument, that being the keystroke captured by the keyboard scanning function. It uses that value to update (if it's not rejected) the widget's state information. A rough skeleton for this function would be as follows: .PP .Vb 4 \& sub input_key { \& my $self = shift; \& my $key = shift; \& my $conf = $self\->{CONF}; \& \& # validate/update state information \& } .Ve .SS "\s-1CONCLUSION\s0" .IX Subsection "CONCLUSION" That, in a nutshell, is all there is to creating a custom widget. For a working example which uses the structure noted above, look at the TextField or ButtonSet widgets. Both consist of nothing more than the routines listed above. .SH "HISTORY" .IX Header "HISTORY" 2001/07/07 \*(-- First draft. 2002/11/01 \*(-- Updated for reworked internals. .SH "AUTHOR/COPYRIGHT" .IX Header "AUTHOR/COPYRIGHT" (c) 2001 Arthur Corliss (corliss@digitalmages.com),