$VERSION
=
'0.68'
;
Construct Tk::Widget
'CodeText'
;
my
@defaultattributes
= (
'Alert'
=> [
-background
=>
'#DB7C47'
,
-foreground
=>
'#FFFFFF'
],
'Annotation'
=> [
-foreground
=>
'#5A5A5A'
],
'Attribute'
=> [
-foreground
=>
'#00B900'
,
-weight
=>
'bold'
],
'BaseN'
=> [
-foreground
=>
'#0000A9'
],
'BuiltIn'
=> [
-foreground
=>
'#B500E6'
],
'Char'
=> [
-foreground
=>
'#FF00FF'
],
'Comment'
=> [
foreground
=>
'#5A5A5A'
,
-slant
=>
'italic'
],
'CommentVar'
=> [
-foreground
=>
'#5A5A5A'
,
-slant
=>
'italic'
,
-weight
=>
'bold'
],
'Constant'
=> [
-foreground
=>
'#0000FF'
,
-weight
=>
'bold'
],
'ControlFlow'
=> [
-foreground
=>
'#0062AD'
],
'DataType'
=> [
-foreground
=>
'#0080A8'
,
-weight
=>
'bold'
],
'DecVal'
=> [
-foreground
=>
'#9C4E2B'
],
'Documentation'
=> [
-foreground
=>
'#7F5A41'
,
-slant
=>
'italic'
],
'Error'
=> [
-background
=>
'#FF0000'
,
-foreground
=>
'#FFFF00'
],
'Extension'
=> [
-foreground
=>
'#9A53D1'
],
'Float'
=> [
-foreground
=>
'#9C4E2B'
,
-weight
=>
'bold'
],
'Function'
=> [
-foreground
=>
'#008A00'
],
'Import'
=> [
-foreground
=>
'#950000'
,
-slate
=>
'italic'
],
'Information'
=> [
foreground
=>
'#5A5A5A'
,
-weight
=>
'bold'
],
'Keyword'
=> [
-weight
=>
'bold'
],
'Normal'
=> [],
'Operator'
=> [
-foreground
=>
'#85530E'
],
'Others'
=> [
-foreground
=>
'#FF6200'
],
'Preprocessor'
=> [
-slant
=>
'italic'
],
'RegionMarker'
=> [
-background
=>
'#00CFFF'
],
'SpecialChar'
=> [
-foreground
=>
'#9A53D1'
],
'SpecialString'
=> [
-foreground
=>
'#FF4449'
],
'String'
=> [
-foreground
=>
'#FF0000'
],
'Variable'
=> [
-foreground
=>
'#0000FF'
,
-weight
=>
'bold'
],
'VerbatimString'
=> [
-foreground
=>
'#FF4449'
,
-weight
=>
'bold'
],
'Warning'
=> [
-background
=>
'#FFFF00'
,
-foreground
=>
'#FF0000'
],
);
my
$minusimg
= '
static unsigned char indicatorclose_bits[] = {
0xff, 0x07, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0xfd, 0x05,
0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0xff, 0x07 };
';
my
$plusimg
= '
static unsigned char indicatoropen_bits[] = {
0xff, 0x07, 0x01, 0x04, 0x21, 0x04, 0x21, 0x04, 0x21, 0x04, 0xfd, 0x05,
0x21, 0x04, 0x21, 0x04, 0x21, 0x04, 0x01, 0x04, 0xff, 0x07 };
';
sub
Populate {
my
(
$self
,
$args
) =
@_
;
my
$scrollbars
=
delete
$args
->{
'-scrollbars'
};
$scrollbars
=
'soe'
unless
defined
$scrollbars
;
my
$theme
=
delete
$args
->{
'-theme'
};
unless
(
defined
$theme
) {
$theme
= Tk::CodeText::Theme->new;
$theme
->put(
@defaultattributes
);
}
my
@ko
= (
formatter
=> [
'Base'
,
foldingdepth
=>
'all'
,
],
);
my
$xmldir
=
delete
$args
->{
'-xmlfolder'
};
push
@ko
,
'xmlfolder'
,
$xmldir
if
defined
$xmldir
;
$self
->SUPER::Populate(
$args
);
$self
->{COLORINF} = [];
$self
->{COLORED} = 1;
$self
->{FOLDBUTTONS} = {};
$self
->{FOLDINF} = [];
$self
->{FOLDSSHOWN} = [];
$self
->{FOLDSVISIBLE} = 0;
$self
->{KAMELON} = Tk::CodeText::Kamelon->new(
$self
,
@ko
);
$self
->{HIGHLIGHTINTERVAL} = 1;
$self
->{LINESPERCYCLE} = 10;
$self
->{LOOPACTIVE} = 0;
$self
->{NOHIGHLIGHTING} = 1;
$self
->{NUMBERSVISIBLE} = 0;
$self
->{NUMBERINF} = [];
$self
->{POSTCONFIG} = 0;
$self
->{SHOWSPACES} = 0;
$self
->{SPACESCOMPLETED} = 1;
$self
->{SPACESLOOPACTIVE} = 0;
$self
->{STATUSVISIBLE} = 0;
$self
->{SYNTAX} =
'None'
;
$self
->{THEME} =
$theme
;
$self
->{SAVEFIRSTVISIBLE} = 1;
$self
->{SAVELASTVISIBLE} = 1;
my
$ef
=
$self
->Frame(
-relief
=>
'sunken'
,
-borderwidth
=> 2,
)->
pack
(
-expand
=> 1,
-fill
=>
'both'
,
);
my
$numbers
=
$ef
->Frame(
-width
=> 40,
);
my
$folds
=
$ef
->Frame(
-width
=> 18,
);
$folds
->
bind
(
'<ButtonRelease-3>'
, [
$self
,
'foldsMenuPop'
, Ev(
'X'
), Ev(
'Y'
)]);
my
$fmenu
=
$folds
->Menu(
-tearoff
=> 0,
-menuitems
=> [
[
command
=>
'Collapse All'
,
-command
=> [
'foldCollapseAll'
,
$self
]],
[
command
=>
'Expand All'
,
-command
=> [
'foldExpandAll'
,
$self
]],
],
);
$fmenu
->
bind
(
'<Leave>'
, [
$fmenu
,
'unpost'
]);
my
@opt
= (
-escapepressed
=> [
'FindClose'
,
$self
],
-findandreplacecall
=>
sub
{
$self
->FindAndOrReplace(
@_
) },
-modifycall
=> [
'OnModify'
,
$self
],
-relief
=>
'flat'
,
-scrollbars
=>
$scrollbars
,
-yscrollcmd
=>
sub
{
$self
->foldsCheck;
$self
->lnumberCheck;
$self
->bookmarkCheck;
},
);
my
$text
;
if
(
$scrollbars
eq
''
) {
$text
=
$ef
->XText(
@opt
)
}
else
{
$text
=
$ef
->Scrolled(
'XText'
,
@opt
)
}
$text
->
pack
(
-side
=>
'left'
,
-expand
=>1,
-fill
=>
'both'
);
my
@pack
= (
-side
=>
'left'
,
-padx
=> 2,
-pady
=> 2);
my
$sandr
=
$self
->Frame;
$self
->Advertise(
SandR
=>
$sandr
);
my
$case
=
'-case'
;
my
$find
=
''
;
my
$reg
=
'-exact'
;
my
$replace
=
''
;
my
$rframe
;
my
$sframe
=
$sandr
->Frame->
pack
(
-fill
=>
'x'
);
$sframe
->Label(
-anchor
=>
'e'
,
-text
=>
'Find'
,
-width
=> 7,
)->
pack
(
@pack
);
my
$e
=
$sframe
->Entry(
-textvariable
=> \
$find
,
)->
pack
(
@pack
,
-expand
=> 1,
-fill
=>
'x'
);
$e
->
bind
(
'<Escape>'
, [
$self
,
'FindClose'
]);
$e
->
bind
(
'<Return>'
,
sub
{
$self
->FindNext(
'-forward'
,
$reg
,
$case
,
$find
) });
$sframe
->Button(
-text
=>
'Next'
,
-command
=>
sub
{
$self
->FindNext(
'-forward'
,
$reg
,
$case
,
$find
) },
)->
pack
(
@pack
);
$sframe
->Button(
-text
=>
'Previous'
,
-command
=>
sub
{
$self
->FindNext(
'-backward'
,
$reg
,
$case
,
$find
) },
)->
pack
(
@pack
);
$sframe
->Button(
-text
=>
'All'
,
-command
=>
sub
{
$self
->FindAll(
$reg
,
$case
,
$find
) },
)->
pack
(
@pack
);
$sframe
->Button(
-text
=>
'Clear'
,
-command
=>
sub
{
$self
->FindClear },
)->
pack
(
@pack
);
$sframe
->Checkbutton(
-text
=>
'Case'
,
-onvalue
=>
'-case'
,
-offvalue
=>
'-nocase'
,
-variable
=> \
$case
,
)->
pack
(
@pack
);
$sframe
->Checkbutton(
-text
=>
'Reg'
,
-onvalue
=>
'-regexp'
,
-offvalue
=>
'-exact'
,
-variable
=> \
$reg
,
)->
pack
(
@pack
);
$sframe
->Button(
-text
=>
'Close'
,
-command
=> [
'FindClose'
,
$self
],
)->
pack
(
@pack
);
$rframe
=
$sandr
->Frame;
$rframe
->Label(
-anchor
=>
'e'
,
-text
=>
'Replace'
,
-width
=> 7,
)->
pack
(
@pack
);
$self
->Advertise(
Replace
=>
$rframe
);
my
$r
=
$rframe
->Entry(
-textvariable
=> \
$replace
,
)->
pack
(
@pack
,
-expand
=> 1,
-fill
=>
'x'
);
$r
->
bind
(
'<Escape>'
, [
$self
,
'FindClose'
]);
$r
->
bind
(
'<Return>'
,
sub
{
$self
->ReplaceSelectionsWith(
$replace
)
if
$self
->SelectionExists;
$self
->FindNext(
'-forward'
,
$reg
,
$case
,
$find
);
});
$rframe
->Button(
-text
=>
'Replace'
,
-command
=>
sub
{
$self
->FindandReplace(
$reg
,
$case
,
$find
,
$replace
) },
)->
pack
(
@pack
);
$rframe
->Button(
-text
=>
'Skip'
,
-command
=>
sub
{
$self
->FindNext(
'-forward'
,
$reg
,
$case
,
$find
) },
)->
pack
(
@pack
);
$rframe
->Button(
-text
=>
'Replace all'
,
-command
=>
sub
{
$self
->FindandReplaceAll(
$reg
,
$case
,
$find
,
$replace
) },
)->
pack
(
@pack
);
my
$statusbar
=
$self
->StatusBar(
-widget
=>
$self
,
);
$self
->
after
(10, [
'updateStatus'
,
$statusbar
]);
$self
->Advertise(
XText
=>
$text
);
$self
->Advertise(
Numbers
=>
$numbers
);
$self
->Advertise(
Folds
=>
$folds
);
$self
->Advertise(
Statusbar
=>
$statusbar
);
$self
->Advertise(
Foldsmenu
=>
$fmenu
);
$self
->Advertise(
FindEntry
=>
$e
);
my
$l
=
$self
->Label;
my
$fg
=
$l
->cget(
'-foreground'
);
$l
->destroy;
$text
->tagConfigure(
'Hidden'
,
-elide
=> 1);
$text
->tagConfigure(
'Space'
,
-background
=>
'blue'
);
$text
->tagConfigure(
'Tab'
,
-background
=>
'blue'
);
$self
->ConfigSpecs(
-bookmarkcolor
=> [
qw/PASSIVE bookmarkColor BookmarkColor/
,
'#71D0CC'
],
-bookmarksize
=> [
qw/PASSIVE bookmarkSize BookmarkSize/
, 20],
-configdir
=> [
qw/PASSIVE configdir ConfigDir/
,
''
],
-font
=> [
qw/METHOD font Font/
,
'Monospace 10'
],
-highlightinterval
=> [
qw/METHOD highlightInterval HighlightInterval/
, 1],
-linespercycle
=> [
qw/METHOD linesPerCycle LinesPerCycle/
, 10],
-minusimg
=> [
'PASSIVE'
,
undef
,
undef
,
$self
->Bitmap(
-data
=>
$minusimg
,
-foreground
=>
$fg
,
)],
-modifiedcall
=> [
'CALLBACK'
,
undef
,
undef
,
sub
{}],
-plusimg
=> [
'PASSIVE'
,
undef
,
undef
,
$self
->Bitmap(
-data
=>
$plusimg
,
-foreground
=>
$fg
,
)],
-position
=> [
'METHOD'
],
-saveimage
=> [
$statusbar
],
-showfolds
=> [
qw/METHOD showFolds ShowFolds/
, 1],
-shownumbers
=> [
qw/METHOD showNumers ShowNumbers/
, 1],
-showspaces
=> [
qw/METHOD showSpaces ShowSpaces/
, 0],
-showstatus
=> [
qw/METHOD showStatus ShowStatus/
, 1],
-syntax
=> [
qw/METHOD syntax Syntax/
,
'None'
],
-statusinterval
=> [
$statusbar
],
-spacebackground
=> [
qw/METHOD spaceBackground SpaceBackground/
,
'#0098C2'
],
-tabbackground
=> [
qw/METHOD tabBackground TabBackground/
,
'#B5C200'
],
-themefile
=> [
'METHOD'
],
DEFAULT
=> [
$text
],
);
$self
->Delegates(
DEFAULT
=>
$text
,
);
$self
->
after
(10,
sub
{
$self
->{POSTCONFIG} = 1;
$self
->themeUpdate;
$self
->lnumberCheck(1);
});
}
sub
bookmarkAdd {
my
(
$self
,
$line
) =
@_
;
$line
=
$self
->linenumber(
'insert'
)
unless
defined
$line
;
return
if
$self
->bookmarked(
$line
);
$self
->tagAdd(
'BOOKMARK'
,
"$line.0"
,
"$line.0 lineend"
);
}
sub
bookmarkCheck {
my
$self
=
shift
;
my
$numframe
=
$self
->Subwidget(
'Numbers'
);
my
$nbg
=
$numframe
->cget(
'-background'
);
my
$bbg
=
$self
->cget(
'-bookmarkcolor'
);
my
$nimf
=
$self
->{NUMBERINF};
for
(
@$nimf
) {
my
$lab
=
$_
;
my
$line
=
$lab
->cget(
'-text'
);
if
(
$self
->bookmarked(
$line
)) {
$lab
->configure(
'-background'
,
$bbg
);
}
else
{
$lab
->configure(
'-background'
,
$nbg
);
}
}
}
sub
bookmarked {
my
(
$self
,
$line
) =
@_
;
my
@range
=
$self
->tagNextrange(
'BOOKMARK'
,
"$line.0"
,
"$line.0 lineend"
);
return
@range
eq 2
}
sub
bookmarkGo {
my
(
$self
,
$line
) =
@_
;
return
unless
$self
->bookmarked(
$line
);
$self
->goTo(
"$line.0"
);
}
sub
bookmarkList {
my
$self
=
shift
;
my
@list
= ();
my
@ranges
=
$self
->tagRanges(
'BOOKMARK'
);
while
(
@ranges
) {
my
$begin
=
shift
@ranges
;
push
@list
,
$self
->linenumber(
$begin
);
shift
@ranges
;
}
return
@list
}
sub
bookmarkMenuItems {
my
$self
=
shift
;
my
@items
= (
[
command
=>
'~Add bookmark'
,
-command
=> [
'bookmarkNew'
,
$self
],
],
[
command
=>
'~Remove bookmark'
,
-command
=> [
'bookmarkRemove'
,
$self
],
],
[
command
=>
'~Remove all bookmarks'
,
-command
=> [
'bookmarkRemoveAll'
,
$self
],
],
[
separator
=>
''
],
[
command
=>
'~Next bookmark'
,
-command
=> [
'bookmarkNext'
,
$self
],
],
[
command
=>
'~Previous bookmark'
,
-command
=> [
'bookmarkPrev'
,
$self
],
],
[
separator
=>
''
],
);
return
@items
}
sub
bookmarkMenuPop {
my
(
$self
,
$menu
,
$bmentry
) =
@_
;
my
$submenu
;
for
(0 ..
$menu
->
index
(
'end'
)) {
if
(
$menu
->type(
$_
) eq
'cascade'
) {
my
$label
=
$menu
->entrycget(
$_
,
'-label'
);
if
(
$label
eq
$bmentry
) {
$submenu
=
$menu
->entrycget(
$_
,
'-menu'
);
last
;
}
}
}
if
(
defined
$submenu
) {
my
$first
;
for
(0 ..
$submenu
->
index
(
'end'
)) {
next
unless
$submenu
->type(
$_
) eq
'command'
;
my
$label
=
$submenu
->entrycget(
$_
,
'-label'
);
if
(
$label
=~ /^\d+/) {
$first
=
$_
;
last
;
}
}
$submenu
->
delete
(
$first
,
'end'
)
if
defined
$first
;
my
@bookmarks
=
$self
->bookmarkList;
for
(
@bookmarks
) {
my
$mark
=
$_
;
$submenu
->add(
'command'
,
-command
=>
sub
{
$self
->bookmarkGo(
$mark
) },
-label
=>
"$mark - "
.
$self
->bookmarkText(
$mark
),
);
}
}
else
{
warn
"Submenu $bmentry not found"
}
}
sub
bookmarkNew {
my
$self
=
shift
;
$self
->bookmarkAdd(
@_
);
$self
->bookmarkCheck;
}
sub
bookmarkNext {
my
(
$self
,
$line
) =
@_
;
$line
=
$self
->linenumber(
'insert'
)
unless
defined
$line
;
my
@list
=
$self
->bookmarkList;
for
(
@list
) {
my
$next
=
$_
;
if
(
$next
>
$line
) {
$self
->bookmarkGo(
$next
);
return
}
}
}
sub
bookmarkPrev {
my
(
$self
,
$line
) =
@_
;
$line
=
$self
->linenumber(
'insert'
)
unless
defined
$line
;
my
@list
=
$self
->bookmarkList;
for
(
reverse
@list
) {
my
$prev
=
$_
;
if
(
$prev
<
$line
) {
$self
->bookmarkGo(
$prev
);
return
}
}
}
sub
bookmarkRemove {
my
$self
=
shift
;
$self
->bookmarkRemoveForce(
@_
);
$self
->bookmarkCheck;
}
sub
bookmarkRemoveAll {
my
$self
=
shift
;
my
@list
=
$self
->bookmarkList;
for
(
@list
) {
$self
->bookmarkRemove(
$_
);
}
$self
->bookmarkCheck;
}
sub
bookmarkRemoveForce {
my
(
$self
,
$line
) =
@_
;
$line
=
$self
->linenumber(
'insert'
)
unless
defined
$line
;
return
unless
$self
->bookmarked(
$line
);
$self
->tagRemove(
'BOOKMARK'
,
"$line.0"
,
"$line.0 lineend"
);
}
sub
bookmarkText {
my
(
$self
,
$line
) =
@_
;
my
$text
=
$self
->get(
"$line.0"
,
"$line.0 lineend"
);
$text
=~ s/^\s+//;
my
$max
=
$self
->cget(
'-bookmarksize'
);
$text
=
substr
(
$text
, 0,
$max
)
if
length
(
$text
) >
$max
;
return
$text
}
sub
clear {
my
$self
=
shift
;
$self
->Subwidget(
'XText'
)->clear;
$self
->Kamelon->Reset;
$self
->configure(
-syntax
=>
'None'
);
}
sub
Colored {
my
$self
=
shift
;
$self
->{COLORED} =
shift
if
@_
;
return
$self
->{COLORED}
}
sub
ColorInf {
my
$self
=
shift
;
$self
->{COLORINF} =
shift
if
@_
;
return
$self
->{COLORINF}
}
sub
contentCheck {
my
$self
=
shift
;
$self
->lnumberCheck;
$self
->bookmarkCheck;
}
sub
FindAndOrReplace {
my
(
$self
,
$flag
) =
@_
;
my
$geosave
=
$self
->toplevel->geometry;
my
$sandr
=
$self
->Subwidget(
'SandR'
);
if
(
$flag
) {
$self
->Subwidget(
'Replace'
)->packForget
}
else
{
$self
->Subwidget(
'Replace'
)->
pack
(
-fill
=>
'x'
,
);
}
$sandr
->
pack
(
-fill
=>
'x'
,
-before
=>
$self
->Subwidget(
'Statusbar'
),
);
$self
->Subwidget(
'FindEntry'
)->focus;
$self
->toplevel->geometry(
$geosave
);
}
sub
FindClose {
my
$self
=
shift
;
$self
->FindClear;
$self
->Subwidget(
'XText'
)->focus;
$self
->Subwidget(
'SandR'
)->packForget;
$self
->tagRemove(
'Find'
,
'1.0'
,
'end'
);
}
sub
fixIndent {
my
(
$self
,
$icon
) =
@_
;
my
(
$begin
,
$end
) =
$self
->getRange;
my
@padding
= (
-padx
=> 10,
-pady
=> 10);
my
$q
=
$self
->{POPSPACESPERTABS};
unless
(
defined
$q
) {
$q
=
$self
->YADialog(
-title
=>
'Fix indent'
,
-buttons
=> [
qw(Ok Cancel)
],
);
$q
->Label(
-image
=>
$icon
)->
pack
(
-side
=>
'left'
,
@padding
)
if
defined
$icon
;
my
$f
=
$q
->Frame->
pack
(
-side
=>
'left'
,
@padding
);
$f
->Label(
-anchor
=>
'w'
,
-text
=>
'Spaces per tab'
,
)->
pack
(
-fill
=>
'x'
,
-padx
=> 2,
-pady
=> 2);
my
$e
=
$f
->Entry->
pack
(
-fill
=>
'x'
,
-padx
=> 2,
-pady
=> 2);
$self
->{POPENTRY} =
$e
;
$e
->focus;
$e
->
bind
(
'<Return>'
,
sub
{
$q
->{PRESSED} =
'Ok'
});
$self
->{POPSPACESPERTABS} =
$q
;
}
my
$answer
=
$q
->Show(
-popover
=>
$self
->toplevel);
if
(
$answer
eq
'Ok'
) {
my
$spaces_per_tab
=
$self
->{POPENTRY}->get;
return
unless
$spaces_per_tab
=~ /^\d+$/;
for
(
$begin
..
$end
) {
my
$line
=
$_
;
my
$b
=
$self
->
index
(
"$line.0"
);
my
$e
=
$self
->
index
(
"$line.0 lineend"
);
my
$text
=
$self
->get(
$b
,
$e
);
if
(
$text
=~ /^([\s|\t]+)/) {
my
$spaces
= $1;
my
$s
= 0;
my
$pos
= 0;
my
$itext
=
''
;
$itext
=
"$itext "
while
length
(
$itext
) ne
$spaces_per_tab
;
while
(
$spaces
ne
''
) {
my
$char
=
substr
$spaces
, 0, 1,
''
;
if
(
$self
->cget(
'-indentstyle'
) eq
'tab'
) {
if
(
$char
eq
"\t"
) {
$s
= 0;
}
else
{
$s
++;
if
(
$s
eq
$spaces_per_tab
) {
my
$linepos
=
$self
->
index
(
"$b + $pos c"
);
$self
->replace(
$linepos
,
"$linepos + $s c"
,
"\t"
);
$s
= 0;
$pos
++;
}
}
}
else
{
if
(
$char
eq
"\t"
) {
my
$linepos
=
$self
->
index
(
"$b + $pos c"
);
$self
->replace(
$linepos
,
"$linepos + 1 c"
,
$itext
);
$pos
=
$pos
+
length
(
$itext
) - 1;
}
$pos
++
}
}
}
}
}
}
sub
foldButton {
my
(
$self
,
$line
) =
@_
;
my
$folds
=
$self
->Kamelon->Formatter->Folds;
my
$fbuttons
=
$self
->FoldButtons;
unless
(
exists
$fbuttons
->{
$line
}) {
my
$data
=
$folds
->{
$line
};
my
@opt
= ();
my
$state
;
if
(
$self
->isHidden(
$line
+ 1)) {
push
@opt
,
-image
=>
$self
->cget(
'-plusimg'
);
$state
=
'collapsed'
;
}
else
{
push
@opt
,
-image
=>
$self
->cget(
'-minusimg'
);
$state
=
'expanded'
;
}
my
$b
=
$self
->Subwidget(
'Folds'
)->Button(
@opt
,
-command
=> [
'foldFlip'
,
$self
,
$line
],
-relief
=>
'flat'
,
);
$fbuttons
->{
$line
} = {
button
=>
$b
,
data
=>
$data
,
state
=>
$state
,
};
}
return
$fbuttons
->{
$line
};
}
sub
FoldButtons {
my
$self
=
shift
;
$self
->{FOLDBUTTONS} =
shift
if
@_
;
return
$self
->{FOLDBUTTONS}
}
sub
foldCollapse {
my
(
$self
,
$line
) =
@_
;
my
$data
=
$self
->FoldButtons->{
$line
};
$data
->{
'state'
} =
'collapsed'
;
$data
->{
'button'
}->configure(
-image
=>
$self
->cget(
'-plusimg'
));
my
$end
=
$data
->{
'data'
}->{
'end'
};
$line
++;
while
(
$line
<=
$end
) {
$self
->hideLine(
$line
);
$line
++;
}
$self
->lnumberCheck;
$self
->foldsCheck;
}
sub
foldCollapseAll {
my
$self
=
shift
;
my
$folds
=
$self
->Kamelon->Formatter->Folds;
for
(
sort
keys
%$folds
) {
$self
->foldButton(
$_
);
$self
->foldCollapse(
$_
);
}
}
sub
foldExpand {
my
(
$self
,
$line
) =
@_
;
my
$data
=
$self
->FoldButtons->{
$line
};
$data
->{
'state'
} =
'expanded'
;
$data
->{
'button'
}->configure(
-image
=>
$self
->cget(
'-minusimg'
));
$self
->lnumberCheck;
my
$end
=
$data
->{
'data'
}->{
'end'
};
$line
++;
while
(
$line
<=
$end
) {
$self
->showLine(
$line
);
my
$nested
=
$self
->FoldButtons->{
$line
};
if
(
defined
$nested
) {
$self
->foldExpand(
$line
)
unless
(
$nested
->{
'state'
} eq
'collapsed'
);
$line
=
$nested
->{
'data'
}->{
'end'
};
$self
->showLine(
$line
);
}
else
{
$line
++
}
}
$self
->foldsCheck;
}
sub
foldExpandAll {
my
$self
=
shift
;
my
$folds
=
$self
->Kamelon->Formatter->Folds;
for
(
sort
keys
%$folds
) {
$self
->foldButton(
$_
);
$self
->foldExpand(
$_
);
}
}
sub
foldFlip {
my
(
$self
,
$line
) =
@_
;
my
$data
=
$self
->FoldButtons->{
$line
};
if
(
$data
->{
'state'
} eq
'collapsed'
) {
$self
->foldExpand(
$line
);
}
elsif
(
$data
->{
'state'
} eq
'expanded'
) {
$self
->foldCollapse(
$line
);
}
}
sub
foldsCheck {
my
$self
=
shift
;
return
unless
$self
->cget(
'-showfolds'
);
my
$line
=
$self
->visualBegin;
my
$last
=
$self
->visualEnd;
return
if
$self
->Colored <
$last
;
my
$folds
=
$self
->Kamelon->Formatter->Folds;
my
$fframe
=
$self
->Subwidget(
'Folds'
);
my
$btns
=
$self
->FoldButtons;
for
(
keys
%$btns
) {
if
((
$_
<
$self
->visualBegin) or (
$_
>
$self
->visualEnd)) {
my
$b
=
delete
$btns
->{
$_
};
$b
->{
'button'
}->destroy;
}
}
my
@shown
= ();
while
(
$line
<=
$last
) {
while
(
$self
->isHidden(
$line
)) {
$line
++ }
if
(
exists
$folds
->{
$line
}) {
my
(
$x
,
$y
,
$wi
,
$he
) =
$self
->dlineinfo(
"$line.0"
);
my
$but
=
$self
->foldButton(
$line
)->{
'button'
};
my
$bh
=
$but
->reqheight;
my
$delta
=
int
((
$he
-
$bh
) / 2);
$but
->place(
-x
=> 0,
-y
=>
$y
+
$delta
);
push
@shown
,
$but
;
}
elsif
(
exists
$btns
->{
$line
}) {
my
$b
=
delete
$btns
->{
$line
};
$b
->{
'button'
}->destroy;
}
else
{
}
$line
++;
}
$self
->{FOLDSSHOWN} = \
@shown
;
}
sub
foldsClear {
my
$self
=
shift
;
my
$shown
=
$self
->{FOLDSSHOWN};
for
(
@$shown
) {
$_
->placeForget;
}
$self
->{FOLDSSHOWN} = [];
}
sub
foldsMenuPop {
my
(
$self
,
$x
,
$y
) =
@_
;
$self
->Subwidget(
'Foldsmenu'
)->post(
$x
- 2,
$y
- 2);
}
sub
font {
my
$self
=
shift
;
my
$xt
=
$self
->Subwidget(
'XText'
);
if
(
@_
) {
my
$new
=
shift
;
$xt
->configure(
'-font'
,
$new
);
my
$inf
=
$self
->{NUMBERINF};
for
(
@$inf
) {
$_
->configure(
'-font'
,
$new
);
}
$self
->update
if
$self
->{POSTCONFIG};
$self
->lnumberCheck(1);
}
return
$xt
->cget(
'-font'
);
}
sub
fontCompose {
my
(
$self
,
$font
,
%options
) =
@_
;
my
$family
=
$self
->fontActual(
$font
,
'-family'
);
my
$size
=
$self
->fontActual(
$font
,
'-size'
);
my
$weight
=
''
;
my
$slant
=
''
;
$slant
=
$options
{
'-slant'
}
if
exists
$options
{
'-slant'
};
$weight
=
$options
{
'-weight'
}
if
exists
$options
{
'-weight'
};
$slant
=
'roman'
if
$slant
eq
''
;
$weight
=
'normal'
if
$weight
eq
''
;
return
$self
->Font(
-family
=>
$family
,
-size
=>
$size
,
-slant
=>
$slant
,
-weight
=>
$weight
,
);
}
sub
getRange {
my
$self
=
shift
;
my
$begin
= 1;
my
$end
=
$self
->linenumber(
'end - 1c'
);
my
@sel
=
$self
->tagRanges(
'sel'
);
if
(
@sel
) {
$begin
=
$self
->linenumber(
shift
@sel
);
$end
=
$self
->linenumber(
shift
@sel
);
}
return
(
$begin
,
$end
);
}
sub
hideLine {
my
(
$self
,
$line
) =
@_
;
$self
->tagAdd(
'Hidden'
,
"$line.0"
,
"$line.0 lineend + 1c"
);
}
sub
highlightCheck {
my
(
$self
,
$pos
) =
@_
;
return
if
$self
->NoHighlighting;
my
$line
=
$self
->linenumber(
$pos
);
my
$colored
=
$self
->Colored;
$self
->highlightPurge(
$line
)
if
$line
<=
$self
->Colored;
}
sub
highlightinterval {
my
$self
=
shift
;
$self
->{HIGHLIGHTINTERVAL} =
shift
if
@_
;
return
$self
->{HIGHLIGHTINTERVAL}
}
sub
highlightLine {
my
(
$self
,
$num
) =
@_
;
my
$kam
=
$self
->Kamelon;
$kam
->LineNumber(
$num
);
my
$xt
=
$self
->Subwidget(
'XText'
);
my
$begin
=
"$num.0"
;
my
$end
=
$xt
->
index
(
"$num.0 lineend + 1c"
);
my
$cli
=
$self
->ColorInf;
my
$k
=
$cli
->[
$num
- 1];
$kam
->StateSet(
@$k
);
my
$txt
=
$xt
->get(
$begin
,
$end
);
if
(
$txt
ne
''
) {
my
$pos
= 0;
my
$start
= 0;
my
@h
=
$kam
->ParseRaw(
$txt
);
while
(
@h
ne 0) {
$start
=
$pos
;
$pos
+=
length
(
shift
@h
);
my
$tag
=
shift
@h
;
$xt
->tagAdd(
$tag
,
"$num.$start"
,
"$num.$pos"
);
};
$xt
->tagRaise(
'Find'
);
$xt
->tagRaise(
'Space'
);
$xt
->tagRaise(
'Tab'
);
$xt
->tagRaise(
'sel'
);
};
$cli
->[
$num
] = [
$kam
->StateGet ];
}
sub
highlightLoop {
my
$self
=
shift
;
if
(
$self
->NoHighlighting) {
$self
->LoopActive(0);
return
}
my
$xt
=
$self
->Subwidget(
'XText'
);
my
$lpc
=
$self
->cget(
'-linespercycle'
);
my
$colored
=
$self
->Colored;
$self
->highlightRemove(
$colored
,
$colored
+
$lpc
);
for
(1 ..
$lpc
) {
my
$colored
=
$self
->Colored;
if
(
$colored
<=
$xt
->linenumber(
'end - 1c'
)) {
$self
->LoopActive(1);
$self
->highlightLine(
$colored
);
$colored
++;
$self
->Colored(
$colored
);
}
else
{
$self
->
after
(100, [
'foldsCheck'
,
$self
]);
$self
->LoopActive(0);
}
last
unless
$self
->LoopActive;
}
$self
->
after
(
$self
->highlightinterval, [
'highlightLoop'
,
$self
])
if
$self
->LoopActive;
}
sub
highlightPurge {
my
(
$self
,
$line
,
$remove
) =
@_
;
$line
= 1
unless
defined
$line
;
$remove
= 0
unless
defined
$remove
;
$self
->highlightRemove(
$line
)
if
$remove
;
$self
->Colored(
$line
);
my
$cli
=
$self
->ColorInf;
if
(
@$cli
) {
splice
(
@$cli
,
$line
) };
my
$folds
=
$self
->Kamelon->Formatter->Folds;
for
(
keys
%$folds
) {
delete
$folds
->{
$_
}
if
$_
>=
$line
}
$self
->highlightLoop
unless
$self
->LoopActive;
}
sub
highlightRemove {
my
(
$self
,
$begin
,
$end
) =
@_
;
$begin
= 1
unless
defined
$begin
;
$end
=
$self
->linenumber(
'end'
)
unless
defined
$end
;
$begin
=
"$begin.0"
;
$end
=
$self
->
index
(
"$end.0 lineend"
);
for
(
$self
->tags) {
$self
->tagRemove(
$_
,
$begin
,
$end
)
}
}
sub
isHidden {
my
(
$self
,
$line
) =
@_
;
my
@names
=
$self
->tagNames(
"$line.0"
);
my
$hit
=
grep
({
$_
eq
'Hidden'
}
@names
);
return
$hit
;
}
sub
Kamelon {
return
$_
[0]->{KAMELON}
}
sub
linespercycle {
my
$self
=
shift
;
$self
->{LINESPERCYCLE} =
shift
if
@_
;
return
$self
->{LINESPERCYCLE}
}
sub
lineVisible {
my
(
$self
,
$line
) =
@_
;
my
$first
=
$self
->visualBegin;
my
$last
=
$self
->visualEnd;
return
((
$line
>=
$first
) and (
$line
<=
$last
))
}
sub
lnumberCheck {
my
(
$self
,
$force
) =
@_
;
$force
= 0
unless
defined
$force
;
my
$line
=
$self
->visualBegin;
my
$last
=
$self
->visualEnd;
my
$sb
=
$self
->SaveFirstVisible;
my
$se
=
$self
->SaveLastVisible;
unless
(
$force
) {
return
if
(
$sb
eq
$line
) and (
$last
eq
$se
);
}
return
unless
$self
->{POSTCONFIG};
return
unless
$self
->cget(
'-shownumbers'
);
$self
->SaveFirstVisible(
$line
);
$self
->SaveLastVisible(
$last
);
my
$widget
=
$self
->Subwidget(
'XText'
);
my
$count
= 0;
my
$font
=
$widget
->cget(
'-font'
);
my
$nimf
=
$self
->{NUMBERINF};
my
$numframe
=
$self
->Subwidget(
'Numbers'
);
while
(
$line
<=
$last
) {
while
(
$self
->isHidden(
$line
)) {
$line
++ }
my
(
$x
,
$y
,
$wi
,
$he
) =
$self
->dlineinfo(
"$line.0"
);
unless
(
defined
$nimf
->[
$count
]) {
my
$l
=
$numframe
->Label(
-justify
=>
'right'
,
-anchor
=>
'ne'
,
-font
=>
$font
,
-borderwidth
=> 0,
);
push
@$nimf
,
$l
;
}
my
$lab
=
$nimf
->[
$count
];
$lab
->configure(
-text
=>
$line
,
-width
=>
length
(
$last
),
);
$lab
->placeForget
if
$lab
->ismapped;
$lab
->place(
-x
=> 0,
-y
=>
$y
);
$line
++;
$count
++;
}
my
$numwidth
=
$nimf
->[
$count
- 1]->reqwidth;
$numframe
->configure(
-width
=>
$numwidth
);
while
(
defined
$nimf
->[
$count
]) {
my
$l
=
pop
@$nimf
;
$l
->placeForget;
$l
->destroy;
}
}
sub
load{
my
(
$self
,
$file
) =
@_
;
if
(
$self
->Subwidget(
'XText'
)->load(
$file
)) {
my
$syntax
=
$self
->Kamelon->SuggestSyntax(
$file
);
$self
->configure(
-syntax
=>
$syntax
)
if
defined
$syntax
;
$self
->
after
(500, [
'contentCheck'
,
$self
]);
return
1
}
return
0
}
sub
LoopActive {
my
$self
=
shift
;
$self
->{LOOPACTIVE} =
shift
if
@_
;
return
$self
->{LOOPACTIVE}
}
sub
NoHighlighting {
my
$self
=
shift
;
$self
->{NOHIGHLIGHTING} =
shift
if
@_
;
return
$self
->{NOHIGHLIGHTING}
}
sub
OnModify {
my
(
$self
,
$index
) =
@_
;
$self
->highlightCheck(
$index
);
$self
->bookmarkCheck;
$self
->spacesCheck(
$index
);
$self
->Callback(
'-modifiedcall'
,
$index
);
}
sub
position {
my
(
$self
,
$pos
) =
@_
;
if
(
defined
$pos
) {
$self
->goTo(
$pos
);
$self
->see(
$pos
);
}
return
$self
->
index
(
'insert'
);
}
sub
removeTrailingSpaces {
my
$self
=
shift
;
my
(
$begin
,
$end
) =
$self
->getRange;
for
(
$begin
..
$end
) {
my
$line
=
$_
;
my
$b
=
$self
->
index
(
"$line.0"
);
my
$e
=
$self
->
index
(
"$line.0 lineend"
);
my
$text
=
$self
->get(
$b
,
$e
);
if
(
$text
=~ /(\s+)$/) {
my
$spaces
= $1;
my
$l
=
length
(
$spaces
);
$self
->
delete
(
"$e - $l c"
,
$e
);
}
}
}
sub
SaveFirstVisible {
my
$self
=
shift
;
$self
->{SAVEFIRSTVISIBLE} =
shift
if
@_
;
return
$self
->{SAVEFIRSTVISIBLE}
}
sub
SaveLastVisible {
my
$self
=
shift
;
$self
->{SAVELASTVISIBLE} =
shift
if
@_
;
return
$self
->{SAVELASTVISIBLE}
}
sub
showfolds {
my
(
$self
,
$flag
) =
@_
;
my
$f
=
$self
->Subwidget(
'Folds'
);
if
(
defined
$flag
) {
if
(
$flag
) {
my
$before
=
$self
->Subwidget(
'XText'
);
$f
->
pack
(
-side
=>
'left'
,
-before
=>
$before
,
-fill
=>
'y'
,
);
$self
->{FOLDSVISIBLE} = 1;
$self
->foldsCheck;
}
else
{
$self
->{FOLDSVISIBLE} = 0;
$f
->packForget;
}
}
return
$self
->{FOLDSVISIBLE}
}
sub
showLine {
my
(
$self
,
$line
) =
@_
;
$self
->tagRemove(
'Hidden'
,
"$line.0"
,
"$line.0 lineend + 1c"
);
}
sub
shownumbers {
my
(
$self
,
$flag
) =
@_
;
my
$f
=
$self
->Subwidget(
'Numbers'
);
if
(
defined
$flag
) {
if
(
$flag
) {
my
$before
=
$self
->Subwidget(
'XText'
);
$before
=
$self
->Subwidget(
'Folds'
)
if
$self
->{FOLDSVISIBLE};
$f
->
pack
(
-side
=>
'left'
,
-before
=>
$before
,
-fill
=>
'y'
,
);
$self
->{NUMBERSVISIBLE} = 1;
$self
->lnumberCheck;
}
else
{
$f
->packForget;
$self
->{NUMBERSVISIBLE} = 0;
}
}
return
$self
->{NUMBERSVISIBLE}
}
sub
showspaces {
my
$self
=
shift
;
if
(
@_
) {
$self
->{SHOWSPACES} =
shift
;
$self
->spacesPurge(1, 1)
if
$self
->{POSTCONFIG};
}
return
$self
->{SHOWSPACES}
}
sub
showstatus {
my
(
$self
,
$flag
) =
@_
;
my
$f
=
$self
->Subwidget(
'Statusbar'
);
if
(
defined
$flag
) {
if
(
$flag
) {
$f
->
pack
(
-fill
=>
'x'
,
);
$self
->{STATUSVISIBLE} = 1;
$f
->updateStatus;
}
else
{
$f
->packForget;
$self
->{STATUSVISIBLE} = 0;
}
}
return
$self
->{STATUSVISIBLE};
}
sub
spacebackground {
my
$self
=
shift
;
if
(
@_
) {
$self
->tagConfigure(
'Space'
,
-background
=>
shift
);
}
return
$self
->tagCget(
'Space'
,
'-background'
);
}
sub
spacesCheck {
my
(
$self
,
$pos
) =
@_
;
return
unless
$self
->cget(
'-showspaces'
);
my
$line
=
$self
->linenumber(
$pos
);
my
$completed
=
$self
->spacesCompleted;
$self
->spacesPurge(
$line
)
if
$line
<=
$self
->spacesCompleted;
}
sub
spacesCompleted {
my
$self
=
shift
;
$self
->{SPACESCOMPLETED} =
shift
if
@_
;
return
$self
->{SPACESCOMPLETED}
}
sub
spacesLine {
my
(
$self
,
$line
) =
@_
;
my
$begin
=
$self
->
index
(
"$line.0"
);
my
$end
=
$self
->
index
(
"$begin lineend"
);
my
$text
=
$self
->get(
$begin
,
$end
);
for
(
'Space'
,
'Tab'
) {
$self
->tagRemove(
$_
,
$begin
,
$end
)
}
if
(
$text
=~ /^([\s|\t]+)/) {
my
$spaces
= $1;
my
$count
= 0;
while
(
$spaces
ne
''
) {
my
$char
=
substr
$spaces
, 0, 1,
''
;
my
$next
=
$count
+ 1;
$self
->tagAdd(
'Space'
,
"$begin + $count c"
,
"$begin + $next c"
)
if
$char
eq
' '
;
$self
->tagAdd(
'Tab'
,
"$begin + $count c"
,
"$begin + $next c"
)
if
$char
eq
"\t"
;
$count
++
}
}
if
(
$text
=~ /(\s+)$/) {
my
$spaces
= $1;
my
$l
=
length
(
$spaces
);
$end
=
$self
->
index
(
"$end - $l c"
);
my
$count
= 0;
while
(
$spaces
ne
''
) {
my
$char
=
substr
$spaces
, 0, 1,
''
;
my
$next
=
$count
+ 1;
$self
->tagAdd(
'Space'
,
"$end + $count c"
,
"$end + $next c"
)
if
$char
eq
' '
;
$self
->tagAdd(
'Tab'
,
"$end + $count c"
,
"$end + $next c"
)
if
$char
eq
"\t"
;
$count
++
}
}
$self
->tagRaise(
'Space'
);
$self
->tagRaise(
'Tab'
);
$self
->tagRaise(
'Find'
);
$self
->tagRaise(
'sel'
);
}
sub
spacesLoop {
my
$self
=
shift
;
unless
(
$self
->cget(
'-showspaces'
)) {
$self
->spacesLoopActive(0);
return
}
my
$xt
=
$self
->Subwidget(
'XText'
);
my
$lpc
=
$self
->cget(
'-linespercycle'
);
my
$complete
=
$self
->spacesCompleted;
$self
->spacesRemove(
$complete
,
$complete
+
$lpc
);
for
(1 ..
$lpc
) {
my
$complete
=
$self
->spacesCompleted;
if
(
$complete
<=
$xt
->linenumber(
'end - 1c'
)) {
$self
->spacesLoopActive(1);
$self
->spacesLine(
$complete
);
$complete
++;
$self
->spacesCompleted(
$complete
);
}
else
{
$self
->spacesLoopActive(0);
}
last
unless
$self
->spacesLoopActive;
}
$self
->
after
(
$self
->highlightinterval, [
'spacesLoop'
,
$self
])
if
$self
->spacesLoopActive;
}
sub
spacesLoopActive {
my
$self
=
shift
;
$self
->{SPACESLOOPACTIVE} =
shift
if
@_
;
return
$self
->{SPACESLOOPACTIVE}
}
sub
spacesPurge {
my
(
$self
,
$line
,
$remove
) =
@_
;
$line
= 1
unless
defined
$line
;
$remove
= 0
unless
defined
$remove
;
$self
->spacesRemove(
$line
)
if
$remove
;
$self
->spacesCompleted(
$line
);
$self
->spacesLoop
unless
$self
->spacesLoopActive;
}
sub
spacesRemove {
my
(
$self
,
$begin
,
$end
) =
@_
;
$begin
= 1
unless
defined
$begin
;
$end
=
$self
->linenumber(
'end'
)
unless
defined
$end
;
$begin
=
"$begin.0"
;
$end
=
$self
->
index
(
"$end.0 lineend"
);
for
(
'Space'
,
'Tab'
) {
$self
->tagRemove(
$_
,
$begin
,
$end
)
}
}
sub
syntax {
my
(
$self
,
$new
) =
@_
;
my
$kam
=
$self
->Kamelon;
if
(
defined
(
$new
)) {
$self
->NoHighlighting(1);
$self
->highlightPurge(1, 1);
$self
->Subwidget(
'XText'
)->configure(
-mlcommentend
=>
undef
,
-mlcommentstart
=>
undef
,
-slcomment
=>
undef
,
);
unless
(
$new
eq
'None'
) {
$kam
->Syntax(
$new
);
my
$idx
=
$kam
->GetIndexer;
$self
->Subwidget(
'XText'
)->configure(
-mlcommentend
=>
$idx
->InfoMLCommentEnd(
$new
),
-mlcommentstart
=>
$idx
->InfoMLCommentStart(
$new
),
-slcomment
=>
$idx
->InfoSLComment(
$new
),
);
$self
->NoHighlighting(0);
$self
->Colored(0);
$self
->ColorInf([ [
$kam
->StateGet] ]);
$self
->highlightLoop
unless
$self
->LoopActive;
}
$self
->{SYNTAX} =
$new
;
}
return
$self
->{SYNTAX}
}
sub
tabbackground {
my
$self
=
shift
;
if
(
@_
) {
$self
->tagConfigure(
'Tab'
,
-background
=>
shift
);
}
return
$self
->tagCget(
'Tab'
,
'-background'
);
}
sub
tags {
return
$_
[0]->Kamelon->AvailableAttributes
}
sub
theme {
return
$_
[0]->{THEME}
}
sub
themeDialog {
my
$self
=
shift
;
my
$theme
=
$self
->theme;
my
$dialog
=
$self
->DialogBox(
-title
=>
'Theme editor'
,
-buttons
=> [
'Ok'
,
'Cancel'
],
-default_button
=>
'Ok'
,
-cancel_button
=>
'Cancel'
,
);
my
$historyfile
;
my
$config
=
$self
->cget(
'-configdir'
);
$historyfile
=
"$config/recent_colors"
;
my
$editor
=
$dialog
->add(
'TagsEditor'
,
-defaultbackground
=>
$self
->Subwidget(
'XText'
)->cget(
'-background'
),
-defaultforeground
=>
$self
->Subwidget(
'XText'
)->cget(
'-foreground'
),
-defaultfont
=>
$self
->Subwidget(
'XText'
)->cget(
'-font'
),
-historyfile
=>
$historyfile
,
-relief
=>
'sunken'
,
-borderwidth
=> 2,
-width
=> 62,
)->
pack
(
-expand
=> 1,
-fill
=>
'both'
,
-padx
=> 2,
-pady
=> 2);
my
$toolframe
=
$dialog
->add(
'Frame'
,
)->
pack
(
-fill
=>
'x'
);
$toolframe
->Button(
-command
=>
sub
{
my
$file
=
$self
->getSaveFile(
-filetypes
=> [
[
'Highlight Theme'
=>
'.ctt'
],
],
);
$editor
->save(
$file
)
if
defined
$file
;
},
-text
=>
'Save'
,
)->
pack
(
-side
=>
'left'
,
-padx
=> 5,
-pady
=> 5);
$toolframe
->Button(
-text
=>
'Load'
,
-command
=>
sub
{
my
$file
=
$self
->getOpenFile(
-filetypes
=> [
[
'Highlight Theme'
=>
'.ctt'
],
],
);
if
(
defined
$file
) {
my
$obj
= Tk::CodeText::Theme->new;
$obj
->load(
$file
);
$editor
->put(
$obj
->get);
$editor
->updateAll
}
},
)->
pack
(
-side
=>
'left'
,
-padx
=> 5,
-pady
=> 5);
$editor
->put(
$theme
->get);
my
$button
=
$dialog
->Show(
-popover
=>
$self
);
if
(
$button
eq
'Ok'
) {
$theme
->put(
$editor
->get);
$self
->themeUpdate;
}
$dialog
->destroy;
}
sub
themefile {
my
$self
=
shift
;
if
(
@_
) {
my
$file
=
shift
;
if
((
defined
$file
) and (-e
$file
)) {
$self
->theme->load(
$file
);
$self
->
after
(1, [
'themeUpdate'
,
$self
]);;
}
$self
->{THEMEFILE} =
$file
;
}
return
$self
->{THEMEFILE};
}
sub
themeUpdate {
my
$self
=
shift
;
my
$theme
=
$self
->theme;
my
@values
=
$theme
->get;
my
$font
=
$self
->cget(
'-font'
);
my
$bg
=
$self
->Subwidget(
'XText'
)->cget(
'-background'
);
my
$fg
=
$self
->Subwidget(
'XText'
)->cget(
'-foreground'
);
for
(
$theme
->tagList) {
$self
->tagDelete(
$_
) }
while
(
@values
) {
my
$tag
=
shift
@values
;
my
$options
=
shift
@values
;
my
%opt
=
@$options
;
my
$nbg
=
$bg
;
my
$nfg
=
$fg
;
my
$nfont
=
$font
;
$nbg
=
$opt
{
'-background'
}
if
exists
$opt
{
'-background'
};
$nfg
=
$opt
{
'-foreground'
}
if
exists
$opt
{
'-foreground'
};
$nfont
=
$self
->fontCompose(
$nfont
,
-slant
=>
$opt
{
'-slant'
})
if
exists
$opt
{
'-slant'
};
$nfont
=
$self
->fontCompose(
$nfont
,
-weight
=>
$opt
{
'-weight'
})
if
exists
$opt
{
'-weight'
};
$self
->tagConfigure(
$tag
,
-background
=>
$nbg
,
-foreground
=>
$nfg
,
-font
=>
$nfont
,
);
}
$self
->highlightPurge(1);
}
sub
ViewMenuItems {
my
$self
=
shift
;
my
$a
;
tie
$a
,
'Tk::Configure'
,
$self
,
'-autoindent'
;
my
$b
;
tie
$b
,
'Tk::Configure'
,
$self
,
'-autobrackets'
;
my
$c
;
tie
$c
,
'Tk::Configure'
,
$self
,
'-autocomplete'
;
my
$d
;
tie
$d
,
'Tk::Configure'
,
$self
,
'-showspaces'
;
my
$f
;
tie
$f
,
'Tk::Configure'
,
$self
,
'-showfolds'
;
my
$n
;
tie
$n
,
'Tk::Configure'
,
$self
,
'-shownumbers'
;
my
$s
;
tie
$s
,
'Tk::Configure'
,
$self
,
'-showstatus'
;
my
$v
=
$self
->cget(
'-wrap'
);
Tie::Watch->new(
-variable
=> \
$v
,
-store
=>
sub
{
my
(
$watch
,
$value
) =
@_
;
$watch
->Store(
$value
);
$self
->configure(
-wrap
=>
$v
);
$self
->contentCheck;
},
);
my
@values
= (
-onvalue
=> 1,
-offvalue
=> 0);
my
$match
=
$self
->cget(
'-match'
);
my
$curlies
=
''
;
$curlies
=
'{}'
if
$match
=~ /\{\}/;
my
$paren
=
''
;
$paren
=
'()'
if
$match
=~ /\(\)/;
my
$brackets
=
''
;
$brackets
=
'[]'
if
$match
=~ /\[\]/;
my
@opt
= (
-command
=>
sub
{
$self
->configure(
'-match'
,
$curlies
.
$paren
.
$brackets
) },
-offvalue
=>
''
,
);
my
@items
= (
[
checkbutton
=>
'~Auto indent'
,
@values
,
-variable
=> \
$a
],
[
checkbutton
=>
'~Auto brackets'
,
@values
,
-variable
=> \
$b
],
[
checkbutton
=>
'A~uto complete'
,
@values
,
-variable
=> \
$c
],
[
checkbutton
=>
'~Show spaces and tabs'
,
@values
,
-variable
=> \
$d
],
[
'cascade'
=>
'~Wrap'
,
-tearoff
=> 0,
-menuitems
=> [
[
radiobutton
=>
'Word'
,
-variable
=> \
$v
,
-value
=>
'word'
],
[
radiobutton
=>
'Character'
,
-variable
=> \
$v
,
-value
=>
'char'
],
[
radiobutton
=>
'None'
,
-variable
=> \
$v
,
-value
=>
'none'
],
]],
[
'cascade'
=>
'~Match'
,
-tearoff
=> 0,
-menuitems
=> [
[
checkbutton
=>
'() Parenthesis'
,
@opt
,
-variable
=> \
$paren
,
-onvalue
=>
'()'
],
[
checkbutton
=>
'{} Curlies'
,
@opt
,
-variable
=> \
$curlies
,
-onvalue
=>
'{}'
],
[
checkbutton
=>
'[] Brackets'
,
@opt
,
-variable
=> \
$brackets
,
-onvalue
=>
'[]'
],
]],
[
command
=>
'Au~to complete settings'
,
-command
=> [
acSettings
=>
$self
]],
[
command
=>
'~Colors'
,
-command
=> [
themeDialog
=>
$self
]],
'separator'
,
[
checkbutton
=>
'Code ~folds'
,
@values
,
-variable
=> \
$f
],
[
checkbutton
=>
'~Line numbers'
,
@values
,
-variable
=> \
$n
],
[
checkbutton
=>
'~Status bar'
,
@values
,
-variable
=> \
$s
],
'separator'
,
[
command
=>
'~Fix indentation'
,
-command
=> [
fixIndent
=>
$self
]],
[
command
=>
'~Remove trailing spaces'
,
-command
=> [
removeTrailingSpaces
=>
$self
]],
);
return
@items
}
1;