From 8f0026f42e39f6e8aa40c341d5236d2804c161b8 Mon Sep 17 00:00:00 2001 From: Paul Manias <31156549+paul-manias@users.noreply.github.com> Date: Fri, 29 Nov 2024 00:08:08 +0000 Subject: [PATCH] Script and UI improvements (#279) * Reworked theme, palette and icon management * Fixed issues with the divider patterns * Visual improvements to FileView and ToolTip widgets * Added dropdown script, simplified menu script * Improved the presentation of toolbars in flush mode. * Improved ColumnView presentation * Added gui.rgbToIconTheme() * Added a Ratio parameter to gui.interpolateRGB() and gui.interpolateHSV() * Fixed issue with crossing events not being reported to vectors. * [Core] Fixed free-space detection for Win32 drives * [Core] Added BOOKMARK flag to the DEVICE group. --- data/fonts/options.cfg | 12 +- docs/xml/modules/classes/storagedevice.xml | 1 + docs/xml/modules/core.xml | 9 +- examples/vue.fluid | 2 +- include/parasol/modules/core.h | 1 + scripts/dev/idl/common.fdl | 3 +- scripts/gui.fluid | 577 ++++++++++++--------- scripts/gui/button.fluid | 54 +- scripts/gui/checkbox.fluid | 36 +- scripts/gui/columnview.fluid | 173 +++--- scripts/gui/combobox.fluid | 40 +- scripts/gui/divider.fluid | 37 +- scripts/gui/dropdown.fluid | 343 ++++++++++++ scripts/gui/filedialog.fluid | 16 +- scripts/gui/fileview.fluid | 101 ++-- scripts/gui/fontdialog.fluid | 11 +- scripts/gui/input.fluid | 31 +- scripts/gui/listview.fluid | 76 +-- scripts/gui/menu.fluid | 206 ++++---- scripts/gui/menubar.fluid | 99 ++-- scripts/gui/toolbar.fluid | 309 ++++++----- scripts/gui/tooltip.fluid | 19 +- src/core/defs.h | 2 +- src/core/fs_identify.cpp | 9 +- src/core/idl.h | 2 +- src/core/lib_filesystem.cpp | 10 +- src/core/microsoft/windows.cpp | 8 +- src/vector/scene/scene.cpp | 2 +- src/vector/scene/scene_input.cpp | 2 +- src/vector/vectors/vector.cpp | 2 + 30 files changed, 1308 insertions(+), 885 deletions(-) create mode 100644 scripts/gui/dropdown.fluid diff --git a/data/fonts/options.cfg b/data/fonts/options.cfg index 96ce7266d..7e840bcc3 100644 --- a/data/fonts/options.cfg +++ b/data/fonts/options.cfg @@ -16,16 +16,13 @@ Hidden = Yes [Crimson Pro] Hinting = Normal +[Noto Color Emoji] +Hidden = Yes + [Noto Sans] Hinting = Light Default = Yes -[Vollkorn] -Hinting = Normal - -[Noto Color Emoji] -Hidden = Yes - [Source Sans 3] Hidden = Yes @@ -37,3 +34,6 @@ Alias = Source Sans 3 Name = Times New Roman Alias = Crimson Pro Hidden = Yes + +[Vollkorn] +Hinting = Normal diff --git a/docs/xml/modules/classes/storagedevice.xml b/docs/xml/modules/classes/storagedevice.xml index 84afd6a81..89ab99fea 100644 --- a/docs/xml/modules/classes/storagedevice.xml +++ b/docs/xml/modules/classes/storagedevice.xml @@ -83,6 +83,7 @@ + This marker indicates that the presented volume is a bookmark and not a device name. Compact disc style device Catch-all for fixed media devices that are not directly identifiable. Floppy disk style device diff --git a/docs/xml/modules/core.xml b/docs/xml/modules/core.xml index 3a4a13508..666e47f73 100644 --- a/docs/xml/modules/core.xml +++ b/docs/xml/modules/core.xml @@ -928,9 +928,9 @@ GetField(Object, FID_Y|TLONG, &y); Optional argument that can refer to a variable that will store the resulting sub-class ID (if the result is a base-class, this variable will receive a value of zero). -

This function examines the relationship between file data and installed classes. It allows for instance, a JPEG file to be identified as a datatype of the Picture class, or an MP3 file to be identified as a datatype of the Sound class.

-

The method involves analysing the Path's file extension and comparing it to the supported extensions of all available classes. If a class supports the file extension then the ID of that class will be returned. If the file extension is not listed in the class dictionary or if it is listed more than once, the first 80 bytes of the file's data will be loaded and checked against classes that can match against file header information. If a match is found, the ID of the matching class will be returned.

-

This function returns an error code of ERR::Search in the event that a suitable class is not available to match against the given file.

+

This function examines the relationship between file data and Parasol classes. For instance, a JPEG file would be identified as a datatype of the Picture class. An MP3 file would be identified as a datatype of the Sound class.

+

The method involves analysing the Path's file extension and comparing it to the supported extensions of all available classes. If a class supports the file extension, the ID of that class will be returned. If the file extension is not listed in the class dictionary or if it is listed more than once, the first 80 bytes of the file's data will be loaded and checked against classes that can match against file header information. If a match is found, the ID of the matching class will be returned.

+

The ERR::Search code is returned if a suitable class does not match the targeted file.

Operation successful. @@ -1291,7 +1291,7 @@ parasol:pictures/ parasol:documents parasol:documents (Existing documents The discovered string value is returned here if found. -

Call ReadInfoTag() to retrieve the string value associated with a named tag in a FileInfo structure. The tag must have been added with AddInfoTag or ERR::NotFound will be returned.

+

ReadInfoTag() will read the value of a named tag in a FileInfo structure. The tag must have been added with AddInfoTag or ERR::NotFound will be returned.

Operation successful. @@ -2121,6 +2121,7 @@ SetField(Object, FID_Statement|TSTR, "string");
+ This marker indicates that the presented volume is a bookmark and not a device name. Compact disc style device Catch-all for fixed media devices that are not directly identifiable. Floppy disk style device diff --git a/examples/vue.fluid b/examples/vue.fluid index cceaf670a..3c003bb56 100644 --- a/examples/vue.fluid +++ b/examples/vue.fluid @@ -138,7 +138,7 @@ function displayImage(Path) glStats = { width = pic.bitmap.width, height = pic.bitmap.height } end, function(Exception) - displayError("

Failed to process selected file.

") + displayError([[

Failed to process selected file.

]]) end) end diff --git a/include/parasol/modules/core.h b/include/parasol/modules/core.h index 31c68124a..f10c669d2 100644 --- a/include/parasol/modules/core.h +++ b/include/parasol/modules/core.h @@ -98,6 +98,7 @@ enum class DEVICE : LARGE { FIXED = 0x00008000, PRINTER_3D = 0x00010000, SCANNER_3D = 0x00020000, + BOOKMARK = 0x00040000, }; DEFINE_ENUM_FLAG_OPERATORS(DEVICE) diff --git a/scripts/dev/idl/common.fdl b/scripts/dev/idl/common.fdl index 98df9023d..7191acadd 100644 --- a/scripts/dev/idl/common.fdl +++ b/scripts/dev/idl/common.fdl @@ -29,7 +29,8 @@ flags("DEVICE", { bits=64, module="Core" }, "USB: Removable USB storage device. May be further qualified by `HARD_DISK`, `FLOPPY_DISK` etc", "FIXED: Catch-all for fixed media devices that are not directly identifiable.", "PRINTER_3D: Device is a three dimensional printer.", - "SCANNER_3D: Device is a three dimensional scanner.") + "SCANNER_3D: Device is a three dimensional scanner.", + "BOOKMARK: This marker indicates that the presented volume is a bookmark and not a device name.") flags("CCF", { comment="Class categories", module="Core" }, "COMMAND: Command classes perform specific procedures, like copying or moving a file, managing volumes or executing a program.", diff --git a/scripts/gui.fluid b/scripts/gui.fluid index 69ca402e7..a813cb007 100644 --- a/scripts/gui.fluid +++ b/scripts/gui.fluid @@ -1,168 +1,19 @@ -- Graphical User Interface functions -if (gui == nil) then - -- The following values are the default 'light' theme. They can be overridden by the "style:values.xml" file. +if gui then return end + + if not mVec then mVec = mod.load('vector') end + gui = { theme = 'light', dpi = 160, - fonts = { - -- Use percentages for scalable sizes, where 100% is equivalent to the value of gui.interface.fontSize - default = { face='Noto Sans,Source Sans Pro', size='100%' }, - window = { face='Noto Sans,Source Sans Pro', size='100%' }, -- For text that is not inside a widget - button = { face='Noto Sans,Source Sans Pro', size='100%' }, -- Text inside buttons - icon = { face='Noto Sans,Source Sans Pro', size='100%' }, -- Text at the bottom of icons - menu = { face='Noto Sans,Source Sans Pro', size='100%' }, -- Menu item text - titlebar = { face='Noto Sans', size='100%' }, -- Window titlebar text - small = { face='Tiny', size='60%' }, -- Recommended text for small sizes - large = { face='Noto Sans,Source Sans Pro', size='130%' }, -- Recommended text for headers - widget = { face='Noto Sans,Source Sans Pro', size='100%' }, -- Text inside widgets (e.g. combobox) - label = { face='Noto Sans,Source Sans Pro::bold', size='100%' } -- Text for labels and outside widgets - }, - style = { - -- These are all fills, so any SVG compliant fill value can potentially be used to define a 'colour'. - widget = { - text = 'rgb(255,255,255)', - bkgd = 'rgb(0,0,0,100)', - stroke = 'rgb(255,255,255,60)', - strokeFocus = 'rgb(255,255,255,160)', - strokeDisabled = 'rgb(255,255,255,60)', - strokeWidth = 2, - width = 160, -- Default width for common widgets (px) - gap = 6, -- Recommended gap between widgets (px) - margin = 6 -- Recommended internal margin for widgets (px) - }, - button = { - bkgd = 'rgb(230,230,230)', -- Background when raised / default - bkgdActive = 'rgb(200,200,200)' -- Background when temporarily clicked (depressed) - }, - page = { - bkgd = 'rgb(255,255,255)', -- Background for hosting text & paper-based layouts - border = 'rgb(144,144,144)', -- Border stroke for any area surrounding 'bkgd' - borderFocus = 'rgb(160,160,160)', -- Stroke to use when 'border' has the user's focus - text = 'rgb(0,0,0)', -- Default colour for text drawn over 'bkgd' - textHighlight = 'rgb(0,0,0)', -- Colour for 'text' when temporarily highlighted - textHighlightBkgd = 'rgb(224,224,240)' -- Background fill for 'text' that is highlighted - }, - window = { - bkgd = 'rgb(220,220,220)', - text = 'rgb(0,0,0)' -- Colour for text that is drawn directly to the window - }, - menubar = { - bkgd = 'rgb(190,190,190)' - }, - menu = { - bkgd = 'rgb(240,240,240)', - border = 'rgb(200,200,200)' -- Stroke for menu border - }, - desktop = { - bkgd = 'rgb(160,160,160)' - }, - recess = 'rgb(160,160,160)', -- Fill for recessed areas with no content. - strokeShadow = 'rgb(0,0,0,100)', -- Base colour/alpha value for stroked shadows - strokeHighlight = 'rgb(255,255,255,150)' -- Base colour/alpha value for stroked highlights - }, - interface = { - fontSize = 11, -- Default font-size for everything (pt) - iconTheme = 'Default', - iconSize = 20 -- Recommended default size for icons (px) and should be linked to fontSize - }, - iconThemes = { - default = { first={ r=90,g=90,b=90 }, last={ r=70,g=70,b=110 } }, - carbon = { first={ r=90,g=90,b=90 }, last={ r=70,g=70,b=110 } }, - yellow = { first={ r=0xec,g=0xef,b=0x9e }, last={ r=0xd6,g=0x87,b=0x10 }, stroke={ r=60, g=30, b=30, a=90 } }, - orange = { first={ r=0xFD,g=0xC8,b=0x30 }, last={ r=0xF3,g=0x73,b=0x35 } }, - blue = { first={ r=0x4b,g=0x6c,b=0xb7 }, last={ r=0x18,g=0x28,b=0x48 } }, - ocean = { first={ r=0xA8,g=0xC0,b=0xFF }, last={ r=0x3F,g=0x2B,b=0x96 } }, - green = { first={ r=0x7e,g=0x9d,b=0x13 }, last={ r=0x00,g=0x65,b=0x32 } }, - red = { first={ r=0xf5,g=0xaf,b=0x19 }, last={ r=0xf1,g=0x27,b=0x11 } }, - indigo = { first={ r=0xad,g=0x53,b=0x89 }, last={ r=0x3c,g=0x10,b=0x53 } }, - rose = { first={ r=0xff,g=0xc3,b=0xa0 }, last={ r=0xFF,g=0xAF,b=0xBD } }, - pink = { first={ r=0xff,g=0xdd,b=0xe1 }, last={ r=0xee,g=0x9c,b=0xa7 } }, - grey = { first={ r=100,g=100,b=100 }, last={ r=70,g=70,b=70 } }, - pearl = { first={ r=250,g=249,b=248 }, last={ r=210,g=211,b=212 } } - }, _counter = 0, configureScene = function(Window, Scene) -- A custom configure function can be defined that adds definitions to the window scene, e.g. images and patterns for fills. end } - function convertFontSizes() -- Convert font percentage sizes to their px size - for k,v in pairs(gui.fonts) do - if gui.fonts[k].size then - if string.match(gui.fonts[k].size, '^%-?%d+%%$') then - pct = tonumber(string.match(gui.fonts[k].size, '^(%-?%d+)%%$')) - gui.fonts[k].size = math.floor(gui.interface.fontSize * (pct / 100)) - end - end - end - end - - local path = 'style:values.xml' - if mSys.AnalysePath(path) != ERR_Okay then - path = 'environment:config/values.xml' - if mSys.AnalysePath(path) != ERR_Okay then - path = 'styles:default/values.xml' - end - end - - local xml = obj.new('xml', { path=path }) - - if (xml != nil) then ---[[ - local err, index = xml.mtFindTag('/colours') - if (err == ERR_Okay) then - for k,v in pairs(gui.style) do - err, colour = xml.mtGetAttrib(index, k) - if (err == ERR_Okay) then gui.style[k] = colour end - end - end ---]] - local err, index = xml.mtFindTag('/interface') - if (err == ERR_Okay) then - for k,v in pairs(gui.interface) do - err, val = xml.mtGetAttrib(index, k) - if (err == ERR_Okay) then - if string.match(val, '^%-?%d+$') then - gui.interface[k] = tonumber(val) - else - gui.interface[k] = val - end - end - end - end - - convertFontSizes() - - local err, index = xml.mtFindTag('/fonts') - if (err == ERR_Okay) then - for k,v in pairs(gui.fonts) do - local err, index = xml.mtFindTag("/fonts/font(@name='" .. k .. "')") - if (err == ERR_Okay) then - local err, face = xml.mtGetAttrib(index, 'face') - if (err == ERR_Okay) then gui.fonts[k].face = face end - local err, size = xml.mtGetAttrib(index, 'size') - if (err == ERR_Okay) then - if string.match(size, '^%-?%d+$') then - gui.fonts[k].size = tonumber(size) - elseif string.match(size, '^%-?%d+%%$') then - pct = tonumber(string.match(size, '^(%-?%d+)%%$')) - gui.fonts[k].size = math.floor(gui.interface.fontSize * (pct / 100)) - else - gui.fonts[k].size = size - end - end - end - end - end - - xml = nil - else - convertFontSizes() - end -end - ------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------- gui.getFontHeight = function(Font) if not Font.height then @@ -175,24 +26,24 @@ gui.getFontHeight = function(Font) return Font.spacing, Font.height end ------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------- -- Read a style value and return it in pixel units. gui.pixel = function(val) - if (val != nil) then + if val != nil then local num, alpha = val:match('^(%d+)(%a-)$') num = tonumber(num) - if (num == nil) then error('Invalid graphics unit \'' .. val .. '\'') end - if (alpha != nil) then - if (alpha == 'px') then + if num == nil then error('Invalid graphics unit \'' .. val .. '\'') end + if alpha != nil then + if alpha == 'px' then return num - elseif (alpha == 'in') then + elseif alpha == 'in' then return gui.dpi * num - elseif (alpha == 'mm') then -- 25.4 units per inch + elseif alpha == 'mm' then -- 25.4 units per inch return gui.dpi * (num / 25.4) - elseif (alpha == 'pt') then -- 72 units per inch + elseif alpha == 'pt' then -- 72 units per inch return gui.dpi * (num / 72) - elseif (alpha == 'dp') then -- 160dpi relative value + elseif alpha == 'dp' then -- 160dpi relative value return num * (gui.dpi * 0.00625) end end @@ -202,85 +53,96 @@ gui.pixel = function(val) end end ------------------------------------------------------------------------------- --- Convert an RGB string to an RGB table. +---------------------------------------------------------------------------------------------------------------------- +-- Convert an RGB string to an RGB table. Supports '#' and 'rgb()' gui.strToRGB = function(Value) if not Value then error('Empty value passed to strToRGB()\n' .. debug.traceback()) end - if (string.byte(Value) == 35) then - local colour = tonumber(Value) - if (Value:len() == 7) then - return { - r = bit.band(bit.rshift(colour, 16), 0xff), - g = bit.band(bit.rshift(colour, 8), 0xff), - b = bit.band(colour, 0xff), - a = 255 - } - elseif (Value:len() == 9) then - return { - r = bit.band(bit.rshift(colour, 24), 0xff), - g = bit.band(bit.rshift(colour, 16), 0xff), - b = bit.band(bit.rshift(colour, 8), 0xff), - a = bit.band(colour, 0xff) - } + local result + xpcall(function() + if string.byte(Value) == 35 then + local colour = tonumber(string.sub(Value,2), 16) + if Value:len() == 7 then + result = { + r = bit.band(bit.rshift(colour, 16), 0xff), + g = bit.band(bit.rshift(colour, 8), 0xff), + b = bit.band(colour, 0xff), + a = 255 + } + elseif Value:len() == 9 then + result = { + r = bit.band(bit.rshift(colour, 24), 0xff), + g = bit.band(bit.rshift(colour, 16), 0xff), + b = bit.band(bit.rshift(colour, 8), 0xff), + a = bit.band(colour, 0xff) + } + else + result = { r=0, g=0, b=0, a=255 } + end else - return { r=0, g=0, b=0, a=255 } - end - else - local colours = { } - for str in string.gmatch(Value, '([^,]+)') do - table.insert(colours, tonumber(str)) + local colours = { } + for str in string.gmatch(Value, '([^,]+)') do + table.insert(colours, tonumber(str)) + end + local r = nz(colours[1], 0) + local g = nz(colours[2], 0) + local b = nz(colours[3], 0) + local a = nz(colours[4], 255) + if r > 255 then r = 255 end + if g > 255 then g = 255 end + if b > 255 then b = 255 end + if a > 255 then a = 255 end + if r < 0 then r = 0 end + if g < 0 then g = 0 end + if b < 0 then b = 0 end + if a < 0 then a = 0 end + result = { r=r, g=g, b=b, a=a } end - local r = nz(colours[1], 0) - local g = nz(colours[2], 0) - local b = nz(colours[3], 0) - local a = nz(colours[4], 255) - if (r > 255) then r = 255 end - if (g > 255) then g = 255 end - if (b > 255) then b = 255 end - if (a > 255) then a = 255 end - if (r < 0) then r = 0 end - if (g < 0) then g = 0 end - if (b < 0) then b = 0 end - if (a < 0) then a = 0 end - return { r=r, g=g, b=b, a=a } - end + end, + function(Error) + error(Error .. '\nInput value: ' .. Value .. '\n' .. debug.traceback()) + end) + + return result end ------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------- -- Convert an RGB table to a SVG colour string gui.rgbToSVG = function(Value) return string.format('rgb(%d,%d,%d,%d)', Value.r, Value.g, Value.b, nz(Value.a,255)) end ------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------- -- Interpolate two RGB colours -gui.interpolateRGB = function(Base, New) +gui.interpolateRGB = function(Base, New, Ratio) + if not Ratio then Ratio = 0.5 end return { - a = Base.a + ((New.a - Base.a)*0.5), - r = Base.r + ((New.r - Base.r)*0.5), - g = Base.g + ((New.g - Base.g)*0.5), - b = Base.b + ((New.b - Base.b)*0.5) + a = Base.a + ((New.a - Base.a) * Ratio), + r = Base.r + ((New.r - Base.r) * Ratio), + g = Base.g + ((New.g - Base.g) * Ratio), + b = Base.b + ((New.b - Base.b) * Ratio) } end ------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------- -- Interpolate two HSV colours -gui.interpolateHSV = function(Base, New) +gui.interpolateHSV = function(Base, New, Ratio) + if not Ratio then Ratio = 0.5 end return { - a = Base.a + ((New.a - Base.a)*0.5), - h = Base.h + ((New.h - Base.h)*0.5), - s = Base.s + ((New.s - Base.s)*0.5), - v = Base.v + ((New.v - Base.v)*0.5) + a = Base.a + ((New.a - Base.a) * Ratio), + h = Base.h + ((New.h - Base.h) * Ratio), + s = Base.s + ((New.s - Base.s) * Ratio), + v = Base.v + ((New.v - Base.v) * Ratio) } end ------------------------------------------------------------------------------- + +---------------------------------------------------------------------------------------------------------------------- -- Convert HSV table to RGB gui.hsvToRGB = function(Value) @@ -314,17 +176,35 @@ gui.hsvToRGB = function(Value) end end ------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------- -- Return the light value of an RGB colour (i.e. the V in HSV) gui.rgbValue = function(Value) + if not Value then + error('Empty value passed to rgbValue()\n' .. debug.traceback()) + end + local max = Value.b if Value.g > max then max = Value.g end if Value.r > max then max = Value.r end return max end ------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------- + +gui.rgbToIconTheme = function(Value) + if type(Value) == 'string' then + Value = gui.strToRGB(Value) + end + + if gui.rgbValue(Value) > 127 then + return 'pearl' + else + return 'carbon' + end +end + +---------------------------------------------------------------------------------------------------------------------- -- Convert RGB table to HSV gui.rgbToHSV = function(Value) @@ -361,33 +241,33 @@ gui.rgbToHSV = function(Value) return hsv end ------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------- -- Call a client function for each vector in the tree gui.forVector = function(Vector, Function) while (Vector != nil) do Function(Vector) local child = Vector.child - if (child != nil) then gui.forVector(child, Function) end + if child != nil then gui.forVector(child, Function) end Vector = Vector.next end end ------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------- gui.applyFill = function(Vector, Fill) while (Vector != nil) do - if (Vector.fill != 'none') then + if Vector.fill != 'none' then Vector.fill = Fill end - if (Vector.stroke != nil) then Vector.stroke = Fill end + if Vector.stroke != nil then Vector.stroke = Fill end local child = Vector.child - if (child != nil) then gui.applyFill(child, Fill) end + if child != nil then gui.applyFill(child, Fill) end Vector = Vector.next end end ------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------- -- Generate a simple gradient fill for vectors. gui.simpleGradient = function(Scene, Name, Colours, X1, Y1, X2, Y2, Units, IgnoreClashes) @@ -421,8 +301,8 @@ gui.simpleGradient = function(Scene, Name, Colours, X1, Y1, X2, Y2, Units, Ignor Scene.mtAddDef(Name, gradient) end) - if (ex) then - if (ex.code == ERR_ResourceExists) then + if ex then + if ex.code == ERR_ResourceExists then gradient.free() return nil else @@ -436,7 +316,7 @@ gui.simpleGradient = function(Scene, Name, Colours, X1, Y1, X2, Y2, Units, Ignor return gradient end ------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------- -- Build an icon styled with the current theme and register it as a pattern. The pattern can then be used as a fill, -- i.e. "url(#Path)". Using it in a VectorRectangle is akin to a cached bitmap (fast), or apply to a VectorViewport -- for live rendering (higher quality transforms). @@ -444,39 +324,46 @@ end gui.createIcon = function(Scene, Path, Size, Theme, Name) if not Size then Size = 16 end if not Path then error('No Path specified.') end - if not Name then Name = Path end local lGradient = gui.iconThemes.default local icon = { size=Size } - if Scene.mtFindDef(Name) == ERR_Okay then -- Return if the icon pattern is already registered - return - end + gui._counter = gui._counter + 1 + local gname = 'icon_grd' .. gui._counter if type(Theme) == 'table' then lGradient = Theme elseif type(Theme) == 'string' then + gname = 'icon_' .. Theme if gui.iconThemes[Theme] then lGradient = gui.iconThemes[Theme] else error('gui.createIcon() theme ' .. Theme .. ' not recognised.') end + + if not Name then Name = Theme:lower() .. '/' .. Path:lower() end + else + error('Invalid Theme specified.') + end + + if not Name then Name = Path end + + if Scene.mtFindDef(Name) == ERR_Okay then -- Return if the icon pattern is already registered + return { name = Name, theme = Theme, size = Size, path = Path, fill = 'url(#' .. Name .. ')' } end - gui._counter = gui._counter + 1 - local gname = 'icon_grd' .. gui._counter icon.pattern = Scene.new('VectorPattern', { pageWidth=Size, pageHeight=Size, spreadMethod=VSPREAD_PAD }) - icon.gradient = gui.simpleGradient(icon.pattern.scene, gname, { lGradient.first, lGradient.last }, 0, 0, 0, 1) + icon.gradient = gui.simpleGradient(icon.pattern.scene, gname, { lGradient.first, lGradient.last }, 0, 0, 0, 1, 'boundingbox', true) if string.find(Path, 'icons:') != 1 then Path = 'icons:' .. Path .. '.svg' end icon.svg = obj.new('svg', { target=icon.pattern.viewport, path=Path }) gui.forVector(icon.pattern.viewport, function(Vector) - if (Vector.fill != 'none') then + if Vector.fill != 'none' then Vector.fill = 'url(#' .. gname .. ')' end - if (Vector.stroke != nil) then + if Vector.stroke != nil then Vector.stroke = 'url(#' .. gname .. ')' elseif lGradient.stroke then Vector.stroke = gui.rgbToSVG(lGradient.stroke) @@ -487,15 +374,15 @@ gui.createIcon = function(Scene, Path, Size, Theme, Name) -- Adjust gradient size to match the viewport height. local viewport = icon.pattern.viewport.child - if (viewport != nil) then - while (child != nil) do - if (child.class.id == ID_VECTORVIEWPORT) then + if viewport != nil then + while child != nil do + if child.class.id == ID_VECTORVIEWPORT then viewport = child break end end - if (viewport.viewHeight < viewport.viewWidth) then + if viewport.viewHeight < viewport.viewWidth then icon.gradient.y1 = viewport.viewY - ((viewport.viewWidth - viewport.viewHeight) * 0.5) icon.gradient.y2 = icon.gradient.y1 + viewport.viewWidth else @@ -505,4 +392,214 @@ gui.createIcon = function(Scene, Path, Size, Theme, Name) end check(Scene.mtAddDef(Name, icon.pattern)) + + return { name = Name, theme = Theme, size = Size, path = Path, fill = 'url(#' .. Name .. ')' } end + +---------------------------------------------------------------------------------------------------------------------- + + -- The following values are the default 'light' theme. They can be overridden by the "style:values.xml" file. + + gui.fonts = { + -- Use percentages for scalable sizes, where 100% is equivalent to the value of gui.interface.fontSize + default = { face='Noto Sans,Source Sans Pro', size='100%' }, + window = { face='Noto Sans,Source Sans Pro', size='100%' }, -- For text that is not inside a widget + button = { face='Noto Sans,Source Sans Pro', size='100%' }, -- Text inside buttons + icon = { face='Noto Sans,Source Sans Pro', size='100%' }, -- Labeling for icons + menu = { face='Noto Sans,Source Sans Pro', size='100%' }, -- Menu item text + titlebar = { face='Noto Sans', size='100%' }, -- Window titlebar text + small = { face='Tiny', size='60%' }, -- Recommended text for small sizes + large = { face='Noto Sans,Source Sans Pro', size='130%' }, -- Recommended text for headers + widget = { face='Noto Sans,Source Sans Pro', size='100%' }, -- Text inside widgets (e.g. combobox) + label = { face='Noto Sans,Source Sans Pro::bold', size='100%' } -- Text for labels and outside widgets + } + + gui.iconThemes = { + default = { first={ r=90,g=90,b=90 }, last={ r=70,g=70,b=110 } }, + carbon = { first={ r=90,g=90,b=90 }, last={ r=70,g=70,b=110 } }, + yellow = { first={ r=0xec,g=0xef,b=0x9e }, last={ r=0xd6,g=0x87,b=0x10 }, stroke={ r=60, g=30, b=30, a=90 } }, + orange = { first={ r=0xFD,g=0xC8,b=0x30 }, last={ r=0xF3,g=0x73,b=0x35 } }, + blue = { first={ r=0x4b,g=0x6c,b=0xb7 }, last={ r=0x18,g=0x28,b=0x48 } }, + ocean = { first={ r=0xA8,g=0xC0,b=0xFF }, last={ r=0x3F,g=0x2B,b=0x96 } }, + green = { first={ r=0x7e,g=0x9d,b=0x13 }, last={ r=0x00,g=0x65,b=0x32 } }, + red = { first={ r=0xf5,g=0xaf,b=0x19 }, last={ r=0xf1,g=0x27,b=0x11 } }, + indigo = { first={ r=0xad,g=0x53,b=0x89 }, last={ r=0x3c,g=0x10,b=0x53 } }, + rose = { first={ r=0xff,g=0xc3,b=0xa0 }, last={ r=0xFF,g=0xAF,b=0xBD } }, + pink = { first={ r=0xff,g=0xdd,b=0xe1 }, last={ r=0xee,g=0x9c,b=0xa7 } }, + grey = { first={ r=100,g=100,b=100 }, last={ r=70,g=70,b=70 } }, + pearl = { first={ r=250,g=249,b=248 }, last={ r=210,g=211,b=212 } } + } + + gui.palettes = { + -- bkgd is the standard background colour for text. In a light theme it should be near-white. + -- base is the inverse light value of bkgd and should share the same hue as the prime colour. + -- prime (primary) and second (secondary prime) are colour pairs of the same hue. + -- contrast is a suitable complement to prime and should be of a strongly contrasting hue + -- neutral is a default background colour for unpainted areas, usually a light grey tone + ocean = { type = 'light', bkgd = '#ECF0F1', base = '#2C3E50', prime = '#3498DB', second = '#2980B9', + contrast = '#E74C3C', neutral = 'rgb(220,220,220)', text='rgb(0,0,0)', altText='rgb(255,255,255)' }, + orangeApples = { type = 'light', bkgd = '#ffffff', base = '#19302d', prime = '#74a108', second = '#263248', + contrast = '#e89214', neutral = 'rgb(220,220,220)', text='rgb(0,0,0)', altText='rgb(255,255,255)' }, + greenland = { type = 'light', bkgd = '#f9FFfB', base = '#163a00', prime = '#c55500', second = '#55c500', + contrast = '#567a00', neutral = '#e9e9e0', text='rgb(0,0,0)', altText='rgb(255,255,255)' }, + sunrise = { type = 'light', bkgd = '#f9FfFc', base = '#687878', prime = '#e2581b', second = '#bd3232', + contrast = '#eb9500', neutral = 'rgb(220,220,220)', text='rgb(0,0,0)', altText='rgb(255,255,255)' }, + candyfloss = { type = 'light', bkgd = '#fffaf7', base = '#375a5e', prime = '#6ac9a6', second = '#FF8B94', + contrast = '#e07780', neutral = 'rgb(220,220,220)', text='rgb(0,0,0)', altText='rgb(255,255,255)' }, + template = { type = '', bkgd = '', base = '', prime = '', second = '', contrast = '', neutral = 'rgb(220,220,220)', text='rgb(0,0,0)', altText='rgb(255,255,255)' } + } + + gui.palette = gui.palettes.ocean + + gui.style = { + -- All colour values are fills, so gradient and pattern references are also permitted for 'colours'. + page = { + bkgd = gui.palette.bkgd, -- Background for hosting text & paper-based layouts + stroke = gui.palette.base, -- Border stroke for any area surrounding 'bkgd' + strokeFocus = gui.palette.contrast, -- Stroke to use when 'border' has the user's focus + strokeWidth = 2, + text = gui.palette.text, -- Default colour for text drawn over 'bkgd' + icon = nil, -- Default icon theme for icons drawn over 'bkgd' + textHighlight = gui.palette.altText, -- Colour for 'text' during user hover + textHighlightBkgd = gui.palette.contrast, -- Background fill for 'text' during user hover + iconHighlight = nil, -- Recommended icon theme when highlighted or selected + textSelect = gui.palette.altText, -- Colour for 'text' when selected + textSelectBkgd = gui.palette.prime -- Background fill for 'text' when selected + }, + widget = { + text = gui.palette.altText, + bkgd = gui.palette.prime, + stroke = 'rgb(255,255,255,60)', + strokeFocus = gui.palette.contrast, + strokeWidth = 2, + width = 160, -- Default width for common widgets (px) + gap = 6, -- Recommended gap between widgets (px) + margin = 6 -- Recommended internal margin for widgets (px) + }, + window = { + bkgd = gui.palette.neutral, + text = 'rgb(0,0,0)' + }, + button = { + bkgd = gui.palette.base, + highlight = gui.palette.contrast + }, + menubar = { + bkgd = gui.palette.base, + text = gui.palette.altText, + highlight = gui.palette.contrast + }, + menu = { + bkgd = gui.palette.base, + stroke = gui.palette.neutral, + text = gui.palette.altText + }, + dropdown = { + bkgd = gui.palette.bkgd, + stroke = gui.palette.base, + icon = nil, + iconHighlight = nil, + text = gui.palette.text, + textHighlight = gui.palette.altText + }, + desktop = { + bkgd = 'rgb(160,160,160)' + } + } + + if gui.palette.type == 'light' then + gui.style.page.icon = 'carbon' + gui.style.page.iconHighlight = 'pearl' + gui.style.page.text = gui.palette.text + gui.style.page.textHighlight = gui.palette.altText + gui.style.page.textSelect = gui.palette.altText + gui.style.menu.icon = 'pearl' + gui.style.dropdown.icon = 'carbon' + gui.style.dropdown.iconHighlight = 'pearl' + else + gui.style.page.icon = 'pearl' + gui.style.page.iconHighlight = 'carbon' + gui.style.menu.icon = 'carbon' + gui.style.dropdown.icon = 'pearl' + gui.style.dropdown.iconHighlight = 'carbon' + end + + gui.interface = { + fontSize = 11, -- Default font-size for everything (pt) + iconTheme = 'Default', -- Named folder to load the icons from + iconSize = 20 -- Recommended default size for icons (px) and should be linked to fontSize + } + + function convertFontSizes() -- Convert font percentage sizes to their px size + for k,v in pairs(gui.fonts) do + if gui.fonts[k].size then + if string.match(gui.fonts[k].size, '^%-?%d+%%$') then + pct = tonumber(string.match(gui.fonts[k].size, '^(%-?%d+)%%$')) + gui.fonts[k].size = math.floor(gui.interface.fontSize * (pct / 100)) + end + end + end + end + + local path = 'style:values.xml' + if mSys.AnalysePath(path) != ERR_Okay then + path = 'environment:config/values.xml' + if mSys.AnalysePath(path) != ERR_Okay then + path = 'styles:default/values.xml' + end + end + + local xml = obj.new('xml', { path=path }) + + if xml != nil then +--[[ + local err, index = xml.mtFindTag('/colours') + if err == ERR_Okay then + for k,v in pairs(gui.style) do + err, colour = xml.mtGetAttrib(index, k) + if err == ERR_Okay then gui.style[k] = colour end + end + end +--]] + local err, index = xml.mtFindTag('/interface') + if err == ERR_Okay then + for k,v in pairs(gui.interface) do + err, val = xml.mtGetAttrib(index, k) + if err == ERR_Okay then + if string.match(val, '^%-?%d+$') then + gui.interface[k] = tonumber(val) + else + gui.interface[k] = val + end + end + end + end + + convertFontSizes() + + local err, index = xml.mtFindTag('/fonts') + if err == ERR_Okay then + for k,v in pairs(gui.fonts) do + local err, index = xml.mtFindTag("/fonts/font(@name='" .. k .. "')") + if err == ERR_Okay then + local err, face = xml.mtGetAttrib(index, 'face') + if err == ERR_Okay then gui.fonts[k].face = face end + local err, size = xml.mtGetAttrib(index, 'size') + if err == ERR_Okay then + if string.match(size, '^%-?%d+$') then + gui.fonts[k].size = tonumber(size) + elseif string.match(size, '^%-?%d+%%$') then + pct = tonumber(string.match(size, '^(%-?%d+)%%$')) + gui.fonts[k].size = math.floor(gui.interface.fontSize * (pct / 100)) + else + gui.fonts[k].size = size + end + end + end + end + end + + xml = nil + else + convertFontSizes() + end diff --git a/scripts/gui/button.fluid b/scripts/gui/button.fluid index 6a44d41e2..0ab4405e9 100644 --- a/scripts/gui/button.fluid +++ b/scripts/gui/button.fluid @@ -10,14 +10,6 @@ local HEIGHT = math.floor(FONT_MAX_HEIGHT * 1.75) + 1 local ICON_SIZE = HEIGHT * 0.56 local GAP = HEIGHT * 0.35 -local function iconTheme() - if (gui.rgbValue(gui.strToRGB(gui.style.widget.text)) > 127) then - return 'pearl' - else - return 'default' -- The default theme is dark - end -end - gui.button = function(Options) local self = { -- Public variables events = nz(Options.events, { }), @@ -32,7 +24,7 @@ gui.button = function(Options) self.disabled = true self.viewport.acDisable() self.text.opacity = 0.5 - self.bkgd.fill = gui.style.widget.bkgd + self.bkgd.fill = gui.style.button.bkgd if self.events.disable then self.events.disable(self) end self.viewport.acDraw() end @@ -41,7 +33,7 @@ gui.button = function(Options) self.disabled = false self.viewport.acDisable() self.text.opacity = 1.0 - self.bkgd.fill = gui.style.widget.bkgd + self.bkgd.fill = gui.style.button.bkgd if self.events.enable then self.events.enable(self) end self.viewport.acDraw() end @@ -76,7 +68,7 @@ gui.button = function(Options) self.viewport = self.parentViewport.new('VectorViewport', vps) self.bkgd = self.viewport.new('VectorRectangle', { - fill = gui.style.widget.bkgd, + fill = gui.style.button.bkgd, x = gui.style.widget.strokeWidth * 0.5, y = gui.style.widget.strokeWidth * 0.5, width = self.viewport.width - gui.style.widget.strokeWidth, @@ -98,29 +90,33 @@ gui.button = function(Options) if Options.icon then pcall(function() - gui.createIcon(self.viewport.scene, Options.icon, ICON_SIZE, iconTheme()) - - self.iconRender = self.viewport.new('VectorViewport', { - x = GAP, - y = (self.viewport.height - ICON_SIZE) * 0.5, - width = ICON_SIZE, - height = ICON_SIZE, - fill = 'url(#' .. Options.icon .. ')' - }) - - label_offset = (GAP * 0.5) + ICON_SIZE + local icon = gui.createIcon(self.viewport.scene, Options.icon, ICON_SIZE, gui.rgbToIconTheme(gui.style.widget.text)) + + if icon then + self.iconRender = self.viewport.new('VectorViewport', { + x = GAP, + y = (self.viewport.height - icon.size) * 0.5, + width = icon.size, + height = icon.size, + fill = icon.fill + }) + + label_offset = (GAP * 0.5) + ICON_SIZE + end end) end self._textClip = self.viewport.new('VectorViewport', { - x=gui.style.widget.strokeWidth, y=gui.style.widget.strokeWidth, xOffset=gui.style.widget.strokeWidth, yOffset=gui.style.widget.strokeWidth, overflow=VOF_HIDDEN + x = gui.style.widget.strokeWidth, y = gui.style.widget.strokeWidth, + xOffset = gui.style.widget.strokeWidth, yOffset = gui.style.widget.strokeWidth, + overflow = VOF_HIDDEN }) self.text = self._textClip.new('VectorText', { x = GAP + label_offset, - y = FONT_HEIGHT + math.floor((HEIGHT - FONT_HEIGHT - gui.style.widget.strokeWidth - gui.style.widget.strokeWidth) * 0.5), - face = gui.fonts.widget.face, - fontSize = string.format('%.2fpt', gui.fonts.widget.size), + y = FONT_HEIGHT + math.floor((HEIGHT - FONT_HEIGHT - (gui.style.widget.strokeWidth * 2)) * 0.5), + face = gui.fonts.button.face, + fontSize = string.format('%.2fpt', gui.fonts.button.size), fill = gui.style.widget.text, string = Options.text, lineLimit = 1 @@ -157,14 +153,12 @@ gui.button = function(Options) self.viewport.mtSubscribeInput(bit.bor(JTYPE_CROSSING, JTYPE_BUTTON, JTYPE_REPEATED), function(Viewport, Msg) repeat if (Msg.type == JET_CROSSED_IN) then - local highlight = gui.strToRGB(gui.style.widget.bkgd) - highlight.a = highlight.a * 0.5 - self.bkgd.fill = gui.rgbToSVG(highlight) + self.bkgd.fill = gui.style.button.highlight if self.events.cursorEntry then self.events.cursorEntry(self) end elseif (Msg.type == JET_CROSSED_OUT) then - self.bkgd.fill = gui.style.widget.bkgd + self.bkgd.fill = gui.style.button.bkgd if self.events.cursorExit then self.events.cursorExit(self) end diff --git a/scripts/gui/checkbox.fluid b/scripts/gui/checkbox.fluid index 7528c4247..bb08b0a99 100644 --- a/scripts/gui/checkbox.fluid +++ b/scripts/gui/checkbox.fluid @@ -13,7 +13,7 @@ local ICON_SIZE = HEIGHT * 0.56 local GAP = HEIGHT * 0.35 local function iconTheme() - if (gui.rgbValue(gui.strToRGB(gui.style.widget.text)) > 127) then + if (gui.rgbValue(gui.strToRGB(gui.style.page.text)) > 127) then return 'pearl' else return 'default' -- The default theme is dark @@ -47,7 +47,7 @@ gui.checkbox = function(Options) self.disabled = true self.viewport.acDisable() self.text.opacity = 0.5 - self.bkgd.fill = gui.style.widget.bkgd + self.bkgd.fill = gui.style.page.bkgd if self.events.disable then self.events.disable(self) end self.viewport.acDraw() end @@ -56,7 +56,7 @@ gui.checkbox = function(Options) self.disabled = false self.viewport.acDisable() self.text.opacity = 1.0 - self.bkgd.fill = gui.style.widget.bkgd + self.bkgd.fill = gui.style.page.bkgd if self.events.enable then self.events.enable(self) end self.viewport.acDraw() end @@ -88,25 +88,25 @@ gui.checkbox = function(Options) self.viewport = self.parentViewport.new('VectorViewport', vps) self.bkgd = self.viewport.new('VectorRectangle', { - fill = gui.style.widget.bkgd, - x = gui.style.widget.strokeWidth * 0.5, - y = gui.style.widget.strokeWidth * 0.5, - width = HEIGHT - gui.style.widget.strokeWidth, - height = HEIGHT - gui.style.widget.strokeWidth, - roundX = gui.style.widget.strokeWidth * 2, - roundY = gui.style.widget.strokeWidth * 2, - stroke = gui.style.widget.stroke, - strokeWidth = gui.style.widget.strokeWidth, + fill = gui.style.page.bkgd, + x = gui.style.page.strokeWidth * 0.5, + y = gui.style.page.strokeWidth * 0.5, + width = HEIGHT - gui.style.page.strokeWidth, + height = HEIGHT - gui.style.page.strokeWidth, + roundX = gui.style.page.strokeWidth * 2, + roundY = gui.style.page.strokeWidth * 2, + stroke = gui.style.page.stroke, + strokeWidth = gui.style.page.strokeWidth, }) - gui.createIcon(self.viewport.scene, 'items/checkmark', ICON_SIZE, iconTheme()) + local chk_icon = gui.createIcon(self.viewport.scene, 'items/checkmark', ICON_SIZE, iconTheme()) self.iconRender = self.viewport.new('VectorViewport', { x = (HEIGHT - ICON_SIZE) * 0.5, y = (self.viewport.height - ICON_SIZE) * 0.5, width = ICON_SIZE, height = ICON_SIZE, - fill = 'url(#items/checkmark)', + fill = chk_icon.fill, opacity = (function() if self.state == 1 then return 1.0 @@ -132,7 +132,7 @@ gui.checkbox = function(Options) if Options.align == 'right' then self.text.x = 0 - self.bkgd.x = self.viewport.width - HEIGHT + (gui.style.widget.strokeWidth * 0.5) + self.bkgd.x = self.viewport.width - HEIGHT + (gui.style.page.strokeWidth * 0.5) self.iconRender.x = self.viewport.width - HEIGHT + ((HEIGHT - ICON_SIZE) * 0.5) else self.text.x = GAP + (GAP * 0.5) + ICON_SIZE @@ -140,13 +140,13 @@ gui.checkbox = function(Options) self.viewport.mtSubscribeFeedback(bit.bor(FM_HAS_FOCUS, FM_CHILD_HAS_FOCUS, FM_LOST_FOCUS), function(Viewport, Event) if (Event == FM_LOST_FOCUS) then - self.bkgd.stroke = gui.style.widget.stroke + self.bkgd.stroke = gui.style.page.stroke if self.events.lostFocus then self.events.lostFocus(self) end else if self.disabled then - self.bkgd.stroke = gui.style.widget.stroke + self.bkgd.stroke = gui.style.page.stroke else - self.bkgd.stroke = gui.style.widget.strokeFocus + self.bkgd.stroke = gui.style.page.strokeFocus if self.events.focus then self.events.focus(self) end end end diff --git a/scripts/gui/columnview.fluid b/scripts/gui/columnview.fluid index 0343535b8..f824a6d7a 100644 --- a/scripts/gui/columnview.fluid +++ b/scripts/gui/columnview.fluid @@ -22,13 +22,7 @@ local LINE_OFFSET = (LINE_HEIGHT + FONT_HEIGHT) * 0.5 local BANNER_HEIGHT = math.round(LINE_HEIGHT * 1.15) local lColours = { - buttonBackground = 'rgb(240,240,240)', - fillTitleFont = 'rgb(0,0,0)', - fillTitleSortFont = 'rgb(0,0,0)', - fillSelect = 'rgb(0,0,60,140)', - fillBkgdHighlight = 'rgb(0,0,0,10)', - fillBkgdSelectHighlight = 'rgb(0,0,90,140)', - strokeButton = 'rgb(160,160,160)' + strokeButton = 'rgb(160,160,160)' } ---------------------------------------------------------------------------------------------------------------------- @@ -38,55 +32,51 @@ local function columnText(Value, Type) Value = Value.value end - if not Value then - return '' - end + if not Value then return '' end - if (Type == 'bytesize') then + if Type == 'bytesize' then Value = tonumber(Value) if not Value then return '' - elseif (Value < 1024) then + elseif Value < 1024 then return string.format('%.0f', Value) - elseif (Value < 1024 * 1024) then + elseif Value < 1024 * 1024 then return string.format('%.0f KB', Value / 1024) - elseif (Value < 1024 * 1024 * 1024) then + elseif Value < 1024 * 1024 * 1024 then Value = Value / (1024 * 1024) - if (Value >= 10) then + if Value >= 10 then return string.format('%.0f MB', Value) else return string.format('%.1f MB', Value) end - elseif (Value < 1024 * 1024 * 1024 * 1024) then + elseif Value < 1024 * 1024 * 1024 * 1024 then return string.format('%.1f GB', Value / (1024 * 1024 * 1024)) else return string.format('%.1f TB', Value / (1024 * 1024 * 1024 * 1024)) end - elseif (Type == 'date') then - -- The date type can be expressed as "YYYY-MM-DD HH:NN", "YYYY-MM-DD", "YYYY-MM-DDTHH:NN". - - if (not lDate) then lDate = struct.new('DateTime') end + elseif Type == 'date' then + -- The date type can be expressed as 'YYYY-MM-DD HH:NN', 'YYYY-MM-DD', 'YYYY-MM-DDTHH:NN'. + if not lDate then lDate = struct.new('DateTime') end local day, time = string.match(Value, '^(%d%d%d%d%-%d%d?%-%d%d?)[%sT]?(.*)$') - lDate.year, lDate.month, lDate.day = string.match(day, '^(%d+)-(%d+)-(%d+)$') local h, min, sec = string.match(time, '^(%d%d):(%d%d):?(%d?%d?)$') - if (h != nil) then + if h != nil then lDate.hour = h lDate.minute = min lDate.second = sec end return string.format('%4d-%02d-%02d %02d:%02d', lDate.year, lDate.month, lDate.day, lDate.hour, lDate.minute) - elseif (Type == 'numeric') then + elseif Type == 'numeric' then return string.format('%d', nz(tonumber(Value), 0)) - elseif (Type == 'seconds') then + elseif Type == 'seconds' then Value = nz(tonumber(Value), 0) local min = Value / 60 local sec = Value % 60 return string.format('%d:%.2d', min, sec) - elseif (Type == 'float') then + elseif Type == 'float' then return string.format('%.3f', nz(tonumber(Value), 0)) end @@ -100,7 +90,7 @@ local function setColumnGradient(View, Column) local selName = 'colSelect' .. lCounter lCounter = lCounter + 1 - if (nz(Column.align, 'left') == 'right') then + if nz(Column.align, 'left') == 'right' then Column.vecGradient = gui.simpleGradient(View.scene, defName, { { r=0,g=0,b=0,a=0,offset=0.1 }, { r=0,g=0,b=0,a=255,offset=0.2 }, { r=0,g=0,b=0,a=255,offset=1.0 } }, 0, 0, Column.width, 0, 'userspace') @@ -153,19 +143,28 @@ local function highlightItem(View, Item, Highlighted) for k, col in pairs(Item._col) do if col.text then col.text.fill = View.namedCol[k].fillItemSelect end end - Item._vectors.highlight.fill = lColours.fillBkgdSelectHighlight - else + local col = gui.interpolateRGB(gui.strToRGB(gui.style.page.textHighlightBkgd), gui.strToRGB(gui.style.page.textSelectBkgd)) + Item._vectors.highlight.fill = gui.rgbToSVG(col) --gui.style.page.textHighlightBkgd + if Item._vectors.iconImage and Item._iconHighlight then + Item._vectors.iconImage.fill = Item._iconHighlight + end + else -- Highlighted for k, col in pairs(Item._col) do - if col.text then col.text.fill = View.namedCol[k].fillItem end + if col.text then col.text.fill = View.namedCol[k].fillItemSelect end + end + Item._vectors.highlight.fill = gui.style.page.textHighlightBkgd + if Item._vectors.iconImage and Item._iconHighlight then + Item._vectors.iconImage.fill = Item._iconHighlight end - Item._vectors.highlight.fill = lColours.fillBkgdHighlight end - elseif (Item._selected) then + elseif Item._selected then for k, col in pairs(Item._col) do if col.text then col.text.fill = View.namedCol[k].fillItemSelect end end - - Item._vectors.highlight.fill = lColours.fillSelect + Item._vectors.highlight.fill = gui.style.page.textSelectBkgd + if Item._vectors.iconImage and Item._iconHighlight then + Item._vectors.iconImage.fill = Item._iconHighlight + end else if Item.fill then for k, col in pairs(Item._col) do @@ -183,6 +182,10 @@ local function highlightItem(View, Item, Highlighted) end end + if Item._vectors.iconImage then + Item._vectors.iconImage.fill = Item._iconFill + end + if Item._vectors.highlight then Item._vectors.highlight.free() Item._vectors.highlight = nil @@ -195,7 +198,7 @@ local function arrangeColumns(View) local pc = struct.new('PathCommand') for _, col in pairs(View.columns) do - if (col.align == 'right') then + if col.align == 'right' then col.vecTitle.x = col.width - MARGIN else col.vecTitle.x = MARGIN @@ -219,7 +222,7 @@ local function arrangeColumns(View) if View._sort then local col = View._sort.col - if (col.align == 'right') then + if col.align == 'right' then View._sort.icon.x = MARGIN else View._sort.icon.x = col.width - MARGIN - ICON_SIZE @@ -228,7 +231,7 @@ local function arrangeColumns(View) end local function bannerZoneClick(View, Col, X, Y, Value) - if (Value == 1) then return end + if Value == 1 then return end if View._sort and View._sort.icon then View._sort.icon.free() @@ -238,13 +241,13 @@ local function bannerZoneClick(View, Col, X, Y, Value) if View._sort and (View._sort.col == Col) and (View._sort.ascending == true) then View._sort = { col=Col, ascending=false } if not View.iconDescending then - if not View.icons['sort_desc'] then - gui.createIcon(View.scene, 'layout/sort_alpha_desc', ICON_SIZE, nil, 'sort_desc') - View.icons['sort_desc'] = true + if not View._sort_desc then + local info = gui.createIcon(View.scene, 'layout/sort_alpha_desc', ICON_SIZE, gui.rgbToIconTheme(gui.style.widget.text), 'sort_desc') + View._sort_desc = info.fill end View._sort.icon = Col.bannerVP.new('VectorRectangle', { - fill = 'url(#sort_desc)', + fill = View._sort_desc, y = math.round( ((BANNER_HEIGHT - ICON_SIZE) * 0.5)), width = ICON_SIZE, height = ICON_SIZE @@ -253,21 +256,21 @@ local function bannerZoneClick(View, Col, X, Y, Value) else View._sort = { col=Col, ascending=true } if not View.iconAscending then - if not View.icons['sort_asc'] then - View.icons['sort_asc'] = true - gui.createIcon(View.scene, 'layout/sort_alpha_asc', ICON_SIZE, nil, 'sort_asc') + if not View._sort_asc then + local info = gui.createIcon(View.scene, 'layout/sort_alpha_asc', ICON_SIZE, gui.rgbToIconTheme(gui.style.widget.text), 'sort_asc') + View._sort_asc = info.fill end View._sort.icon = Col.bannerVP.new('VectorRectangle', { - fill = 'url(#sort_asc)', - y = math.round( ((BANNER_HEIGHT - ICON_SIZE) * 0.5)), + fill = View._sort_asc, + y = math.round((BANNER_HEIGHT - ICON_SIZE) * 0.5), width = ICON_SIZE, height = ICON_SIZE }) end end - if (Col.align == 'right') then + if Col.align == 'right' then View._sort.icon.x = MARGIN else View._sort.icon.x = Col.width - MARGIN - ICON_SIZE @@ -320,11 +323,8 @@ gui.columnView = function(Options) end View.bannerHeight = BANNER_HEIGHT - View.y = View.bannerHeight + View.y = View.bannerHeight View.banner = { } - if not View.icons then - View.icons = { } - end -- Background graphics @@ -338,25 +338,19 @@ gui.columnView = function(Options) }) View.banner.bkgd = View.banner.viewport.new('VectorRectangle', { - x = 0, - y = 0, - width = '100%', - height = '100%', - fill = lColours.buttonBackground, - stroke = lColours.strokeButton, - strokeWidth = 2 + x = 0, y = 0, width = '100%', height = '100%', + fill = gui.style.button.bkgd, stroke = lColours.strokeButton, strokeWidth = 1 }) View.banner.lines = View.banner.viewport.new('VectorPath', { - stroke = lColours.strokeButton, - strokeWidth = 1 + stroke = lColours.strokeButton, strokeWidth = 1 }) View.banner.viewport.mtSubscribeInput(bit.bor(JTYPE_MOVEMENT, JTYPE_BUTTON), function(Viewport, Events) local ev = Events - while (ev) do - if (ev.type == JET_BUTTON_1) then - if (bit.band(ev.flags, JTYPE_REPEATED) != 0) then + while ev do + if ev.type == JET_BUTTON_1 then + if bit.band(ev.flags, JTYPE_REPEATED) != 0 then return end @@ -415,7 +409,7 @@ gui.columnView = function(Options) -- Rearrange layout local delta_x = X - SizeVP.x col.width = col.width + delta_x - if (col.width < MARGIN) then col.width = MARGIN end + if col.width < MARGIN then col.width = MARGIN end col.vecViewport.width = col.width local scan = col.next @@ -435,7 +429,7 @@ gui.columnView = function(Options) View.scrollbar.setDynamicPageSize(page_width, page_width, Page.height) end - if (col.align == 'right') then -- Realign all text in this column + if col.align == 'right' then -- Realign all text in this column local align_x = col.width - MARGIN for _, item in pairs(View.items) do if item._col and item._col[col.attrib].text then @@ -457,9 +451,9 @@ gui.columnView = function(Options) col.vecTitle.string = nz(col['title'], 'Untitled') if View._sort and (col == View._sort.col) then - col.vecTitle.fill = lcolours.fillTitleSortFont + col.vecTitle.fill = gui.style.widget.text else - col.vecTitle.fill = lColours.fillTitleFont + col.vecTitle.fill = gui.style.widget.text end x = x + col.width @@ -528,10 +522,8 @@ gui.columnView = function(Options) item._highlightEvent = highlightItem - -- Respond to positive item selection by the user (e.g. button click) - item._selectEvent = function(View, Item) - if (Item == View.hItem) then + if Item == View.hItem then Item._highlightEvent(View, Item, true) else Item._highlightEvent(View, Item, false) @@ -546,35 +538,40 @@ gui.columnView = function(Options) if col.showIcons and item.icon then pcall(function() - local uid = item.icon - if item.iconColour then - uid = uid .. '+' .. item.iconColour - end - - if not View.icons[uid] then - gui.createIcon(View.scene, item.icon, ICON_SIZE, item.iconColour, uid) - View.icons[uid] = true + local theme = nz(item.iconTheme, gui.style.page.icon) + local uid = theme .. '+' .. item.icon + local info = gui.createIcon(View.scene, item.icon, ICON_SIZE, theme, uid) + item._iconFill = info.fill + + if gui.style.page.iconHighlight and gui.style.page.iconHighlight != theme then + local theme = gui.style.page.iconHighlight + local uid = theme .. '+' .. item.icon + local info = gui.createIcon(View.scene, item.icon, ICON_SIZE, theme, uid) + item._iconHighlight = info.fill end if not item._vectors.iconImage then item._vectors.iconImage = col.vecViewport.new('VectorRectangle', { - fill = 'url(#' .. uid .. ')', - x = MARGIN, + fill = item._iconFill, + x = MARGIN * 2, y = y + ICON_OFFSET, width = ICON_SIZE, height = ICON_SIZE }) end end) - elseif (col.checkBoxes) then + elseif col.checkBoxes then -- Checkbox mode leverages the icon mechanisms that are already in place. --[[ if not glTick and not tick_error then - obj.new('picture', src="templates:images/tick") then + obj.new('picture', src='templates:images/tick') then end - if (item.checked) glTick->Bitmap->Opacity = 255 - else glTick->Bitmap->Opacity = 40 + if item.checked then + glTick->Bitmap->Opacity = 255 + else + glTick->Bitmap->Opacity = 40 + end --]] end @@ -591,11 +588,11 @@ gui.columnView = function(Options) item._col[attrib].text.y = y + LINE_OFFSET end - if (col.align == 'right') then + if col.align == 'right' then item._col[attrib].text.x = col.width - MARGIN else if col.showIcons then - item._col[attrib].text.x = MARGIN + ICON_SIZE + MARGIN + item._col[attrib].text.x = (MARGIN * 2) + ICON_SIZE + (MARGIN * 2) else item._col[attrib].text.x = MARGIN end @@ -638,7 +635,7 @@ gui.columnView = function(Options) -- NB: Attrib values that evaluate to nil are not permitted/supported. vw.sortColumn = function(View, Column, Ascending) - if (type(Column) == 'string') then + if type(Column) == 'string' then for _, col in pairs(View.columns) do if col['attrib'] == Column then Column = col @@ -650,9 +647,9 @@ gui.columnView = function(Options) end if type(Column) == 'table' then - if (#View.items > 0) then + if #View.items > 0 then local attrib = Column['attrib'] - if (type(View.items[1][attrib]) == 'table') then + if type(View.items[1][attrib]) == 'table' then if View.items[1][attrib]['sort'] then table.sort(View.items, function(a,b) if Ascending then diff --git a/scripts/gui/combobox.fluid b/scripts/gui/combobox.fluid index a18726654..f549013e8 100644 --- a/scripts/gui/combobox.fluid +++ b/scripts/gui/combobox.fluid @@ -6,14 +6,14 @@ Documentation is available in the Parasol Wiki. require 'common' require 'gui' - require 'gui/menu' + require 'gui/dropdown' local FONT_MAX_HEIGHT, FONT_HEIGHT = gui.getFontHeight(gui.fonts.widget) local BOX_HEIGHT = math.floor(FONT_MAX_HEIGHT * 1.35) + 1 local MARGIN = math.floor(FONT_HEIGHT * 0.5) + 1 local function iconTheme() - if (gui.rgbValue(gui.strToRGB(gui.style.widget.text)) > 127) then + if (gui.rgbValue(gui.strToRGB(gui.style.page.text)) > 127) then return 'pearl' else return 'default' -- The default theme is dark @@ -58,7 +58,7 @@ gui.combobox = function(Options) self.disabled = true self.viewport.acDisable() self.text.opacity = 0.5 - self.bkgd.fill = gui.style.widget.bkgd + self.bkgd.fill = gui.style.page.bkgd if self.events.disable then self.events.disable(self) end self.viewport.acDraw() end @@ -67,7 +67,7 @@ gui.combobox = function(Options) self.disabled = false self.viewport.acDisable() self.text.opacity = 1.0 - self.bkgd.fill = gui.style.widget.bkgd + self.bkgd.fill = gui.style.page.bkgd if self.events.enable then self.events.enable(self) end self.viewport.acDraw() end @@ -132,36 +132,33 @@ gui.combobox = function(Options) end self.bkgd = self.inputViewport.new('VectorRectangle', { - fill = gui.style.widget.bkgd, - x = 0, - y = 0, - width = '100%', - height = '100%', + fill = gui.style.page.bkgd, x = 0, y = 0, width = '100%', height = '100%' }) local ICON_SIZE = FONT_HEIGHT - gui.createIcon(self.viewport.scene, 'arrows/down', ICON_SIZE, iconTheme()) + local down_icon = gui.createIcon(self.viewport.scene, 'arrows/down', ICON_SIZE, iconTheme()) self.iconRender = self.viewport.new('VectorViewport', { xOffset = MARGIN, y = (self.viewport.height - ICON_SIZE) * 0.5, width = ICON_SIZE, height = ICON_SIZE, - fill = 'url(#arrows/down)' + fill = down_icon.fill }) if not Options.flushEdges then - self.bkgd.stroke = gui.style.widget.stroke - self.bkgd.strokeWidth = gui.style.widget.strokeWidth - self.bkgd.roundX = gui.style.widget.strokeWidth * 2 - self.bkgd.roundY = gui.style.widget.strokeWidth * 2 + self.bkgd.stroke = gui.style.page.stroke + self.bkgd.strokeWidth = gui.style.page.strokeWidth + self.bkgd.roundX = gui.style.page.strokeWidth * 2 + self.bkgd.roundY = gui.style.page.strokeWidth * 2 end self._textClip = self.inputViewport.new('VectorViewport', { cursor = (function() if self.allowCustom then return 'text' end end)(), - x=gui.style.widget.strokeWidth, y=gui.style.widget.strokeWidth, xOffset=self.iconRender.width + MARGIN + MARGIN, yOffset=gui.style.widget.strokeWidth, overflow=VOF_HIDDEN + x=gui.style.widget.strokeWidth, y=gui.style.widget.strokeWidth, + xOffset=self.iconRender.width + MARGIN + MARGIN, yOffset=gui.style.widget.strokeWidth, overflow=VOF_HIDDEN }) local defaultText = Options.text @@ -174,7 +171,7 @@ gui.combobox = function(Options) y = FONT_HEIGHT + math.floor((BOX_HEIGHT - FONT_HEIGHT - (gui.style.widget.strokeWidth * 2)) * 0.5), face = gui.fonts.widget.face, fontSize = string.format('%.2fpt', gui.fonts.widget.size), - fill = gui.style.widget.text, + fill = gui.style.page.text, string = defaultText, lineLimit = 1, textFlags = (function() @@ -190,7 +187,7 @@ gui.combobox = function(Options) self.viewport.mtSubscribeFeedback(bit.bor(FM_HAS_FOCUS, FM_CHILD_HAS_FOCUS, FM_LOST_FOCUS), function(Viewport, Event) if (Event == FM_LOST_FOCUS) then - self.bkgd.stroke = gui.style.widget.stroke + self.bkgd.stroke = gui.style.page.stroke if self.events.lostFocus then self.events.lostFocus(self) end if self.allowCustom then reportFeedback(self) @@ -200,9 +197,9 @@ gui.combobox = function(Options) else self._lastGoodInput = self.text.string if self.disabled then - self.bkgd.stroke = gui.style.widget.stroke + self.bkgd.stroke = gui.style.page.stroke else - self.bkgd.stroke = gui.style.widget.strokeFocus + self.bkgd.stroke = gui.style.page.strokeFocus if self.events.focus then self.events.focus(self) end end end @@ -230,10 +227,9 @@ gui.combobox = function(Options) until Msg == nil end) - self.menu = gui.menu({ + self.menu = gui.dropdown({ relative = self.viewport, client = self.inputViewport, - style = 'list', config = Options.items, lineLimit = 8, feedback = function(Menu, Item) diff --git a/scripts/gui/divider.fluid b/scripts/gui/divider.fluid index 167052f97..dcef0c8e4 100644 --- a/scripts/gui/divider.fluid +++ b/scripts/gui/divider.fluid @@ -30,14 +30,18 @@ local function arrangeAll(self, Middle) if (self._orientation == 'h') then local margin = 0 - self._div = { x = a_len+1, y = self._primary.y + margin, width = GAP-2, height = self._primary.height - (margin*2) } - self._pattern.x = self._vp.absX + a_len - self._pattern.y = self._primary.absY + margin + self._div = { x = a_len, y = self._primary.y + margin, width = GAP, height = self._primary.height - (margin*2) } + if self._pattern then + self._pattern.x = self._vp.absX + a_len + self._pattern.y = self._primary.absY + margin + end else local margin = 0 - self._div = { x = self._primary.x + margin, y = a_len+1, width = self._primary.width - (margin*2), height = GAP-2 } - self._pattern.x = self._primary.absX + margin - self._pattern.y = self._vp.absY + a_len + self._div = { x = self._primary.x + margin, y = a_len, width = self._primary.width - (margin*2), height = GAP } + if self._pattern then + self._pattern.x = self._primary.absX + margin + self._pattern.y = self._vp.absY + a_len + end end self._secondary[self._anchor] = a_len + GAP @@ -103,22 +107,23 @@ gui.divider = function(Options) local div_name = 'divider-bkgd-' .. self._vp.id if (Options.style != 'none') then + local opacity = 0.15 if (self._orientation == 'h') then -- Top to bottom tiling self._pattern = self._vp.scene.new('VectorPattern', { - name='div_pattern', x=0, y=0, pageWidth=GAP, pageHeight=GAP*4, width=GAP, height=GAP*4, units=VUNIT_USERSPACE, spreadMethod=VSPREAD_REPEAT + name = 'div_pattern', x = 0, y = 0, pageWidth = GAP, pageHeight = GAP*4, width = GAP, height = GAP*4, + units = VUNIT_USERSPACE, spreadMethod = VSPREAD_REPEAT }) - local pt = string.format('0,0, %d,%d, %d,%d 0,%d', GAP, GAP, GAP, GAP*4, GAP) - self._pattern.viewport.new('VectorRectangle', { fill='rgb(0,0,0,20)' }) - self._pattern.viewport.new('VectorPolygon', { points=pt, fill='rgb(0,0,0,20)' }) + + local pt = string.format('%d,%d, %d,%d, %d,%d %d,%d', 0, 0, GAP, GAP*2, GAP, GAP*4, 0, GAP*2) + self._pattern.viewport.new('VectorPolygon', { points = pt, fill = gui.palette.base, opacity = opacity }) else -- Left to right tiling self._pattern = self._vp.scene.new('VectorPattern', { - name='div_pattern', x=0, y=0, pageWidth=GAP*3, pageHeight=GAP, width=GAP*3, height=GAP, units=VUNIT_USERSPACE, spreadMethod=VSPREAD_REPEAT + name = 'div_pattern', x = 0, y = 0, pageWidth = GAP*4, pageHeight=GAP, width=GAP*4, height=GAP, + units = VUNIT_USERSPACE, spreadMethod = VSPREAD_REPEAT }) - local pt = string.format('0,0, %d,0, %d,%d %d,%d', GAP, GAP*2, GAP, GAP, GAP) - self._pattern.viewport.new('VectorPolygon', { points=pt, fill='rgb(0,0,0,20)' }) - local pt = string.format('%d,0, %d,0, %d,%d %d,%d', GAP, GAP+GAP, GAP*2+GAP, GAP, GAP+GAP, GAP) - self._pattern.viewport.new('VectorPolygon', { points=pt, fill='rgb(0,0,0,40)' }) + local pt = string.format('%d,%d, %d,%d, %d,%d %d,%d', GAP*2, 0, GAP*4, 0, GAP*2, GAP, 0, GAP) + self._pattern.viewport.new('VectorPolygon', { points = pt, fill = gui.palette.base, opacity = opacity }) end check(self._vp.scene.mtAddDef(div_name, self._pattern)) @@ -140,7 +145,7 @@ gui.divider = function(Options) if (Options.style != 'none') then self._dividerVP.new('VectorRectangle', { - name='div_fill', x=0, y=0, width='100%', height='100%', fill='url(#' .. div_name .. ')' + name='div_fill', x='1%', y='1%', width='98%', height='98%', fill='url(#' .. div_name .. ')' }) end diff --git a/scripts/gui/dropdown.fluid b/scripts/gui/dropdown.fluid new file mode 100644 index 000000000..a3cedeaea --- /dev/null +++ b/scripts/gui/dropdown.fluid @@ -0,0 +1,343 @@ +--[[ +Internal script for combobox drop-down menus. +--]] + + require 'common' + require 'gui' + include 'display' + + if not mGfx then mGfx = mod.load('display') end + +local FONT_MAX_HEIGHT, FONT_HEIGHT = gui.getFontHeight(gui.fonts.menu) +local ITEM_HEIGHT = math.floor(FONT_MAX_HEIGHT * 1.5) +local VMARGIN = math.floor(ITEM_HEIGHT * 0.33) +local HMARGIN = 6 +local ICON_SIZE = math.floor(ITEM_HEIGHT * 0.8) +local ITEM_SPACING = 1.2 + +gui.dropdown = function(Options) + local self = { -- Public variables + surface = nil, + timeShow = 0, + timeHide = 0, + visible = false, + client = Options.client, + feedback = Options.feedback, + x = nz(Options.x, 0), + y = nz(Options.y, 0), + relative = Options.relative, + items = { } + } + + local function initVectorScene() + local showIcons = nz(Options.showIcons, true) + local TEXT_X = HMARGIN + + if showIcons then + local iconsPresent = false + for _, item in ipairs(Options.config) do + if item.icon then + iconsPresent = true + TEXT_X = HMARGIN + ICON_SIZE + HMARGIN + HMARGIN + end + end + end + + -- To use the clip, set the 'mask' field of any drawable vector. + self.clip = self.scene.new('VectorClip', { units='BoundingBox' }) + local clipRect = self.clip.viewport.new('VectorRectangle', { + x = 1.5, y = 1.5, roundX = 3, roundY = 3, width = 1, height = 1 + }) + + self.viewport.new('VectorRectangle', { -- Background + fill = gui.style.dropdown.bkgd, + x = 1.5, y = 1.5, roundX = 3, roundY = 3, width = 1, height = 1, + resizeEvent = function(Viewport, Vector, X, Y, Width, Height) + Vector.width = Width - (Vector.x * 2) + Vector.height = Height - (Vector.y * 2) + clipRect.width = Width - (Vector.x * 2) + clipRect.height = Height - (Vector.y * 2) + end + }) + + self.highlight = self.viewport.new('VectorRectangle', { + x = 2, y = 0, xOffset = 2, height = ITEM_HEIGHT, fill = gui.palette.contrast, visibility = 'hidden' + }) + + self.viewport.new('VectorRectangle', { -- Border + stroke = gui.style.dropdown.stroke, + strokeWidth = 1.5, x = 1.5, y = 1.5, roundX = 3, roundY = 3, width = 1, height = 1, + resizeEvent = function(Viewport, Vector, X, Y, Width, Height) + Vector.width = Width - (Vector.x * 2) + Vector.height = Height - (Vector.y * 2) + end + }) + + self.items = { } + local widestItem = 0 + local widestKey = 0 + local y = VMARGIN + for _, item in ipairs(Options.config) do + if item['item'] then + local mi = { y=y, config=item } + local vText = self.viewport.new('VectorText', { + x = TEXT_X, + face = gui.fonts.menu.face, + fontSize = string.format('%.2fpt', gui.fonts.menu.size), + fill = gui.style.page.text, + align = 'left', + string = item['item'] + }) + + local err, bx, by, bw, bh = vText.mtGetBoundary(0) + + mi.text = vText + mi.textY = y + ((vText.lineSpacing + vText.displayHeight) * 0.5) + + if bw > widestItem then widestItem = bw end + + if showIcons and item.icon then + pcall(function() + local info = gui.createIcon(self.viewport.scene, item.icon, ICON_SIZE, gui.style.dropdown.icon) + mi.iconFill = info.fill + + if gui.style.dropdown.iconHighlight and gui.style.dropdown.iconHighlight != gui.style.dropdown.icon then + local info = gui.createIcon(self.viewport.scene, item.icon, ICON_SIZE, gui.style.dropdown.iconHighlight) + mi.iconHighlightFill = info.fill + end + + mi.iconView = self.viewport.new('VectorRectangle', { + x = HMARGIN, y = y + math.floor((ITEM_HEIGHT - ICON_SIZE) * 0.5), width = ICON_SIZE, height = ICON_SIZE, fill = info.fill + }) + end) + end + + vText.y = mi.textY + mi.height = vText.lineSpacing * ITEM_SPACING + y = y + mi.height + + table.insert(self.items, mi) + end + end + + self.surface.width = TEXT_X + widestItem + (HMARGIN * 3) + widestKey + HMARGIN + self.surface.height = y + VMARGIN + end + + -- toggle() alternates the visible state of the menu. A TimeLapse is supported so that rapid changes to + -- menu visibility can be avoided. + + local lastTime = 0 + self.toggle = function(TimeLapse) + local timelapse + if TimeLapse and (TimeLapse >= 0) then + timelapse = TimeLapse * 1000 + else + timelapse = 5000 + end + + local currentTime = mSys.PreciseTime() + if self.timeShow > self.timeHide then -- Hide the menu + if (currentTime - self.timeShow >= timelapse) then self.hide() end + lastTime = currentTime + return 0 + else + if (currentTime - self.timeHide >= timelapse) then self.show() end + lastTime = currentTime + return 1 + end + end + + self.selectItem = function() + + end + + self.getItem = function() + + end + + self.hide = function() + self.surface.acHide() + self.timeHide = mSys.PreciseTime() + end + + self.show = function() + local surface = self.surface + if bit.band(surface.flags, RNF_VISIBLE) != 0 then return end + + if self.relative then + -- Correct the position of the menu according to the relative vector that it is offset from. + + local err, target = mGfx.GetSurfaceInfo(self.relative.scene.surface) + if err == ERR_Okay then + local rel = { absX = target.absX, absY = target.absY } + local target = { absX = 0, absY = 0, height = 4096 } + + if Options.target then + local err, target = mGfx.GetSurfaceInfo(Options.target) + if err == ERR_Okay then + target.absX = target.absX + target.absY = target.absY + target.height = target.height + end + else + local err, display = mGfx.GetDisplayInfo(0) + if err == ERR_Okay then + target.height = display.height + end + end + + local x = rel.absX + self.x - target.absX + local y = rel.absY + self.y - target.absY + + if lReverseY then + y = rel.absY + nz(Options.y, 0) - target.absY - surface.height + end + + if y + surface.height > target.height then + y = y - surface.height - nz(Options.y, 0) + end + + surface.acMoveToPoint(x, y, 0, bit.bor(MTF_X, MTF_Y)) + end + end + + self.surface.acShow() + self.surface.acMoveToFront() + self.timeShow = mSys.PreciseTime() + end + + local function highlightItem(Item) + if Item == self.hItem then + return + elseif Item then + if Item.lineBreak or Item.disabled then + return + end + end + + if self.hItem then -- Redraw the previously highlighted item + self.hItem.text.fill = gui.style.dropdown.text + if self.hItem.iconView then + self.hItem.iconView.fill = self.hItem.iconFill + end + self.surface.mtScheduleRedraw() + self.hItem = nil + end + + self.hItem = Item + + if Item then -- Draw the newly highlighted area + Item.text.fill = gui.style.dropdown.textHighlight + if Item.iconView then + Item.iconView.fill = Item.iconHighlightFill + end + self.highlight.y = Item.y + self.highlight.height = Item.height + self.highlight.visibility = 'visible' + self.surface.mtScheduleRedraw() + else + self.highlight.visibility = 'hidden' + self.surface.mtScheduleRedraw() + end + end + + -- Main entry point -- + + if not Options.config then error('A config value is required to define the Menu items') end + + self.surface = obj.new('surface') + self.surface.name = 'menu' + self.surface.width = nz(Options.width, 400) + self.surface.parent = Options.target + self.surface.flags = bit.bor(RNF_STICK_TO_FRONT, RNF_COMPOSITE) + self.surface.x = -10000 + self.surface.y = -10000 + self.surface.windowType = 'NONE' + self.surface.height = 400 + if self.surface.init() != ERR_Okay then error('Failed to initialise surface.') end + + self.scene = obj.new('VectorScene', { flags=VPF_RESIZE, surface=self.surface }) + self.viewport = self.scene.new('VectorViewport', { }) + + self.surface.subscribe('free', function(Surface, Args) + self.surface = nil + end) + + self.surface.subscribe('hide', function(Surface, Args) + self.visible = false + self.timeHide = mSys.preciseTime() + end) + + self.surface.subscribe('show', function(Surface, Args) + self.visible = true + self.timeShow = mSys.preciseTime() + + -- Keyboard support requires a client reference to grab input from. + + if self.client and (not self._subscribedKb) then + if self.client.mtSubscribeKeyboard(function(Viewport, Qualifiers, Value, Unicode) + if not self.visible then + self._subscribedKb = false + check(ERR_Terminate) + end + + if bit.band(Qualifiers, KQ_PRESSED) == 0 then return end + if Value == KEY_UP then + elseif Value == KEY_DOWN then + + elseif Value == KEY_RETURN then + + end + end) == ERR_Okay then + self._subscribedKb = true + end + end + end) + + self.viewport.mtSubscribeInput(bit.bor(JTYPE_MOVEMENT, JTYPE_BUTTON, JTYPE_CROSSING), function(Viewport, Events) + local ev = Events + while ev do + if ev.type == JET_BUTTON_1 then + if ev.value == 1 then + if self.hItem then -- Menu item activated + if self.hItem.config.feedback then + self.hItem.config.feedback(self, self.hItem.config) + end + if self.feedback then + self.feedback(self, self.hItem.config) + end + self.surface.acHide() + end + end + elseif ev.type == JET_ABS_XY then + local highlightFound = false + for _, item in pairs(self.items) do + if not item.lineBreak then + if (ev.y >= item.y) and (ev.y < item.y + item.height) then + if self.hItem != item then + highlightItem(item) + end + highlightFound = true + break + end + end + end + + -- Remove existing menu highlighting if the cursor is no longer positioned over a highlight-able item. + + if not highlightFound and self.hItem then + highlightItem(nil) + end + elseif (ev.type == JET_CROSSED_OUT) then + if self.hItem then highlightItem(nil) end + end + + ev = ev.next + end + end) + + initVectorScene() + + return self +end diff --git a/scripts/gui/filedialog.fluid b/scripts/gui/filedialog.fluid index 8fc71cbd6..a8bd2b26b 100644 --- a/scripts/gui/filedialog.fluid +++ b/scripts/gui/filedialog.fluid @@ -107,11 +107,17 @@ gui.dialog.file = function(Options) self.viewport = self.window:clientViewport({ }) + local bkgd = self.viewport.new('VectorRectangle', { + x=0, y=0, xOffset=0, height=1, fill=gui.palette.base + }) + self.toolbar = gui.toolbar({ - target = self.viewport, - x = 0, - y = 0, - xOffset = 0, + target = self.viewport, + iconTheme = 'pearl', + x = 0, + y = 0, + xOffset = 0, + flush = true, createItems = function(Bar) Bar.addGroup(1, 'Navigation', 2) @@ -163,6 +169,8 @@ gui.dialog.file = function(Options) end }) + bkgd.height = self.toolbar.viewport.height + self.pathbox = gui.input({ target = self.viewport, x = 0, diff --git a/scripts/gui/fileview.fluid b/scripts/gui/fileview.fluid index 9d352780d..d7e2a5480 100644 --- a/scripts/gui/fileview.fluid +++ b/scripts/gui/fileview.fluid @@ -57,7 +57,7 @@ end local function parentWindow(Surface) local scan = obj.find(Surface.parent) while scan do - if (mSys.GetClassID(mSys.GetOwnerID(scan.id)) == ID_WINDOW) then + if mSys.GetClassID(mSys.GetOwnerID(scan.id)) == ID_WINDOW then return scan end scan = obj.find(scan.parent) @@ -96,7 +96,7 @@ end local function updateFileAttributes(Item, Info) if Item.date then - if (Item.type == 'folder') then + if Item.type == 'folder' then Item.date.sort = 'D' .. sortNum(Info.timestamp) else Item.date.sort = 'F' .. sortNum(Info.timestamp) @@ -202,19 +202,21 @@ local function applyFilters(self) end local function displayFilters(self) - if (#self.filterList < 1) then return end + if #self.filterList < 1 then return end if not self.filterViewport then -- Construct the filter list + local bkgd = gui.interpolateRGB(gui.strToRGB(gui.palette.base), gui.strToRGB(gui.palette.bkgd), 0.1) + self.filterViewport = self.view.viewport.new('VectorViewport', { visibility = VIS_HIDDEN, x = 0, y = self.toolbar.viewport.height, xOffset = 0, height = 1 }) - self.filterViewport.new('VectorRectangle', { width='100%', height='100%', fill='rgb(80,80,90)' }) + self.filterViewport.new('VectorRectangle', { width='100%', height='100%', fill=gui.rgbToSVG(bkgd) }) local height = 2, text_x, text_y, item_height, descent for _, item in ipairs(self.filterList) do item.vp = self.filterViewport.new('VectorViewport', { x = 0, y = height, width = '100%', height = 1 }) - item.highlight = item.vp.new('VectorRectangle', { x = 0, y = 0, width='100%', height='100%', fill='#ff5b00', visibility = VIS_HIDDEN }) - item.txt = item.vp.new('VectorText', { x=0, y=0, string=item.name, fill='rgb(255,255,255)', face='Noto Sans', fontSize=12 }) + item.highlight = item.vp.new('VectorRectangle', { x = 0, y = 0, width='100%', height='100%', fill=gui.palette.prime, visibility = VIS_HIDDEN }) + item.txt = item.vp.new('VectorText', { x=0, y=0, string=item.name, fill=gui.palette.altText, face='Noto Sans', fontSize=12 }) if not descent then descent = math.round(item.txt.descent) height = descent @@ -261,7 +263,7 @@ local function displayFilters(self) -- Toggle the filter list - if (self.filterViewport.visibility != VIS_HIDDEN) then + if self.filterViewport.visibility != VIS_HIDDEN then self.filterViewport.visibility = VIS_HIDDEN local list_y = self._reserved_height self.view.window.y = list_y @@ -369,10 +371,12 @@ local function createFileItem(self, Info) local total_size = nil local free_space = nil local device = obj.new('storagedevice', { volume = Info.name .. ':' } ) - if bit.band(device.deviceFlags, bit.bor(DEVICE_FLOPPY_DISK, DEVICE_FIXED, DEVICE_HARD_DISK, DEVICE_COMPACT_DISC)) != 0 then + if bit.band(device.deviceFlags, DEVICE_BOOKMARK) != 0 then -- User shortcut + colour = 'carbon' + elseif bit.band(device.deviceFlags, bit.bor(DEVICE_FLOPPY_DISK, DEVICE_FIXED, DEVICE_HARD_DISK, DEVICE_COMPACT_DISC)) != 0 then colour = 'green' - if (device.deviceSize >= 1) then total_size = sortNum(device.deviceSize) end - if (device.bytesFree >= 1) then free_space = sortNum(device.bytesFree) end + if device.deviceSize >= 1 then total_size = sortNum(device.deviceSize) end + if device.bytesFree >= 1 then free_space = sortNum(device.bytesFree) end end local display_name = Info.name ..':' @@ -384,7 +388,7 @@ local function createFileItem(self, Info) new_item = { type = 'volume', icon = icon, - iconColour = colour, + iconTheme = colour, sort = '\x02' .. Info.name:lower(), filename = Info.name, -- Unique insensitive = true, @@ -407,7 +411,7 @@ local function createFileItem(self, Info) new_item = { type = 'folder', icon = getFileIcon(self.path .. Info.name), - iconColour = 'yellow', + iconTheme = 'yellow', sort = '\x03' .. Info.name:lower(), filename = Info.name, name = { sort = 'D' .. display_name:lower(), value = display_name }, @@ -418,7 +422,7 @@ local function createFileItem(self, Info) size = { sort = sortNum(0), value = nil } -- Dummy required for sorting } - if (Info.modified.year != 0) then + if Info.modified.year != 0 then new_item.date = { sort = 'D' .. sortNum(Info.timestamp), value = printableTime(Info.modified) } end elseif bit.band(Info.Flags, RDF_FILE) != 0 then @@ -577,7 +581,7 @@ gui.fileview = function(View, Options) if bit.band(info.Flags, RDF_VOLUME) != 0 and bit.band(info.Flags, RDF_HIDDEN) != 0 then -- Ignore hidden volumes - elseif (#self.view.items == 0) then -- Empty view, this is the first file. + elseif #self.view.items == 0 then -- Empty view, this is the first file. addFileItem(self, info) break else @@ -601,13 +605,13 @@ gui.fileview = function(View, Options) end end - if (#self.view.items > 0) then -- Check for deleted files + if #self.view.items > 0 then -- Check for deleted files local path = nz(self.path,'') if not self.path then -- Do not resolve the path when at the root view else -- Use ResolvePath() to prevent problems with multi-folder volumes local err, resolved_path = mSys.ResolvePath(path, RSF_NO_FILE_CHECK) - if (err == ERR_Okay) then + if err == ERR_Okay then path = resolved_path end end @@ -662,7 +666,7 @@ gui.fileview = function(View, Options) local function pathWatch(MonitoredFile, Path, Custom, Flags) if self.inRefresh then return end - if (Flags == 0) then -- No flags means a change has occurred but the host is unable to tell us what happened. + if Flags == 0 then -- No flags means a change has occurred but the host is unable to tell us what happened. self.refresh() return end @@ -671,10 +675,10 @@ gui.fileview = function(View, Options) if (bit.band(Flags, MFF_DELETE) != 0 and bit.band(Flags, MFF_SELF) != 0) or bit.band(Flags, MFF_UNMOUNT) != 0 then - if (self.path:sub(1,2) == 'cd') then - elseif (self.path:sub(1,4) == 'disk') then + if self.path:sub(1,2) == 'cd' then + elseif self.path:sub(1,4) == 'disk' then else -- Check that the folder is definitely gone and that this is not a mis-report. - if (mSys.AnalysePath(self.path, 0) != ERR_Okay) then + if mSys.AnalysePath(self.path, 0) != ERR_Okay then self.browse(nil) end end @@ -685,7 +689,7 @@ gui.fileview = function(View, Options) local info, info_err if bit.band(Flags, MFF_DELETE) == 0 then info_err, info = mSys.GetFileInfo(self.path .. nz(Path,'')) - if (info_err == ERR_Okay) then + if info_err == ERR_Okay then if lNoFiles and bit.band(info.Flags, RDF_FILE) != 0 then return end -- Use the true file name with the trailing slash if it is a folder (important -- for symbolically linked directories). @@ -696,14 +700,14 @@ gui.fileview = function(View, Options) end if bit.band(Flags, MFF_CREATE) != 0 then - if (info_err == ERR_Okay) then + if info_err == ERR_Okay then addFileItem(self, info) self.view.sort() end elseif bit.band(Flags, MFF_DELETE) != 0 then deleteItem(Path) elseif bit.band(Flags, MFF_MOVED) != 0 then -- Determine if the file has been moved in or moved out - if (info_err == ERR_Okay) then + if info_err == ERR_Okay then -- It is possible that the moved file is replacing an already existing file in -- the view (i.e. rename operation), so do a tag-check first. @@ -714,7 +718,7 @@ gui.fileview = function(View, Options) deleteItem(Path) end elseif bit.band(Flags, bit.bor(MFF_ATTRIB, MFF_CLOSED)) != 0 and File then - if (info_err == ERR_Okay) then + if info_err == ERR_Okay then local item = findItem(Path) if item then updateFileAttributes(item, info) @@ -754,7 +758,7 @@ gui.fileview = function(View, Options) for _,item in pairs(Items) do local err, class_id, command = mSys.IdentifyFile(self.path .. item.name.value, Mode, 0) - if (err == ERR_Okay) then + if err == ERR_Okay then obj.new('task', { path = command }).acActivate() end end @@ -786,7 +790,7 @@ gui.fileview = function(View, Options) end local function responseRename(Dialog, Response, State) - if (Response.id > 0) then + if Response.id > 0 then local dir = false if string.find(Dialog.var.src, '^.+[:/\\]$') then dir = true @@ -797,11 +801,11 @@ gui.fileview = function(View, Options) if Dialog.var.src == dest then return end local err, path = mSys.ResolvePath(dest, bit.bor(RSF_NO_FILE_CHECK, RSF_CASE_SENSITIVE)) - if (err == ERR_Okay) then -- Use ResolvePath() to prevent problems with multi-folder volumes + if err == ERR_Okay then -- Use ResolvePath() to prevent problems with multi-folder volumes err = mSys.AnalysePath(path, 0) end - if (err == ERR_Okay) then -- The destination exists + if err == ERR_Okay then -- The destination exists self.dlgRenameReplace = gui.dialog.message({ title = 'Confirmation Required', message = 'A file already exists that uses this name. Are you sure that you want to overwrite it?', @@ -826,10 +830,10 @@ gui.fileview = function(View, Options) local item = findItem(Dialog.var.name) if item then local new_name = State.input - if (item.type == 'folder') then + if item.type == 'folder' then item.name = new_name .. '/' item.filename = new_name .. '/' - elseif (item.type == 'volume') then + elseif item.type == 'volume' then item.name = new_name .. ':' item.filename = new_name .. ':' else @@ -865,7 +869,7 @@ gui.fileview = function(View, Options) self.browse = function(Path) if not nz(Path) or (Path == ':') then Path = nil end - if (Path == self.path) then return self.path end + if Path == self.path then return self.path end msg('fileview.browse("' .. nz(Path, 'NIL') .. '")') @@ -1071,7 +1075,7 @@ gui.fileview = function(View, Options) popover = self.window, modal = true, feedback = function(Dialog, Response, State) - if (Response.id > 0) then + if Response.id > 0 then self.view.deselectAll() local statement = '' @@ -1195,7 +1199,7 @@ gui.fileview = function(View, Options) if item then table.insert(items, item) end local current_time = mSys.PreciseTime() - if (current_time - msg_time > 20000) then + if current_time - msg_time > 20000 then if #items > 1 then self.view.addItems(items) items = { } @@ -1324,24 +1328,24 @@ gui.fileview = function(View, Options) -- NB: Sys-keys should only be enabled if cut/copy/paste support is not implemented in the core -- application. - if (Value == KEY_C) then + if Value == KEY_C then copy_files() - elseif (Value == KEY_X) then + elseif Value == KEY_X then cut_files() - elseif (Value == KEY_V) then + elseif Value == KEY_V then paste_files() - elseif (Value == KEY_A) then + elseif Value == KEY_A then self.view.selectAll() end - elseif (Value == KEY_DELETE) then + elseif Value == KEY_DELETE then self.deleteFiles() end end) self.view.viewport.mtSubscribeFeedback(bit.bor(FM_HAS_FOCUS, FM_CHILD_HAS_FOCUS, FM_LOST_FOCUS), function(Viewport, Event) - if (Event == FM_HAS_FOCUS) then + if Event == FM_HAS_FOCUS then self.hasFocus = true - elseif (Event == FM_LOST_FOCUS) then + elseif Event == FM_LOST_FOCUS then self.hasFocus = false end end) @@ -1358,7 +1362,7 @@ gui.fileview = function(View, Options) return end - if (Datatypes[1] == DATA_FILE) then + if Datatypes[1] == DATA_FILE then local items = self.view.dragItems if #items > 0 then local files = { } @@ -1452,12 +1456,12 @@ gui.fileview = function(View, Options) if lOptions.autoMode then local tags = { Item, -1 } - if (tags[1] != -1) then - if (lOptions.autoMode == 'open') then + if tags[1] != -1 then + if lOptions.autoMode == 'open' then openFiles(tags, 'Open') - elseif (lOptions.autoMode == 'edit') then + elseif lOptions.autoMode == 'edit' then openFiles(tags, 'Edit') - elseif (lOptions.autoMode == 'view') then + elseif lOptions.autoMode == 'view' then openFiles(tags, 'View') end end @@ -1470,9 +1474,12 @@ gui.fileview = function(View, Options) end if Options.navigationBar then - local bkgd = self.view.viewport.new('VectorRectangle', { x=0, y=0, xOffset=0, height=1, fill='rgb(0,0,0,20)' }) + local bkgd = self.view.viewport.new('VectorRectangle', { + x=0, y=0, xOffset=0, height=1, fill=gui.palette.base + }) self.toolbar = gui.toolbar({ + iconTheme = 'pearl', target = self.view.viewport, x = 0, y = 0, @@ -1502,7 +1509,7 @@ gui.fileview = function(View, Options) end Bar.addItem(3, 'Bookmark', 'Create Bookmark', 'items/new_bookmark', function() - if (string.len(self.path) < 3) then return end + if not self.path or (string.len(self.path) < 3) then return end local current_path = self.path diff --git a/scripts/gui/fontdialog.fluid b/scripts/gui/fontdialog.fluid index 24efb2ebe..fb5df9027 100644 --- a/scripts/gui/fontdialog.fluid +++ b/scripts/gui/fontdialog.fluid @@ -126,7 +126,7 @@ Fusce auctor metus egestas commodo laoreet. Morbi sed venenatis augue. Maecenas lFontsSorted = { } local font = list local index = 0 - while (font) do + while font do lFonts[font.name] = { } lFonts[font.name].order = index lFonts[font.name].name = font.name @@ -265,13 +265,8 @@ Fusce auctor metus egestas commodo laoreet. Morbi sed venenatis augue. Maecenas }) self.exampleBkgd = self.exampleVP.new('VectorRectangle', { - fill = 'rgb(253,255,246)', - stroke = 'rgb(0,0,0,64)', - strokeWidth = 2, - x = 0, - y = 0, - width = '100%', - height = '100%' + fill = 'rgb(253,255,246)', stroke = 'rgb(0,0,0,64)', strokeWidth = 2, + x = 0, y = 0, width = '100%', height = '100%' }) self.exampleView = self.exampleVP.new('VectorViewport', { diff --git a/scripts/gui/input.fluid b/scripts/gui/input.fluid index 063656c77..559c49e1c 100644 --- a/scripts/gui/input.fluid +++ b/scripts/gui/input.fluid @@ -47,7 +47,7 @@ gui.input = function(Options) self.disabled = true self.viewport.acDisable() self.text.opacity = 0.5 - self.bkgd.fill = gui.style.widget.bkgd + self.bkgd.fill = gui.style.page.bkgd if self.events.disable then self.events.disable(self) end self.viewport.acDraw() end @@ -56,7 +56,7 @@ gui.input = function(Options) self.disabled = false self.viewport.acDisable() self.text.opacity = 1.0 - self.bkgd.fill = gui.style.widget.bkgd + self.bkgd.fill = gui.style.page.bkgd if self.events.enable then self.events.enable(self) end self.viewport.acDraw() end @@ -123,33 +123,30 @@ gui.input = function(Options) end self.bkgd = self.inputViewport.new('VectorRectangle', { - fill = gui.style.widget.bkgd, - x = 0, - y = 0, - width = '100%', - height = '100%', + fill = gui.style.page.bkgd, x = 0, y = 0, width = '100%', height = '100%', }) if not Options.flushEdges then - self.bkgd.stroke = gui.style.widget.stroke - self.bkgd.strokeWidth = gui.style.widget.strokeWidth - self.bkgd.roundX = gui.style.widget.strokeWidth * 2 - self.bkgd.roundY = gui.style.widget.strokeWidth * 2 + self.bkgd.stroke = gui.style.page.stroke + self.bkgd.strokeWidth = gui.style.page.strokeWidth + self.bkgd.roundX = gui.style.page.strokeWidth * 2 + self.bkgd.roundY = gui.style.page.strokeWidth * 2 end self._textClip = self.inputViewport.new('VectorViewport', { name = 'vp_input_clip', - x = gui.style.widget.strokeWidth, y = gui.style.widget.strokeWidth, xOffset = gui.style.widget.strokeWidth, yOffset = gui.style.widget.strokeWidth, + x = gui.style.page.strokeWidth, y = gui.style.page.strokeWidth, + xOffset = gui.style.page.strokeWidth, yOffset = gui.style.page.strokeWidth, overflow = VOF_HIDDEN }) self.text = self._textClip.new('VectorText', { name = 'vt_input', x = 4, - y = font_height + math.floor((box_height - font_height - (gui.style.widget.strokeWidth * 2)) * 0.5), + y = font_height + math.floor((box_height - font_height - (gui.style.page.strokeWidth * 2)) * 0.5), face = gui.fonts.widget.face, fontSize = string.format('%.2fpt', gui.fonts.widget.size), - fill = gui.style.widget.text, + fill = gui.style.page.text, string = Options.text, lineLimit = 1, textFlags = (function() @@ -163,7 +160,7 @@ gui.input = function(Options) self.viewport.mtSubscribeFeedback(bit.bor(FM_HAS_FOCUS, FM_CHILD_HAS_FOCUS, FM_LOST_FOCUS), function(Viewport, Event) if (Event == FM_LOST_FOCUS) then - self.bkgd.stroke = gui.style.widget.stroke + self.bkgd.stroke = gui.style.page.stroke if self.events.lostFocus then self.events.lostFocus(self) end if validateInput(self) then reportActivate(self, 'lost-focus') @@ -171,9 +168,9 @@ gui.input = function(Options) else self._lastGoodInput = self.text.string if self.disabled then - self.bkgd.stroke = gui.style.widget.stroke + self.bkgd.stroke = gui.style.page.stroke else - self.bkgd.stroke = gui.style.widget.strokeFocus + self.bkgd.stroke = gui.style.page.strokeFocus if self.events.focus then self.events.focus(self) end end end diff --git a/scripts/gui/listview.fluid b/scripts/gui/listview.fluid index fc3d40da6..586a9505f 100644 --- a/scripts/gui/listview.fluid +++ b/scripts/gui/listview.fluid @@ -14,15 +14,6 @@ local LINE_HEIGHT, FONT_HEIGHT = gui.getFontHeight(gui.fonts.widget) LINE_HEIGHT = math.round(LINE_HEIGHT * 1.3) local LINE_OFFSET = (LINE_HEIGHT + FONT_HEIGHT) * 0.5 -local lColours = { - fillItem = gui.style.page.text, - fillItemSelectHigh = 'rgb(255,255,255)', - fillSelect = 'rgb(0,0,60,140)', - fillSelectFont = 'rgb(255,255,255)', - fillBkgdHighlight = 'rgb(0,0,0,10)', - fillBkgdSelectHighlight = 'rgb(0,0,90,140)' -} - local function rearrangeItems(View) View.zones = { } local y = 0 @@ -59,32 +50,35 @@ gui.listView = function(Options) -- When an item is hovered, create a highlight for it. local function highlightItem(View, Item, Highlighted) - if (Item._vectors.viewport == nil) then return end + if Item._vectors.viewport == nil then return end - if (not Item._vectors.highlight) then + if not Item._vectors.highlight then Item._vectors.highlight = Item._vectors.viewport.new('VectorRectangle', { roundX = 4, roundY = 4, width = '100%', height = '100%', visibility = VIS_HIDDEN }) Item._vectors.highlight.acMoveToBack() end - if Highlighted then - if Item._selected then -- Both selected AND highlighted - Item._vectors.highlight.fill = lColours.fillBkgdSelectHighlight - setListTextFill(Item, lColours.fillItemSelectHigh) - else - Item._vectors.highlight.fill = lColours.fillBkgdHighlight - setListTextFill(Item, lColours.fillItem) - end - + if Item._selected then + setListTextFill(Item, gui.style.page.textSelect) + Item._vectors.highlight.fill = gui.style.page.textSelectBkgd Item._vectors.highlight.visibility = VIS_VISIBLE - elseif (Item._selected) then - setListTextFill(Item, lColours.fillItemSelectHigh) - Item._vectors.highlight.fill = lColours.fillSelect + if gui.style.page.iconHighlight and View.hIcons[Item.icon] then + Item._vectors.iconImage.fill = 'url(#' .. View.hIcons[Item.icon] .. ')' + end + elseif Highlighted then + Item._vectors.highlight.fill = gui.style.page.textHighlightBkgd + setListTextFill(Item, gui.style.page.textHighlight) Item._vectors.highlight.visibility = VIS_VISIBLE + if gui.style.page.iconHighlight and View.hIcons[Item.icon] then + Item._vectors.iconImage.fill = 'url(#' .. View.hIcons[Item.icon] .. ')' + end else - setListTextFill(Item, lColours.fillItem) + setListTextFill(Item, gui.style.page.text) Item._vectors.highlight.visibility = VIS_HIDDEN + if View.icons[Item.icon] then + Item._vectors.iconImage.fill = 'url(#' .. Item.icon .. ')' + end end end @@ -100,7 +94,7 @@ gui.listView = function(Options) y = y + ((#View.items - #Items) * (LINE_HEIGHT + VSPACING)) for _, item in pairs(Items) do - if (not item._vectors) then item._vectors = { } end + if not item._vectors then item._vectors = { } end item._x = x item._y = y @@ -116,7 +110,7 @@ gui.listView = function(Options) -- Respond to positive item selection by the user (e.g. button click) item._selectEvent = function(View, Item) - if (Item == View.hItem) then + if Item == View.hItem then Item._highlightEvent(View, Item, true) else Item._highlightEvent(View, Item, false) @@ -147,13 +141,20 @@ gui.listView = function(Options) if item.icon then pcall(function() - if not View.icons then View.icons = { } end - if not View.icons[item.icon] then - gui.createIcon(View.scene, item.icon, ICON_SIZE) + gui.createIcon(View.scene, item.icon, ICON_SIZE, gui.style.page.icon, item.icon) View.icons[item.icon] = true end + if gui.style.page.iconHighlight then + if gui.style.page.iconHighlight == gui.style.page.icon then + View.hIcons[item.icon] = item.icon + else + gui.createIcon(View.scene, item.icon, ICON_SIZE, gui.style.page.iconHighlight, '_h_' .. item.icon) + View.hIcons[item.icon] = '_h_' .. item.icon + end + end + if not item._vectors.iconImage then item._vectors.iconImage = vp.new('VectorRectangle', { fill = 'url(#' .. item.icon .. ')', @@ -179,7 +180,7 @@ gui.listView = function(Options) item._vectors.text.x = MARGIN + ICON_MARGIN item._vectors.text.y = LINE_OFFSET - if (type(item_name) == 'table') then + if type(item_name) == 'table' then item._vectors.text.string = item_name.value else item._vectors.text.string = item_name @@ -191,11 +192,11 @@ gui.listView = function(Options) width = MARGIN + ICON_MARGIN + bw + MARGIN if item._selected then - item._vectors.text.fill = lColours.fillSelectFont - elseif (item.index == lHighlightedItem) and (lColours.highlight) then - item._vectors.text.fill = lColours.highlight + item._vectors.text.fill = gui.style.page.textSelect + elseif item.index and (item.index == lHighlightedItem) then + item._vectors.text.fill = gui.style.page.textHighlight else - item._vectors.text.fill = nz(item.colour, lColours.fillItem) + item._vectors.text.fill = nz(item.colour, gui.style.page.text) end end @@ -206,14 +207,14 @@ gui.listView = function(Options) y = y + LINE_HEIGHT + VSPACING end - if (width > widest_item) then widest_item = width end + if width > widest_item then widest_item = width end end -- Item click and hover management for _, item in pairs(View.items) do if not item.hidden then - if (Options.compact == 1) then + if Options.compact == 1 then View.addZone(item._x, item._y, widest_item, item._height, item, itemHoverCallback) else View.addZone(item._x, item._y, nil, item._height, item, itemHoverCallback) @@ -230,6 +231,9 @@ gui.listView = function(Options) end local function constructListView(View, Scene, Window, Page) + if not View.icons then View.icons = { } end + if not View.hIcons then View.hIcons = { } end + if #View.items > 0 then newItems(View, View.items) end collectgarbage() diff --git a/scripts/gui/menu.fluid b/scripts/gui/menu.fluid index 4c5c9e566..a713b854a 100644 --- a/scripts/gui/menu.fluid +++ b/scripts/gui/menu.fluid @@ -1,27 +1,21 @@ --[[ Documentation is available in the Parasol Wiki. +To be used in conjunction with the gui.menubar or as an independent pop-up only. --]] require 'common' require 'gui' include 'display' - if (not mGfx) then mGfx = mod.load('display') end + if not mGfx then mGfx = mod.load('display') end -local FONT_SIZE = 11 -local ITEM_SPACING = 1.2 - -local function applyFill(Vector, Fill) - while (Vector != nil) do - if (Vector.fill != 'none') then - Vector.fill = Fill - end - if (Vector.stroke != nil) then Vector.stroke = Fill end - local child = Vector.child - if (child != nil) then applyFill(child, Fill) end - Vector = Vector.next - end -end +local FONT_MAX_HEIGHT, FONT_HEIGHT = gui.getFontHeight(gui.fonts.menu) +local ITEM_HEIGHT = math.floor(FONT_MAX_HEIGHT * 1.5) +local VMARGIN = math.floor(ITEM_HEIGHT * 0.33) +local HMARGIN = 6 +local ICON_SIZE = math.floor(ITEM_HEIGHT * 0.8) +local KB_HIGHLIGHT = 'rgb(0,0,0,120)' +local ICON_STRIP = 'rgb(255,255,255,40)' gui.menu = function(Options) local self = { -- Public variables @@ -43,72 +37,40 @@ gui.menu = function(Options) } local function initVectorScene() - local GAP_X = 6 - local showIcons = nz(Options.showIcons, true) - - local textX = GAP_X + local TEXT_X = HMARGIN if showIcons then local iconsPresent = false for _, item in ipairs(Options.config) do if item['icon'] then iconsPresent = true - textX = 34 + TEXT_X = HMARGIN + ICON_SIZE + HMARGIN + HMARGIN end end end - -- To use the clip, set the 'mask' field of any drawable vector. - self.clip = self.scene.new('VectorClip', { units='BoundingBox' }) - local clipRect = self.clip.viewport.new('VectorRectangle', { - x = 1.5, - y = 1.5, - roundX = 3, - roundY = 3, - width = 1, - height = 1 - }) - - self.vg.new('VectorRectangle', { - name = 'bkgd_rect', - fill = 'rgb(240,240,240,255)', - x = 1.5, - y = 1.5, - roundX = 3, - roundY = 3, - width = 1, - height = 1, + self.viewport.new('VectorRectangle', { + fill = gui.style.menu.bkgd, x = 0, y = 0, xOffset = 0, yOffset = 0, resizeEvent = function(Viewport, Vector, X, Y, Width, Height) Vector.width = Width - (Vector.x * 2) Vector.height = Height - (Vector.y * 2) - clipRect.width = Width - (Vector.x * 2) - clipRect.height = Height - (Vector.y * 2) end }) - if showIcons and (self.style == 'menubar') or (self.style == 'popup') then - self.vg.new('VectorRectangle', { - name = 'icon_bar', - fill = 'rgb(220,220,255,255)', - x = 0, - y = 0, - width = 30, - height = '100%', - mask = self.clip + if showIcons then -- Icon strip + self.viewport.new('VectorRectangle', { + fill = ICON_STRIP, x = 0, y = 0, width = HMARGIN + ICON_SIZE + HMARGIN, height = '100%' }) end - self.vg.new('VectorRectangle', { -- Border must be the most foregound - name = 'menu_border', - stroke = 'rgb(60,60,80,180)', - strokeWidth = 1.5, - x = 1.5, - y = 1.5, - roundX = 3, - roundY = 3, - width = 1, - height = 1, + self.highlight = self.viewport.new('VectorRectangle', { + x = 2, y = 0, xOffset = 2, height = ITEM_HEIGHT, fill = gui.palette.contrast, visibility = 'hidden' + }) + + self.viewport.new('VectorRectangle', { -- Border + stroke = gui.style.menu.stroke, strokeWidth = 1.5, opacity=0.5, + x = 1, y = 1, xOffset = 1, yOffset = 1, resizeEvent = function(Viewport, Vector, X, Y, Width, Height) Vector.width = Width - (Vector.x * 2) Vector.height = Height - (Vector.y * 2) @@ -118,15 +80,15 @@ gui.menu = function(Options) self.items = { } local widestItem = 0 local widestKey = 0 - local y = 9 + local y = VMARGIN for _, item in ipairs(Options.config) do if item['item'] then local mi = { y=y, config=item } - local vText = self.vg.new('VectorText', { - x = textX, + local vText = self.viewport.new('VectorText', { + x = TEXT_X, face = gui.fonts.menu.face, - fontSize = string.format('%.2fpt', FONT_SIZE), - fill = 'rgb(0,0,0)', + fontSize = string.format('%.2fpt', gui.fonts.menu.size), + fill = gui.style.menu.text, align = 'left', string = item['item'] }) @@ -134,20 +96,16 @@ gui.menu = function(Options) local err, bx, by, bw, bh = vText.mtGetBoundary(0) mi.text = vText - mi.textY = y + ((vText.lineSpacing + vText.displaySize) * 0.5) + mi.textY = y + math.floor((vText.lineSpacing + vText.displayHeight) * 0.5) - if (bw > widestItem) then widestItem = bw end - - local icon_size = vText.displayHeight + vText.descent + if bw > widestItem then widestItem = bw end if showIcons and item['icon'] then - catch(function() - local svgGroup = self.viewport.new('VectorViewport', { - x=8, y=y, width=icon_size, height=icon_size + pcall(function() + local info = gui.createIcon(self.viewport.scene, item.icon, ICON_SIZE, gui.style.menu.icon) + item.iconView = self.viewport.new('VectorRectangle', { + x = HMARGIN, y = y + math.floor((ITEM_HEIGHT - ICON_SIZE) * 0.5), width = ICON_SIZE, height = ICON_SIZE, fill = info.fill }) - local svg = obj.new('svg', { target=svgGroup, path='icons:' .. item['icon'] .. '.svg' }) - applyFill(svgGroup, 'rgb(80,80,120,255)') - mi.svgIcon = svgGroup end) end @@ -157,46 +115,52 @@ gui.menu = function(Options) key = item['qualifier'] .. ' + ' .. key end - local vKey = self.vg.new('VectorText', { + local kb_highlight = self.viewport.new('VectorRectangle', { + fill = KB_HIGHLIGHT, xOffset = HMARGIN, y = y + 2, width = 1, height = ITEM_HEIGHT - 4, + roundX = ITEM_HEIGHT * 0.5, roundY = ITEM_HEIGHT * 0.5 + }) + + local vKey = self.viewport.new('VectorText', { x = self.surface.width, face = gui.fonts.menu.face, - fontSize = string.format('%.2fpt', FONT_SIZE), - fill = 'rgb(30,80,0,255)', + fontSize = string.format('%.2fpt', gui.fonts.menu.size), + fill = gui.style.menu.text, align = 'right', string = key }) local err, bx, by, bw, bh = vKey.mtGetBoundary(0) - vKey.y = y + ((vKey.lineSpacing + vKey.displaySize) * 0.5) + vKey.y = y + math.floor((vKey.lineSpacing + vKey.displayHeight) * 0.5) keyWidth = bw - if (keyWidth > widestKey) then widestKey = keyWidth end + if keyWidth > widestKey then widestKey = keyWidth end mi.keyText = vKey + kb_highlight.width = keyWidth + HMARGIN + HMARGIN end vText.y = mi.textY - mi.height = vText.lineSpacing * ITEM_SPACING + mi.height = ITEM_HEIGHT y = y + mi.height table.insert(self.items, mi) end end - self.surface.width = textX + widestItem + (GAP_X * 3) + widestKey + GAP_X - self.surface.height = y + local width = TEXT_X + widestItem + (HMARGIN * 6) + widestKey + HMARGIN + + self.surface.width = width + self.surface.height = y + VMARGIN for _, item in pairs(self.items) do if item['keyText'] then - item.keyText.x = self.surface.width - GAP_X + item.keyText.x = self.surface.width - HMARGIN - HMARGIN end end end - -- The toggle() method alternates the the visible state of the menu - for example, if the menu is hidden, it - -- will show the menu. A time-lapse feature is supported so that rapid changes to menu visibility can be avoided. - -- For example, if the TimeLapse option is set to 10 milliseconds, the menu state will not change unless the - -- specified amount of time has elapsed since the last toggle. + -- toggle() alternates the visible state of the menu. A TimeLapse is supported so that rapid changes to + -- menu visibility can be avoided. local lastTime = 0 self.toggle = function(TimeLapse) @@ -208,7 +172,7 @@ gui.menu = function(Options) end local currentTime = mSys.PreciseTime() - if (self.timeShow > self.timeHide) then -- Hide the menu + if self.timeShow > self.timeHide then -- Hide the menu if (currentTime - self.timeShow >= timelapse) then self.hide() end lastTime = currentTime return 0 @@ -240,13 +204,13 @@ gui.menu = function(Options) if self.popup then local err, cursor_x, cursor_y = mGfx.getCursorPos() - if (err == ERR_Okay) then + if err == ERR_Okay then local parent = { } local sp = surface.parent if sp then err, parentInfo = mGfx.GetSurfaceInfo(sp) - if (err == ERR_Okay) then + if err == ERR_Okay then parent.width = parentInfo.width parent.height = parentInfo.height parent.absX = parentInfo.absX @@ -276,7 +240,7 @@ gui.menu = function(Options) local x if self.reverseX then x = cursor_x - parent.absX - 1 - surface.width + gui.style.widget.margin - if (x < 0) then + if x < 0 then x = 0 self.reverseX = false end @@ -300,7 +264,7 @@ gui.menu = function(Options) --[[ local parent = { x=0, y = 0, width = 0 } local parent = self.parentMenu - if (parent.menuSurfaceID) then + if parent.menuSurfaceID then local err, info = mGfx.GetSurfaceInfo(parent.MenuSurfaceID) if err == ERR_Okay then parent.x = info.x @@ -311,7 +275,7 @@ gui.menu = function(Options) parent.currentMenu = self local x = parent.x + parent.width - gui.style.widget.margin - if (self.reverseX) then + if self.reverseX then x = parent.x - surface.width + gui.style.widget.margin if x < 2 then x = 2 @@ -319,7 +283,7 @@ gui.menu = function(Options) end else SURFACEINFO *target - if (Options.target) and (!mGfx.GetSurfaceInfo(Options.target, &target)) then + if Options.target and (!mGfx.GetSurfaceInfo(Options.target, &target)) then -- A specific target surface is hosting the menu layer adjust the coordinate if necessary to keep -- it from being partially hidden. if x + surface.width >= target.width then @@ -343,14 +307,14 @@ gui.menu = function(Options) if Options.target then local err, target = mGfx.GetSurfaceInfo(Options.target) - if (err == ERR_Okay) then + if err == ERR_Okay then target.absX = target.absX target.absY = target.absY target.height = target.height end else local err, display = mGfx.GetDisplayInfo(0) - if (err == ERR_Okay) then + if err == ERR_Okay then target.height = display.height end end @@ -364,9 +328,9 @@ gui.menu = function(Options) if (y + surface.height > target.height) then if self.parentMenu then -- Child menu - y = y - surface.height --+ get_item_height() + self.vWhiteSpace + y = y - surface.height else - y = y - surface.height - nz(Options.y, 0) --+ self.vWhiteSpace + y = y - surface.height - nz(Options.y, 0) end end @@ -389,21 +353,25 @@ gui.menu = function(Options) end if self.hItem then -- Redraw the previously highlighted item - self.hItem.text.fill = 'rgb(0,0,0)' - self.viewport.acDraw() + self.surface.mtScheduleRedraw() self.hItem = nil end self.hItem = Item if Item then -- Draw the newly highlighted area - Item.text.fill = 'rgb(180,0,0)' - self.viewport.acDraw() + self.highlight.y = Item.y + self.highlight.height = Item.height + self.highlight.visibility = 'visible' + self.surface.mtScheduleRedraw() + else + self.highlight.visibility = 'hidden' + self.surface.mtScheduleRedraw() end end local function timer(Elapsed, CurrentTime) - if (lCurrentItem) and nz(lCurrentItem.tip) then + if lCurrentItem and nz(lCurrentItem.tip) then gui.tooltip({ text=lCurrentItem.tip }) end self.tipTimer = nil @@ -416,18 +384,17 @@ gui.menu = function(Options) self.surface = obj.new('surface') self.surface.name = 'menu' - self.surface.width = nz(Options.width, 200) + self.surface.width = nz(Options.width, 400) self.surface.parent = Options.target self.surface.flags = bit.bor(RNF_STICK_TO_FRONT, RNF_COMPOSITE) - self.surface.x = self.x - self.surface.y = self.y + self.surface.x = -10000 + self.surface.y = -10000 self.surface.windowType = 'NONE' - self.surface.height = 40 - if (self.surface.init() != ERR_Okay) then error('Failed to initialise surface.') end + self.surface.height = 400 + if self.surface.init() != ERR_Okay then error('Failed to initialise surface.') end self.scene = obj.new('VectorScene', { flags=VPF_RESIZE, surface=self.surface }) self.viewport = self.scene.new('VectorViewport', { }) - self.vg = self.viewport.new('VectorGroup', { }) self.surface.subscribe('free', function(Surface, Args) if self.tipTimer then mSys.UpdateTimer(self.tipTimer, 0) end @@ -462,10 +429,10 @@ gui.menu = function(Options) end if bit.band(Qualifiers, KQ_PRESSED) == 0 then return end - if (Value == KEY_UP) then - elseif (Value == KEY_DOWN) then + if Value == KEY_UP then + elseif Value == KEY_DOWN then - elseif (Value == KEY_RETURN) then + elseif Value == KEY_RETURN then end end) == ERR_Okay then @@ -477,7 +444,7 @@ gui.menu = function(Options) self.viewport.mtSubscribeInput(bit.bor(JTYPE_MOVEMENT, JTYPE_BUTTON, JTYPE_CROSSING), function(Viewport, Events) local ev = Events while ev do - if (ev.type == JET_BUTTON_1) then + if ev.type == JET_BUTTON_1 then if ev.value == 1 then if self.hItem then -- Menu item activated if self.hItem.config.feedback then @@ -489,12 +456,12 @@ gui.menu = function(Options) self.surface.acHide() end end - elseif (ev.type == JET_ABS_XY) then + elseif ev.type == JET_ABS_XY then local highlightFound = false for _, item in pairs(self.items) do if not item.lineBreak then if (ev.y >= item.y) and (ev.y < item.y + item.height) then - if (self.hItem != item) then + if self.hItem != item then highlightItem(item) end highlightFound = true @@ -513,10 +480,11 @@ gui.menu = function(Options) if self.tipTimer then mSys.UpdateTimer(self.tipTimer, self.tipDelay) else - local err - err, self.tipTimer = mSys.SubscribeTimer(self.tipDelay, timer) + _, self.tipTimer = mSys.SubscribeTimer(self.tipDelay, timer) end end + elseif (ev.type == JET_CROSSED_OUT) then + if self.hItem then highlightItem(nil) end end ev = ev.next diff --git a/scripts/gui/menubar.fluid b/scripts/gui/menubar.fluid index 1ae78481e..060fc8498 100644 --- a/scripts/gui/menubar.fluid +++ b/scripts/gui/menubar.fluid @@ -8,16 +8,9 @@ Documentation is available in the Parasol Wiki. require 'translate' include 'vector' -local lColours = { - textFill = 'rgb(255,255,255)', - textHighlight = 'rgb(160,160,220)', - iconGradient = { first={ r=250,g=249,b=248 }, last={ r=190,g=191,b=192 } } -} - local VMARGIN = gui.style.widget.margin local GAP = 26 local ICON_SIZE = 12 -local FONT_SIZE = 16 local count = 0 local function counter() @@ -101,11 +94,12 @@ end local function highlightItem(self, Item) self._currentItem = Item - self._hIcon.x = Item.x + 1 - self._hIcon.y = 1 - self._hIcon.width = Item.width - 2 - self._hIcon.height = self.viewport.height - 2 - self._hIcon.visibility = 'visible' + + self._highlight.x = Item.x + self._highlight.y = 0 + self._highlight.width = Item.width + self._highlight.height = self.viewport.height - 1 + self._highlight.visibility = 'visible' self.viewport.acDraw() end @@ -127,10 +121,10 @@ local function arrangeItems(self) item.gfxWidth = item.width local iconWidth = 0 - if item.svg then + if item.icon then iconWidth = ICON_SIZE + VMARGIN - item.svgGroup.x = x + VMARGIN - item.svgGroup.y = y + VMARGIN + item.icon.x = x + VMARGIN + item.icon.y = y + VMARGIN if self._disabled or item.disabled then item.vectorIcon.opacity = 0.5 end @@ -141,7 +135,7 @@ local function arrangeItems(self) x = x + iconWidth + VMARGIN, face = gui.fonts.menu.face, fontSize = string.format('%.2fpt', gui.fonts.menu.size), - fill = lColours.textFill, + fill = gui.style.menubar.text, string = item.displayName }) @@ -194,31 +188,10 @@ gui.menubar = function(Options) item.menuConfig = Menu if Icon then - catch(function() - local gname = 'menu_grd' .. counter() - item.svgGroup = self.viewport.new('VectorViewport', { x=0, y=0, width=ICON_SIZE, height=ICON_SIZE }) - item.svgGradient = gui.simpleGradient(self.viewport.scene, gname, { lColours.iconGradient.first, lColours.iconGradient.last }, 0, 0, 0, ICON_SIZE, 'userspace', true) - item.svg = obj.new('svg', { target=item.svgGroup, path='icons:' .. Icon .. '.svg' }) - applyFill(item.svgGroup, 'url(#' .. gname .. ')') - - local viewport = item.svgGroup.child - if (viewport != nil) then - while (child != nil) do - if (child.class.id == ID_VECTORVIEWPORT) then - viewport = child - break - end - end - - if (viewport.viewHeight < viewport.viewWidth) then - item.svgGradient.y1 = viewport.viewY - ((viewport.viewWidth - viewport.viewHeight) * 0.5) - item.svgGradient.y2 = item.svgGradient.y1 + viewport.viewWidth - else - item.svgGradient.y1 = viewport.viewY - item.svgGradient.y2 = viewport.viewY + viewport.viewHeight - end - end - end) + local icon = gui.createIcon(self.viewport.scene, Icon, ICON_SIZE, 'pearl') + item.icon = self.viewport.new('VectorRectangle', { + x=0, y=0, width=ICON_SIZE, height=ICON_SIZE, fill = icon.fill + }) end self._arranged = false @@ -247,15 +220,15 @@ gui.menubar = function(Options) local function hoverUpdate(Item, StateChanged) -- Highlight items that the user hovers over. if (self._currentItem == Item) and (StateChanged != true) then return end - self._hIcon.visibility = 'hidden' -- Turn off keyboard highlighting + self._highlight.visibility = 'hidden' self._currentItem = Item if self._prevItem and (self._prevItem != self._currentItem) then - self._prevItem.vectorText.fill = lColours.textFill + -- Reset prevItem presentation if necessary end if self._currentItem and (not self._currentItem.disabled) and (not self._disabled) then - self._currentItem.vectorText.fill = lColours.textHighlight + highlightItem(self, self._currentItem) self._prevItem = self._currentItem end @@ -264,7 +237,7 @@ gui.menubar = function(Options) -- Main entry point - catch(function() + xpcall(function() if (not Options.target) then error('A target viewport is required.') end self.viewport = Options.target.new('vectorviewport') @@ -283,7 +256,7 @@ gui.menubar = function(Options) if (Event == FM_LOST_FOCUS) then self._hasFocus = false if self._currentItem then - self._hIcon.visibility = 'hidden' -- Turn off keyboard highlighting + self._highlight.visibility = 'hidden' -- Turn off highlighting end if self._lastMenu then @@ -369,44 +342,34 @@ gui.menubar = function(Options) self._bkgd = self.viewport.new('VectorGroup', { name='ItemBackground' }) - self._hIcon = self.viewport.new('VectorRectangle', { -- Keyboard-based selection - stroke = 'rgb(0,0,0,128)', - dashArray = '1, 1', - roundX = 3, - roundY = 3, - x = 0, - y = 0, - width = 16, - height = 16, - visibility = 'hidden' - }) - Options.createItems(self) self.viewport.height = ICON_SIZE + (VMARGIN * 2) self._bkgd.new('VectorRectangle', { -- Main background - fill = 'rgb(0,0,0,200)', + fill = gui.style.menubar.bkgd, x = 0, y = 0, width = '100%', height = self.viewport.height - 1 }) + self._highlight = self._bkgd.new('VectorRectangle', { -- Highlight for items + fill = gui.style.menubar.highlight, + x = 0, y = 0, width = 1, height = self.viewport.height - 1, + visibility = 'hidden' + }) + self._bkgd.new('VectorRectangle', { -- Bottom stroke - fill = 'rgb(0,0,0,64)', - stroke = 'rgb(255,255,255,64)', - strokeWidth = 1, - x = 0, - y = self.viewport.height - 1, - width = '100%', - height = 1 + fill = 'rgb(0,0,0,64)', + stroke = 'rgb(255,255,255,64)', strokeWidth = 1, + x = 0, y = self.viewport.height - 1, width = '100%', height = 1 }) arrangeItems(self) end, - function(Exception) - error('Failed to initialise Menubar: ' .. Exception.message) + function(Error) + print(Error .. '\n' .. debug.traceback()) end) return self diff --git a/scripts/gui/toolbar.fluid b/scripts/gui/toolbar.fluid index 1cb19b28d..0928e3bc5 100644 --- a/scripts/gui/toolbar.fluid +++ b/scripts/gui/toolbar.fluid @@ -8,13 +8,6 @@ Documentation is available in the Parasol Wiki. require 'translate' include 'vector' -local lColours = { - hover = 'rgb(0,0,0,32)', - selected = 'rgb(255,255,255,128)', - groupBorder = 'rgb(255,255,255,128)', - iconGradient = { first={ r=90,g=90,b=90 }, last={ r=70,g=70,b=110 } } -} - local lCounter = 0 local lTipDelay = 0.75 @@ -29,16 +22,21 @@ end gui.toolbar = function(Options) local self = { -- Public variables - host = nil, - viewport = nil, -- The main viewport for the toolbar - _groupMargin = 4, - _groupCount = 0, - _round = 4, - _cellMargin = nz(Options.cellMargin, 6), - _disabled = false, - _lookup = { }, - _iconSize = nz(Options.iconSize, gui.interface.iconSize), - _hasFocus = false + host = nil, + viewport = nil, -- The main viewport for the toolbar + _groupMargin = 4, + _groupCount = 0, + _round = 4, + _cellMargin = nz(Options.cellMargin, 6), + _disabled = false, + _lookup = { }, + _iconSize = nz(Options.iconSize, gui.interface.iconSize), + _hasFocus = false, + _iconTheme = nz(Options.iconTheme, gui.style.page.icon), + _iconHighlight = nz(Options.iconHighlight, gui.style.page.iconHighlight), + _hoverFill = nz(Options.hoverFill, gui.style.button.highlight), + _selectFill = nz(Options.selectFill, gui.palette.prime), + _groupBorder = nz(Options.groupBorder, gui.style.widget.stroke) } local function sendFeedback() @@ -89,8 +87,8 @@ gui.toolbar = function(Options) local function getCursorItem(X, Y) local item = self._first while (item) do - if (X >= item.x) and (X < item.x + item.width) and (Y >= item.y) and (Y < item.y + item.height) then - if (item.type == TI_ICON) then return item end + if (X >= item.x) and (X < item.x + item.width) and (Y >= item.y) and (Y < item.y + item.height) then + if item.type == TI_ICON then return item end end item = item.next end @@ -99,16 +97,16 @@ gui.toolbar = function(Options) -- Highlight selected item (for keyboard item selection) local function highlightItem(Item) - if self.hIcon.x == Item.x then return end + if self.kbIcon.x == Item.x then return end self._current = Item - self.hIcon.x = Item.x - self.hIcon.y = 0 - self.hIcon.width = Item.width - self.hIcon.height = self.viewport.height - self.hIcon.visibility = 'visible' + self.kbIcon.x = Item.x + self.kbIcon.y = 0 + self.kbIcon.width = Item.width + self.kbIcon.height = self.viewport.height + self.kbIcon.visibility = 'visible' if self._groupClip then - self.hIcon.mask = self._groupClip + self.kbIcon.mask = self._groupClip end self.viewport.acDraw() @@ -118,33 +116,33 @@ gui.toolbar = function(Options) local function arrangeItems() local groupOffset = 0 - if (self._groupCount > 0) then + if self._groupCount > 0 then groupOffset = self._groupMargin end - if (not self._vHover) then - if (self._groupCount > 0) then - self._vHover = self.viewport.new('VectorRectangle', { -- Hover highlight - fill='rgb(255,255,255)', x=0, y=0, width=1, height=1, visibility='hidden' - }) - else - self._vHover = self.viewport.new('VectorRectangle', { -- Hover highlight - fill='rgb(255,255,255)', x=0, y=0, width=1, height=1, visibility='hidden', roundX=self._round, roundY=self._round - }) - end - end - - -- The _groupClip simplifies masking and 'vg' provides a container for hosting temporary vectors. + -- The _groupClip simplifies masking and 'vg' provides a container for hosting vectors. if self._groupClip then self._groupClip.free() end if self.vg then self.vg.free() end - if (self._groupCount > 0) then + if self._groupCount > 0 then self._groupClip = self.viewport.scene.new('VectorClip', { name='GroupMask', units='UserSpace' }) end self.vg = self.viewport.new('VectorGroup', { name='ItemGroup' }) + if not self._vHover then -- Hover highlight + if self._groupCount > 0 then + self._vHover = self.vg.new('VectorRectangle', { + fill=self._hoverFill, x=0, y=0, width=1, height=1, visibility='hidden' + }) + else + self._vHover = self.vg.new('VectorRectangle', { + fill=self._hoverFill, x=0, y=0, width=1, height=1, visibility='hidden', roundX=self._round, roundY=self._round + }) + end + end + local item = self._first local x, y @@ -159,7 +157,8 @@ gui.toolbar = function(Options) local currentGroup = nil local spanCount = 0 while item do - if (item.type == TI_BREAK) then + -- Note that groups are converted to breaks when in flush mode. + if item.type == TI_BREAK then item.x = x item.y = y item.width = 6 @@ -167,7 +166,7 @@ gui.toolbar = function(Options) local seq = string.format('M%f,%f l0,%f', x+(item.width-1) * 0.5, y+1, item.height) self.vg.new('VectorPath', { - name = 'break', stroke = lColours.groupBorder, sequence = seq, dashArray = '1, 1' + name = 'break', stroke = self._groupBorder, sequence = seq, dashArray = '1, 1' }) if self._horizontal then @@ -175,66 +174,80 @@ gui.toolbar = function(Options) else y = y + item.height end - elseif (item.type == TI_GROUP) then - if self._horizontal then - if not item.prev then - x = x + groupOffset + elseif item.type == TI_GROUP then + if not Options.flush then + if self._horizontal then + if not item.prev then + x = x + groupOffset + else + x = x + (self._iconSize * 0.25) + end else - x = x + (self._iconSize * 0.25) + if not item.prev then + y = y + groupOffset + else + y = y + (self._iconSize * 0.25) + end end - else - if not item.prev then - y = y + groupOffset + + currentGroup = item + spanCount = 0 + + item.x = x + item.y = y + if self._horizontal then + item.height = self._iconSize + (self._cellMargin * 2) else - y = y + (self._iconSize * 0.25) + item.width = self._iconSize + (self._cellMargin * 2) end - end - currentGroup = item - spanCount = 0 - - item.x = x - item.y = y - if self._horizontal then - item.height = self._iconSize + (self._cellMargin * 2) - else - item.width = self._iconSize + (self._cellMargin * 2) - end + item.bkgd = self.vg.new('VectorRectangle', { fill = gui.style.page.bkgd, + name = 'groupbkgd', x = x, y = y, roundX = self._round, roundY = self._round, width = 1, height = 1 + }) - item.border = self.vg.new('VectorRectangle', { - name = 'grouprect', stroke = lColours.groupBorder, fill = 'rgb(0,0,0,20)', strokeWidth = 2, - x = x, y = y, roundX = self._round, roundY = self._round, width = 1, height = 1 - }) + item.bkgd.acMoveToBack() - if self._groupClip then - item.clip = self._groupClip.viewport.new('VectorRectangle', { - name = 'groupclip', x = x, y = y, roundX = self._round, roundY = self._round, width = 1, height = 1 + item.border = self.vg.new('VectorRectangle', { + name = 'grouprect', stroke = gui.style.button.bkgd, strokeWidth = gui.style.widget.strokeWidth, + x = x, y = y, roundX = self._round, roundY = self._round, width = 1, height = 1 }) + + if self._groupClip then + item.clip = self._groupClip.viewport.new('VectorRectangle', { + name = 'groupclip', x = x, y = y, roundX = self._round, roundY = self._round, width = 1, height = 1 + }) + end end - elseif (item.type == TI_ICON) then + elseif item.type == TI_ICON then item.x = x item.y = y item.width = self._iconSize + (self._cellMargin * 2) item.height = self._iconSize + (self._cellMargin * 2) - if item.svgGroup then - item.svgGroup.x = x + self._cellMargin - item.svgGroup.y = y + self._cellMargin + if item.icon then + item.icon.x = x + self._cellMargin + item.icon.y = y + self._cellMargin if self._disabled or item.disabled then item.vectorIcon.opacity = 0.5 end + item.icon.acMoveToFront() elseif nz(item.displayName) then - local gname = 'tbar_grd' .. counter() - item.svgGradient = gui.simpleGradient(self.viewport.scene, gname, - { lColours.iconGradient.first, lColours.iconGradient.last }, - 0, item.y, 0, item.height, 'userspace') + local fill_name = 'tbar_' .. self._iconTheme + gui.simpleGradient(self.viewport.scene, fill_name, gui.iconThemes[self._iconTheme], 0, 0, 0, 1, 'boundingbox', true) + item.textFill = 'url(#' .. fill_name .. ')' + + if self._iconHighlight and (self._iconTheme != self._iconHighlight) then + local alt_name = 'tbar_' .. self._iconHighlight + gui.simpleGradient(self.viewport.scene, alt_name, gui.iconThemes[self._iconHighlight], 0, 0, 0, 1, 'boundingbox', true) + item.textAltFill = 'url(#' .. alt_name .. ')' + end item.vectorText = self.vg.new('VectorText', { x = x + self._cellMargin, - face = 'Noto Sans', + face = gui.fonts.widget.face, fontSize = self._iconSize * 0.75, weight = 500, - fill = 'url(#' .. gname .. ')', + fill = item.textFill, string = item.displayName }) @@ -264,11 +277,23 @@ gui.toolbar = function(Options) currentGroup.width = self.viewport.width - (groupOffset * 2) currentGroup.height = y - currentGroup.y end - currentGroup.border.width = currentGroup.width - currentGroup.border.height = currentGroup.height - currentGroup.clip.width = currentGroup.width - currentGroup.clip.height = currentGroup.height - if (spanCount == currentGroup.span) then + + if currentGroup.bkgd then + currentGroup.bkgd.width = currentGroup.width + currentGroup.bkgd.height = currentGroup.height + end + + if currentGroup.border then + currentGroup.border.width = currentGroup.width + currentGroup.border.height = currentGroup.height + end + + if currentGroup.clip then + currentGroup.clip.width = currentGroup.width + currentGroup.clip.height = currentGroup.height + end + + if spanCount == currentGroup.span then if self._horizontal then x = x + groupOffset -- Gap between groups else @@ -291,8 +316,10 @@ gui.toolbar = function(Options) -- Insert a visual break between items. self.addBreak = function() - newItem(TI_BREAK, 'break', nil) + if not self._first then return end -- At least one item must precede a break + local item = newItem(TI_BREAK, 'break', nil) self._arranged = false + return item end -- Add a clickable item to the toolbar. The Name acts as the item text that is displayed in the toolbar if no @@ -309,10 +336,16 @@ gui.toolbar = function(Options) if Icon then pcall(function() - gui.createIcon(self.viewport.scene, 'icons:' .. Icon .. '.svg', self._iconSize, lColours.iconGradient, Icon) - item.svgGroup = self.viewport.new('VectorRectangle', { - fill = 'url(#' .. Icon .. ')', - x=0, y=0, width=self._iconSize, height=self._iconSize + local info = gui.createIcon(self.viewport.scene, Icon, self._iconSize, self._iconTheme) + item.iconFill = info.fill + + if self._iconHighlight and (self._iconTheme != self._iconHighlight) then + local info = gui.createIcon(self.viewport.scene, Icon, self._iconSize, self._iconHighlight) + item.iconAltFill = info.fill + end + + item.icon = self.viewport.new('VectorRectangle', { + fill = info.fill, x=0, y=0, width=self._iconSize, height=self._iconSize }) end) end @@ -324,10 +357,14 @@ gui.toolbar = function(Options) -- known ahead of time, then added with calls to addItem(). self.addGroup = function(ID, Name, Span) - local item = newItem(TI_GROUP, Name, ID) - item.group = { span=Span } - self._groupCount = self._groupCount + 1 - return item + if Options.flush then + return self.addBreak() + else + local item = newItem(TI_GROUP, Name, ID) + item.group = { span=Span } + self._groupCount = self._groupCount + 1 + return item + end end -- Individual toolbar items can be disabled with this method. Reverse this action with enableItem(). @@ -358,7 +395,7 @@ gui.toolbar = function(Options) item.selected = false self.viewport.acDraw() else - check(ERR_Search) + raise(ERR_Search) end end @@ -370,10 +407,10 @@ gui.toolbar = function(Options) local redraw = false local found = false local item = firstIcon() - while (item) do - if (item.type == TI_ICON) then - if (item.id == ID) then - if (not item.selected) then + while item do + if item.type == TI_ICON then + if item.id == ID then + if not item.selected then item.selected = true redraw = true found = true @@ -388,7 +425,7 @@ gui.toolbar = function(Options) if redraw then self.viewport.acDraw() end - if (not found) then check(ERR_Search) end + if not found then raise(ERR_Search) end end local function tipTimer(Elapsed, CurrentTime) @@ -396,21 +433,34 @@ gui.toolbar = function(Options) gui.tooltip({ text=self._current.tip }) end self._tipTimer = nil - check(ERR_Terminate) + raise(ERR_Terminate) end local function hoverUpdate(Item, StateChanged) -- Highlight items that the user hovers over. if (self._current == Item) and (StateChanged != true) then return end - self.hIcon.visibility = 'hidden' + if self._current then + if self._current.icon then + self._current.icon.fill = self._current.iconFill + elseif self._current.vectorText then + self._current.vectorText.fill = self._current.textFill + end + end + + self.kbIcon.visibility = 'hidden' self._current = Item if self._current and (not self._current.disabled) and (not self._disabled) then if self._clicked then - self._vHover.fill = lColours.selected + self._vHover.fill = self._selectFill else - self._vHover.fill = lColours.hover + self._vHover.fill = self._hoverFill end + if Item.icon and Item.iconAltFill then + Item.icon.fill = Item.iconAltFill + elseif Item.vectorText and Item.textAltFill then + Item.vectorText.fill = Item.textAltFill + end if self._horizontal then self._vHover.x = self._current.x @@ -423,6 +473,7 @@ gui.toolbar = function(Options) self._vHover.width = self.viewport.width self._vHover.height = self._current.height end + self._vHover.visibility = 'visible' if self._groupClip then self._vHover.mask = self._groupClip @@ -437,14 +488,14 @@ gui.toolbar = function(Options) local function inputFeedback(Viewport, Events) -- Internal input handler local ev = Events while ev do - if (ev.type == JET_CROSSED_IN) then + if ev.type == JET_CROSSED_IN then - elseif (ev.type == JET_CROSSED_OUT) then + elseif ev.type == JET_CROSSED_OUT then resetTipTimer() if self._current then hoverUpdate(nil) end - elseif (bit.band(ev.flags, JTYPE_MOVEMENT) != 0) then + elseif bit.band(ev.flags, JTYPE_MOVEMENT) != 0 then resetTipTimer() if self._clicked then return end @@ -461,7 +512,7 @@ gui.toolbar = function(Options) hoverUpdate(item) elseif bit.band(ev.flags, JTYPE_BUTTON) != 0 then - if (ev.value > 0) then + if ev.value > 0 then if self._disabled then return end resetTipTimer() @@ -476,7 +527,7 @@ gui.toolbar = function(Options) hoverUpdate(self._current, true) end end - elseif (ev.type == JET_BUTTON_1) then + elseif ev.type == JET_BUTTON_1 then if self._clicked then self._clicked = nil @@ -484,8 +535,8 @@ gui.toolbar = function(Options) local delta_x = ev.x - lClickX local delta_y = ev.y - lClickY - if (delta_x < 0) then delta_x = -delta_x end - if (delta_y < 0) then delta_y = -delta_y end + if delta_x < 0 then delta_x = -delta_x end + if delta_y < 0 then delta_y = -delta_y end if (delta_x < 4) and (delta_y < 4) then sendFeedback() @@ -500,7 +551,7 @@ gui.toolbar = function(Options) -- Main entry point - if (not Options.target) then error('A target viewport is required.') end + if not Options.target then error('A target viewport is required.') end if Options.groupMargin then self._groupMargin = Options.groupMargin @@ -536,7 +587,7 @@ gui.toolbar = function(Options) self._groupMargin = 0 end - if (self.viewport.init() != ERR_Okay) then error('Failed to initialise viewport.') end + if self.viewport.init() != ERR_Okay then error('Failed to initialise viewport.') end self.viewport.subscribe('free', function(Viewport, Args) if self._tipTimer then mSys.UpdateTimer(self._tipTimer, 0) end @@ -544,10 +595,10 @@ gui.toolbar = function(Options) end) self.viewport.mtSubscribeFeedback(bit.bor(FM_HAS_FOCUS, FM_CHILD_HAS_FOCUS, FM_LOST_FOCUS), function(Viewport, Event) - if (Event == FM_LOST_FOCUS) then + if Event == FM_LOST_FOCUS then self._hasFocus = false if self._current then - self.hIcon.visibility = 'hidden' + self.kbIcon.visibility = 'hidden' self._current = nil end else @@ -567,7 +618,7 @@ gui.toolbar = function(Options) while scan and (scan.type != TI_ICON) do scan = scan.prev end - if (not scan) then scan = lastIcon() end + if not scan then scan = lastIcon() end highlightItem(scan) else highlightItem(firstIcon()) @@ -578,7 +629,7 @@ gui.toolbar = function(Options) while scan and (scan.type != TI_ICON) do scan = scan.next end - if (not scan) then scan = firstIcon() end + if not scan then scan = firstIcon() end highlightItem(scan) else highlightItem(firstIcon()) @@ -589,34 +640,29 @@ gui.toolbar = function(Options) self.viewport.mtSubscribeInput(bit.bor(JTYPE_BUTTON, JTYPE_MOVEMENT, JTYPE_CROSSING), inputFeedback) - local fill = 'rgb(0,0,0,128)' - if (Options.theme != 'light') then - fill = 'rgb(255,255,255,200)' + local kbfill = 'rgb(0,0,0,128)' + if Options.theme != 'light' then + kbfill = 'rgb(255,255,255,200)' end - self.hIcon = self.viewport.new('VectorRectangle', { -- Icon highlighter, for keyboard-based selection - fill = fill, - x = 0, - y = 0, - width = 16, - height = 16, - visibility = 'hidden' + self.kbIcon = self.viewport.new('VectorRectangle', { -- Icon highlighter, for keyboard-based selection + fill = kbfill, x = 0, y = 0, width = 16, height = 16, visibility = 'hidden' }) Options.createItems(self) self._colBreadth = self._iconSize + (self._cellMargin * 2) - if (self._groupCount > 0) then + if self._groupCount > 0 then self._colBreadth = self._colBreadth + (self._groupMargin*2) end - if (Options.orientation == 'horizontal') then + if Options.orientation == 'horizontal' then self._horizontal = true - elseif (Options.orientation == 'vertical') then + elseif Options.orientation == 'vertical' then self._horizontal = false end - if (not self._horizontal) and (Options.y and Options.yOffset) then + if not self._horizontal and (Options.y and Options.yOffset) then self._horizontal = false else self._horizontal = true @@ -630,5 +676,6 @@ gui.toolbar = function(Options) arrangeItems() + collectgarbage() return self end diff --git a/scripts/gui/tooltip.fluid b/scripts/gui/tooltip.fluid index 5e969df87..f4b35a10d 100644 --- a/scripts/gui/tooltip.fluid +++ b/scripts/gui/tooltip.fluid @@ -6,9 +6,6 @@ Documentation is available in the Parasol Wiki. if (gui == nil) then gui = { } end -local FONT_FACE = 'Noto Sans' -local FONT_SIZE = 11 - gui.tooltip = function(Options) local self = { } -- Public variables @@ -33,7 +30,7 @@ gui.tooltip = function(Options) self.box = self.viewport.new('VectorRectangle', { x = 1, y = 1, height = '100%', width = '100%', - stroke = '#606040', fill = '#ffffe0', + stroke = gui.style.page.stroke, fill = gui.style.page.bkgd, strokeWidth = 2, roundX = 4, roundY = 4, resizeEvent = function(Viewport, Vector, X, Y, Width, Height) @@ -43,15 +40,15 @@ gui.tooltip = function(Options) }) self.text = self.viewport.new('VectorText', { - x = FONT_SIZE, + x = gui.fonts.button.size, string = Options.text, - fill = 'rgb(0,0,0)', - face = FONT_FACE, - fontSize = string.format('%.2fpt', FONT_SIZE), + fill = gui.style.page.text, + face = gui.fonts.button.face, + fontSize = string.format('%.2fpt', gui.fonts.button.size), textFlags = VTXF_RASTER }) - self.surface.height = (FONT_SIZE*1.5) + self.text.fontSize + self.surface.height = (gui.fonts.button.size*1.5) + self.text.fontSize self.surface.y = ptr.y - self.surface.height self.text.y = math.floor((self.viewport.height * 0.5) + (self.text.displaySize * 0.5)) @@ -70,8 +67,8 @@ gui.tooltip = function(Options) -- Reduce the width of the tooltip if the text is short. - if (self.surface.width > self.text.textWidth + (FONT_SIZE*2)) then - self.surface.width = (FONT_SIZE*2) + self.text.textWidth + if (self.surface.width > self.text.textWidth + (gui.fonts.button.size * 2)) then + self.surface.width = (gui.fonts.button.size * 2) + self.text.textWidth end -- Adjust the position of the tool tip so that it fits on the screen. diff --git a/src/core/defs.h b/src/core/defs.h index 38336ba39..fb526682c 100644 --- a/src/core/defs.h +++ b/src/core/defs.h @@ -1120,7 +1120,7 @@ extern "C" void winFindClose(WINHANDLE); extern "C" void winFindNextChangeNotification(WINHANDLE); extern "C" void winGetAttrib(CSTRING, LONG *); extern "C" BYTE winGetCommand(char *, char *, LONG); -extern "C" LONG winGetFreeDiskSpace(UBYTE, LARGE *, LARGE *); +extern "C" LONG winGetFreeDiskSpace(char, LARGE *, LARGE *); extern "C" LONG winGetLogicalDrives(void); extern "C" LONG winGetLogicalDriveStrings(STRING, LONG); extern ERR winGetVolumeInformation(STRING Volume, std::string &Label, std::string &FileSystem, int &Type); diff --git a/src/core/fs_identify.cpp b/src/core/fs_identify.cpp index 81b1ebdde..7cdbd5948 100644 --- a/src/core/fs_identify.cpp +++ b/src/core/fs_identify.cpp @@ -4,18 +4,17 @@ -FUNCTION- IdentifyFile: Analyse a file and identify a class that can process it. -This function examines the relationship between file data and installed classes. It allows for instance, a JPEG file -to be identified as a datatype of the @Picture class, or an MP3 file to be identified as a datatype of the @Sound +This function examines the relationship between file data and Parasol classes. For instance, a JPEG file would be +identified as a datatype of the @Picture class. An MP3 file would be identified as a datatype of the @Sound class. The method involves analysing the `Path`'s file extension and comparing it to the supported extensions of all available -classes. If a class supports the file extension then the ID of that class will be returned. If the file extension is +classes. If a class supports the file extension, the ID of that class will be returned. If the file extension is not listed in the class dictionary or if it is listed more than once, the first 80 bytes of the file's data will be loaded and checked against classes that can match against file header information. If a match is found, the ID of the matching class will be returned. -This function returns an error code of `ERR::Search` in the event that a suitable class is not available to match -against the given file. +The `ERR::Search` code is returned if a suitable class does not match the targeted file. -INPUT- cstr Path: The location of the object data. diff --git a/src/core/idl.h b/src/core/idl.h index be17c5170..4648f3012 100644 --- a/src/core/idl.h +++ b/src/core/idl.h @@ -1 +1 @@ -char glIDL[] = { 115,46,73,110,112,117,116,69,118,101,110,116,58,112,78,101,120,116,58,73,110,112,117,116,69,118,101,110,116,44,100,86,97,108,117,101,44,120,84,105,109,101,115,116,97,109,112,44,108,82,101,99,105,112,105,101,110,116,73,68,44,108,79,118,101,114,73,68,44,100,65,98,115,88,44,100,65,98,115,89,44,100,88,44,100,89,44,108,68,101,118,105,99,101,73,68,44,108,84,121,112,101,44,108,70,108,97,103,115,44,108,77,97,115,107,10,115,46,100,99,82,101,113,117,101,115,116,58,108,73,116,101,109,44,99,80,114,101,102,101,114,101,110,99,101,91,52,93,10,115,46,100,99,65,117,100,105,111,58,108,83,105,122,101,44,108,70,111,114,109,97,116,10,115,46,100,99,75,101,121,69,110,116,114,121,58,108,70,108,97,103,115,44,108,86,97,108,117,101,44,120,84,105,109,101,115,116,97,109,112,44,108,85,110,105,99,111,100,101,10,115,46,100,99,68,101,118,105,99,101,73,110,112,117,116,58,100,86,97,108,117,101,115,91,50,93,44,120,84,105,109,101,115,116,97,109,112,44,108,68,101,118,105,99,101,73,68,44,108,70,108,97,103,115,44,108,84,121,112,101,10,115,46,68,97,116,101,84,105,109,101,58,119,89,101,97,114,44,99,77,111,110,116,104,44,99,68,97,121,44,99,72,111,117,114,44,99,77,105,110,117,116,101,44,99,83,101,99,111,110,100,44,99,84,105,109,101,90,111,110,101,10,115,46,72,83,86,58,100,72,117,101,44,100,83,97,116,117,114,97,116,105,111,110,44,100,86,97,108,117,101,44,100,65,108,112,104,97,10,115,46,70,82,71,66,58,102,82,101,100,44,102,71,114,101,101,110,44,102,66,108,117,101,44,102,65,108,112,104,97,10,115,46,82,71,66,56,58,117,99,82,101,100,44,117,99,71,114,101,101,110,44,117,99,66,108,117,101,44,117,99,65,108,112,104,97,10,115,46,82,71,66,49,54,58,117,119,82,101,100,44,117,119,71,114,101,101,110,44,117,119,66,108,117,101,44,117,119,65,108,112,104,97,10,115,46,82,71,66,51,50,58,117,108,82,101,100,44,117,108,71,114,101,101,110,44,117,108,66,108,117,101,44,117,108,65,108,112,104,97,10,115,46,82,71,66,80,97,108,101,116,116,101,58,108,65,109,116,67,111,108,111,117,114,115,44,101,67,111,108,58,82,71,66,56,91,50,53,54,93,10,115,46,67,111,108,111,117,114,70,111,114,109,97,116,58,117,99,82,101,100,83,104,105,102,116,44,117,99,71,114,101,101,110,83,104,105,102,116,44,117,99,66,108,117,101,83,104,105,102,116,44,117,99,65,108,112,104,97,83,104,105,102,116,44,117,99,82,101,100,77,97,115,107,44,117,99,71,114,101,101,110,77,97,115,107,44,117,99,66,108,117,101,77,97,115,107,44,117,99,65,108,112,104,97,77,97,115,107,44,117,99,82,101,100,80,111,115,44,117,99,71,114,101,101,110,80,111,115,44,117,99,66,108,117,101,80,111,115,44,117,99,65,108,112,104,97,80,111,115,44,117,99,66,105,116,115,80,101,114,80,105,120,101,108,10,115,46,67,108,105,112,82,101,99,116,97,110,103,108,101,58,108,76,101,102,116,44,108,84,111,112,44,108,82,105,103,104,116,44,108,66,111,116,116,111,109,10,115,46,69,100,103,101,115,58,108,76,101,102,116,44,108,84,111,112,44,108,82,105,103,104,116,44,108,66,111,116,116,111,109,10,115,46,79,98,106,101,99,116,83,105,103,110,97,108,58,111,79,98,106,101,99,116,10,115,46,70,117,110,99,116,105,111,110,70,105,101,108,100,58,115,78,97,109,101,44,117,108,84,121,112,101,10,115,46,70,117,110,99,116,105,111,110,58,112,65,100,100,114,101,115,115,44,115,78,97,109,101,44,112,65,114,103,115,58,70,117,110,99,116,105,111,110,70,105,101,108,100,10,115,46,70,105,101,108,100,65,114,114,97,121,58,115,78,97,109,101,44,112,71,101,116,70,105,101,108,100,44,112,83,101,116,70,105,101,108,100,44,109,65,114,103,44,117,108,70,108,97,103,115,10,115,46,70,105,101,108,100,68,101,102,58,115,78,97,109,101,44,108,86,97,108,117,101,10,115,46,83,121,115,116,101,109,83,116,97,116,101,58,115,80,108,97,116,102,111,114,109,44,108,67,111,110,115,111,108,101,70,68,44,108,83,116,97,103,101,10,115,46,85,110,105,116,58,100,86,97,108,117,101,44,117,108,84,121,112,101,10,115,46,65,99,116,105,111,110,65,114,114,97,121,58,112,82,111,117,116,105,110,101,44,108,65,99,116,105,111,110,67,111,100,101,10,115,46,65,99,116,105,111,110,84,97,98,108,101,58,117,108,72,97,115,104,44,108,83,105,122,101,44,115,78,97,109,101,44,112,65,114,103,115,58,70,117,110,99,116,105,111,110,70,105,101,108,100,10,115,46,67,104,105,108,100,69,110,116,114,121,58,108,79,98,106,101,99,116,73,68,44,117,108,67,108,97,115,115,73,68,10,115,46,77,101,115,115,97,103,101,58,120,84,105,109,101,44,108,85,73,68,44,108,84,121,112,101,44,108,83,105,122,101,10,115,46,77,101,109,73,110,102,111,58,112,83,116,97,114,116,44,108,79,98,106,101,99,116,73,68,44,117,108,83,105,122,101,44,108,70,108,97,103,115,44,108,77,101,109,111,114,121,73,68,44,119,65,99,99,101,115,115,67,111,117,110,116,10,115,46,67,111,109,112,114,101,115,115,105,111,110,70,101,101,100,98,97,99,107,58,108,70,101,101,100,98,97,99,107,73,68,44,108,73,110,100,101,120,44,115,80,97,116,104,44,115,68,101,115,116,44,120,80,114,111,103,114,101,115,115,44,120,79,114,105,103,105,110,97,108,83,105,122,101,44,120,67,111,109,112,114,101,115,115,101,100,83,105,122,101,44,119,89,101,97,114,44,119,77,111,110,116,104,44,119,68,97,121,44,119,72,111,117,114,44,119,77,105,110,117,116,101,44,119,83,101,99,111,110,100,10,115,46,67,111,109,112,114,101,115,115,101,100,73,116,101,109,58,120,79,114,105,103,105,110,97,108,83,105,122,101,44,120,67,111,109,112,114,101,115,115,101,100,83,105,122,101,44,112,78,101,120,116,58,67,111,109,112,114,101,115,115,101,100,73,116,101,109,44,115,80,97,116,104,44,108,80,101,114,109,105,115,115,105,111,110,115,44,108,85,115,101,114,73,68,44,108,71,114,111,117,112,73,68,44,108,79,116,104,101,114,115,73,68,44,108,70,108,97,103,115,44,101,67,114,101,97,116,101,100,58,68,97,116,101,84,105,109,101,44,101,77,111,100,105,102,105,101,100,58,68,97,116,101,84,105,109,101,10,115,46,70,105,108,101,73,110,102,111,58,120,83,105,122,101,44,120,84,105,109,101,83,116,97,109,112,44,112,78,101,120,116,58,70,105,108,101,73,110,102,111,44,115,78,97,109,101,44,108,70,108,97,103,115,44,108,80,101,114,109,105,115,115,105,111,110,115,44,108,85,115,101,114,73,68,44,108,71,114,111,117,112,73,68,44,101,67,114,101,97,116,101,100,58,68,97,116,101,84,105,109,101,44,101,77,111,100,105,102,105,101,100,58,68,97,116,101,84,105,109,101,10,115,46,68,105,114,73,110,102,111,58,112,73,110,102,111,58,70,105,108,101,73,110,102,111,10,115,46,70,105,108,101,70,101,101,100,98,97,99,107,58,120,83,105,122,101,44,120,80,111,115,105,116,105,111,110,44,115,80,97,116,104,44,115,68,101,115,116,44,108,70,101,101,100,98,97,99,107,73,68,44,99,82,101,115,101,114,118,101,100,91,51,50,93,10,115,46,70,105,101,108,100,58,109,65,114,103,44,112,71,101,116,86,97,108,117,101,44,112,83,101,116,86,97,108,117,101,44,112,87,114,105,116,101,86,97,108,117,101,44,115,78,97,109,101,44,117,108,70,105,101,108,100,73,68,44,117,119,79,102,102,115,101,116,44,117,119,73,110,100,101,120,44,117,108,70,108,97,103,115,10,99,46,65,67,58,65,99,116,105,118,97,116,101,61,48,120,50,44,67,108,101,97,114,61,48,120,52,44,67,108,105,112,98,111,97,114,100,61,48,120,50,100,44,67,111,112,121,68,97,116,97,61,48,120,55,44,68,97,116,97,70,101,101,100,61,48,120,56,44,68,101,97,99,116,105,118,97,116,101,61,48,120,57,44,68,105,115,97,98,108,101,61,48,120,50,102,44,68,114,97,103,68,114,111,112,61,48,120,49,48,44,68,114,97,119,61,48,120,97,44,69,78,68,61,48,120,51,49,44,69,110,97,98,108,101,61,48,120,54,44,70,108,117,115,104,61,48,120,98,44,70,111,99,117,115,61,48,120,99,44,70,114,101,101,61,48,120,100,44,70,114,101,101,87,97,114,110,105,110,103,61,48,120,53,44,71,101,116,75,101,121,61,48,120,102,44,72,105,100,101,61,48,120,49,49,44,73,110,105,116,61,48,120,49,50,44,76,111,99,107,61,48,120,49,51,44,76,111,115,116,70,111,99,117,115,61,48,120,49,52,44,77,111,118,101,61,48,120,49,53,44,77,111,118,101,84,111,66,97,99,107,61,48,120,49,54,44,77,111,118,101,84,111,70,114,111,110,116,61,48,120,49,55,44,77,111,118,101,84,111,80,111,105,110,116,61,48,120,50,51,44,78,101,119,67,104,105,108,100,61,48,120,49,56,44,78,101,119,79,98,106,101,99,116,61,48,120,49,97,44,78,101,119,79,119,110,101,114,61,48,120,49,57,44,78,101,119,80,108,97,99,101,109,101,110,116,61,48,120,51,48,44,78,101,120,116,61,48,120,50,57,44,80,114,101,118,61,48,120,50,97,44,81,117,101,114,121,61,48,120,49,99,44,82,101,97,100,61,48,120,49,100,44,82,101,100,105,109,101,110,115,105,111,110,61,48,120,51,44,82,101,100,111,61,48,120,49,98,44,82,101,102,114,101,115,104,61,48,120,50,101,44,82,101,110,97,109,101,61,48,120,49,101,44,82,101,115,101,116,61,48,120,49,102,44,82,101,115,105,122,101,61,48,120,50,48,44,83,97,118,101,73,109,97,103,101,61,48,120,50,49,44,83,97,118,101,83,101,116,116,105,110,103,115,61,48,120,101,44,83,97,118,101,84,111,79,98,106,101,99,116,61,48,120,50,50,44,83,101,101,107,61,48,120,50,52,44,83,101,116,70,105,101,108,100,61,48,120,50,99,44,83,101,116,75,101,121,61,48,120,50,53,44,83,104,111,119,61,48,120,50,54,44,83,105,103,110,97,108,61,48,120,49,44,85,110,100,111,61,48,120,50,55,44,85,110,108,111,99,107,61,48,120,50,56,44,87,114,105,116,101,61,48,120,50,98,10,99,46,65,76,73,71,78,58,66,79,84,84,79,77,61,48,120,50,48,44,67,69,78,84,69,82,61,48,120,99,44,72,79,82,73,90,79,78,84,65,76,61,48,120,52,44,76,69,70,84,61,48,120,49,44,77,73,68,68,76,69,61,48,120,99,44,82,73,71,72,84,61,48,120,50,44,84,79,80,61,48,120,49,48,44,86,69,82,84,73,67,65,76,61,48,120,56,10,99,46,67,67,70,58,65,85,68,73,79,61,48,120,56,48,44,67,79,77,77,65,78,68,61,48,120,49,44,68,65,84,65,61,48,120,49,48,48,44,70,73,76,69,83,89,83,84,69,77,61,48,120,50,44,71,82,65,80,72,73,67,83,61,48,120,52,44,71,85,73,61,48,120,56,44,73,79,61,48,120,49,48,44,77,73,83,67,61,48,120,50,48,48,44,77,85,76,84,73,77,69,68,73,65,61,48,120,56,48,48,44,78,69,84,87,79,82,75,61,48,120,52,48,48,44,83,89,83,84,69,77,61,48,120,50,48,44,84,79,79,76,61,48,120,52,48,10,99,46,67,70,58,68,69,70,76,65,84,69,61,48,120,51,44,71,90,73,80,61,48,120,49,44,90,76,73,66,61,48,120,50,10,99,46,67,76,70,58,73,78,72,69,82,73,84,95,76,79,67,65,76,61,48,120,49,44,78,79,95,79,87,78,69,82,83,72,73,80,61,48,120,50,10,99,46,67,76,73,80,77,79,68,69,58,67,79,80,89,61,48,120,50,44,67,85,84,61,48,120,49,44,80,65,83,84,69,61,48,120,52,10,99,46,67,77,70,58,65,80,80,76,89,95,83,69,67,85,82,73,84,89,61,48,120,50,48,44,67,82,69,65,84,69,95,70,73,76,69,61,48,120,52,44,78,69,87,61,48,120,50,44,78,79,95,76,73,78,75,83,61,48,120,49,48,44,80,65,83,83,87,79,82,68,61,48,120,49,44,82,69,65,68,95,79,78,76,89,61,48,120,56,10,99,46,67,78,70,58,65,85,84,79,95,83,65,86,69,61,48,120,50,44,78,69,87,61,48,120,56,44,79,80,84,73,79,78,65,76,95,70,73,76,69,83,61,48,120,52,44,83,84,82,73,80,95,81,85,79,84,69,83,61,48,120,49,10,99,46,68,65,84,65,58,65,85,68,73,79,61,48,120,53,44,67,79,78,84,69,78,84,61,48,120,98,44,68,69,86,73,67,69,95,73,78,80,85,84,61,48,120,51,44,70,73,76,69,61,48,120,97,44,73,77,65,71,69,61,48,120,55,44,73,78,80,85,84,95,82,69,65,68,89,61,48,120,99,44,82,65,87,61,48,120,50,44,82,69,67,69,73,80,84,61,48,120,57,44,82,69,67,79,82,68,61,48,120,54,44,82,69,81,85,69,83,84,61,48,120,56,44,84,69,88,84,61,48,120,49,44,88,77,76,61,48,120,52,10,99,46,68,69,86,73,67,69,58,67,79,77,80,65,67,84,95,68,73,83,67,61,48,120,49,44,70,73,88,69,68,61,48,120,56,48,48,48,44,70,76,79,80,80,89,95,68,73,83,75,61,48,120,52,44,72,65,82,68,95,68,73,83,75,61,48,120,50,44,77,69,77,79,82,89,61,48,120,49,48,48,48,44,77,79,68,69,77,61,48,120,50,48,48,48,44,78,69,84,87,79,82,75,61,48,120,56,48,44,80,82,73,78,84,69,82,61,48,120,50,48,48,44,80,82,73,78,84,69,82,95,51,68,61,48,120,49,48,48,48,48,44,82,69,65,68,61,48,120,56,44,82,69,77,79,86,65,66,76,69,61,48,120,50,48,44,82,69,77,79,86,69,65,66,76,69,61,48,120,50,48,44,83,67,65,78,78,69,82,61,48,120,52,48,48,44,83,67,65,78,78,69,82,95,51,68,61,48,120,50,48,48,48,48,44,83,79,70,84,87,65,82,69,61,48,120,52,48,44,84,65,80,69,61,48,120,49,48,48,44,84,69,77,80,79,82,65,82,89,61,48,120,56,48,48,44,85,83,66,61,48,120,52,48,48,48,44,87,82,73,84,69,61,48,120,49,48,10,99,46,68,77,70,58,70,73,88,69,68,95,67,69,78,84,69,82,95,88,61,48,120,49,48,48,48,48,48,44,70,73,88,69,68,95,67,69,78,84,69,82,95,89,61,48,120,50,48,48,48,48,48,44,70,73,88,69,68,95,68,69,80,84,72,61,48,120,49,48,48,48,44,70,73,88,69,68,95,72,69,73,71,72,84,61,48,120,49,48,48,44,70,73,88,69,68,95,82,65,68,73,85,83,95,88,61,48,120,50,48,48,48,48,44,70,73,88,69,68,95,82,65,68,73,85,83,95,89,61,48,120,50,48,48,48,48,48,48,44,70,73,88,69,68,95,87,73,68,84,72,61,48,120,50,48,48,44,70,73,88,69,68,95,88,61,48,120,52,44,70,73,88,69,68,95,88,95,79,70,70,83,69,84,61,48,120,52,48,44,70,73,88,69,68,95,89,61,48,120,56,44,70,73,88,69,68,95,89,95,79,70,70,83,69,84,61,48,120,56,48,44,70,73,88,69,68,95,90,61,48,120,52,48,48,48,44,83,67,65,76,69,68,95,67,69,78,84,69,82,95,88,61,48,120,52,48,48,48,48,44,83,67,65,76,69,68,95,67,69,78,84,69,82,95,89,61,48,120,56,48,48,48,48,44,83,67,65,76,69,68,95,68,69,80,84,72,61,48,120,50,48,48,48,44,83,67,65,76,69,68,95,72,69,73,71,72,84,61,48,120,52,48,48,44,83,67,65,76,69,68,95,82,65,68,73,85,83,95,88,61,48,120,49,48,48,48,48,44,83,67,65,76,69,68,95,82,65,68,73,85,83,95,89,61,48,120,49,48,48,48,48,48,48,44,83,67,65,76,69,68,95,87,73,68,84,72,61,48,120,56,48,48,44,83,67,65,76,69,68,95,88,61,48,120,49,44,83,67,65,76,69,68,95,88,95,79,70,70,83,69,84,61,48,120,49,48,44,83,67,65,76,69,68,95,89,61,48,120,50,44,83,67,65,76,69,68,95,89,95,79,70,70,83,69,84,61,48,120,50,48,44,83,67,65,76,69,68,95,90,61,48,120,56,48,48,48,44,83,84,65,84,85,83,95,67,72,65,78,71,69,95,72,61,48,120,52,48,48,48,48,48,44,83,84,65,84,85,83,95,67,72,65,78,71,69,95,86,61,48,120,56,48,48,48,48,48,10,99,46,68,82,76,58,68,79,87,78,61,48,120,49,44,69,65,83,84,61,48,120,50,44,76,69,70,84,61,48,120,51,44,78,79,82,84,72,61,48,120,48,44,78,79,82,84,72,95,69,65,83,84,61,48,120,52,44,78,79,82,84,72,95,87,69,83,84,61,48,120,53,44,82,73,71,72,84,61,48,120,50,44,83,79,85,84,72,61,48,120,49,44,83,79,85,84,72,95,69,65,83,84,61,48,120,54,44,83,79,85,84,72,95,87,69,83,84,61,48,120,55,44,85,80,61,48,120,48,44,87,69,83,84,61,48,120,51,10,99,46,69,68,71,69,58,65,76,76,61,48,120,102,102,44,66,79,84,84,79,77,61,48,120,56,44,66,79,84,84,79,77,95,76,69,70,84,61,48,120,52,48,44,66,79,84,84,79,77,95,82,73,71,72,84,61,48,120,56,48,44,76,69,70,84,61,48,120,50,44,82,73,71,72,84,61,48,120,52,44,84,79,80,61,48,120,49,44,84,79,80,95,76,69,70,84,61,48,120,49,48,44,84,79,80,95,82,73,71,72,84,61,48,120,50,48,10,99,46,69,82,70,58,78,111,116,105,102,105,101,100,61,48,120,52,48,48,48,48,48,48,48,10,99,46,69,82,82,58,65,99,99,101,115,115,77,101,109,111,114,121,61,48,120,52,98,44,65,99,99,101,115,115,79,98,106,101,99,116,61,48,120,53,51,44,65,99,99,101,115,115,83,101,109,97,112,104,111,114,101,61,48,120,55,51,44,65,99,116,105,118,97,116,101,61,48,120,52,50,44,65,100,100,67,108,97,115,115,61,48,120,52,49,44,65,108,108,111,99,77,101,109,111,114,121,61,48,120,53,52,44,65,108,108,111,99,83,101,109,97,112,104,111,114,101,61,48,120,55,50,44,65,108,114,101,97,100,121,68,101,102,105,110,101,100,61,48,120,98,54,44,65,108,114,101,97,100,121,76,111,99,107,101,100,61,48,120,57,99,44,65,114,103,115,61,48,120,49,52,44,65,114,114,97,121,70,117,108,108,61,48,120,50,100,44,66,117,102,102,101,114,79,118,101,114,102,108,111,119,61,48,120,53,99,44,66,117,115,121,61,48,120,56,98,44,67,97,110,99,101,108,108,101,100,61,48,120,51,44,67,97,114,100,82,101,97,100,101,114,85,110,97,118,97,105,108,97,98,108,101,61,48,120,57,102,44,67,97,114,100,82,101,97,100,101,114,85,110,107,110,111,119,110,61,48,120,57,100,44,67,111,109,112,114,101,115,115,105,111,110,61,48,120,97,100,44,67,111,110,110,101,99,116,105,111,110,65,98,111,114,116,101,100,61,48,120,56,99,44,67,111,110,110,101,99,116,105,111,110,82,101,102,117,115,101,100,61,48,120,56,51,44,67,111,110,115,116,114,97,105,110,116,86,105,111,108,97,116,105,111,110,61,48,120,56,56,44,67,111,110,116,105,110,117,101,61,48,120,53,44,67,111,114,101,86,101,114,115,105,111,110,61,48,120,50,54,44,67,114,101,97,116,101,70,105,108,101,61,48,120,55,52,44,67,114,101,97,116,101,79,98,106,101,99,116,61,48,120,54,53,44,67,114,101,97,116,101,82,101,115,111,117,114,99,101,61,48,120,98,50,44,68,97,116,97,83,105,122,101,61,48,120,56,97,44,68,101,97,99,116,105,118,97,116,101,100,61,48,120,57,97,44,68,101,97,100,76,111,99,107,61,48,120,51,101,44,68,101,99,111,109,112,114,101,115,115,105,111,110,61,48,120,97,99,44,68,101,108,101,116,101,70,105,108,101,61,48,120,55,53,44,68,105,114,69,109,112,116,121,61,48,120,56,44,68,105,115,99,111,110,110,101,99,116,101,100,61,48,120,56,54,44,68,111,78,111,116,69,120,112,117,110,103,101,61,48,120,51,48,44,68,111,101,115,78,111,116,69,120,105,115,116,61,48,120,55,56,44,68,111,117,98,108,101,73,110,105,116,61,48,120,52,51,44,68,114,97,119,61,48,120,52,56,44,69,78,68,61,48,120,98,101,44,69,109,112,116,121,83,116,114,105,110,103,61,48,120,54,100,44,69,110,100,79,102,70,105,108,101,61,48,120,55,101,44,69,110,116,114,121,77,105,115,115,105,110,103,72,101,97,100,101,114,61,48,120,51,97,44,69,120,97,109,105,110,101,70,97,105,108,101,100,61,48,120,49,57,44,69,120,99,101,112,116,105,111,110,61,48,120,97,51,44,69,120,99,101,112,116,105,111,110,84,104,114,101,115,104,111,108,100,61,48,120,57,44,69,120,99,108,117,115,105,118,101,68,101,110,105,101,100,61,48,120,53,51,44,69,120,101,99,86,105,111,108,97,116,105,111,110,61,48,120,56,102,44,69,120,105,115,116,115,61,48,120,55,97,44,69,120,112,101,99,116,101,100,70,105,108,101,61,48,120,54,102,44,69,120,112,101,99,116,101,100,70,111,108,100,101,114,61,48,120,97,101,44,70,97,105,108,101,100,61,48,120,100,44,70,97,108,115,101,61,48,120,49,44,70,105,101,108,100,78,111,116,83,101,116,61,48,120,52,52,44,70,105,101,108,100,83,101,97,114,99,104,61,48,120,51,50,44,70,105,101,108,100,84,121,112,101,77,105,115,109,97,116,99,104,61,48,120,53,97,44,70,105,108,101,61,48,120,101,44,70,105,108,101,68,111,101,115,78,111,116,69,120,105,115,116,61,48,120,49,50,44,70,105,108,101,69,120,105,115,116,115,61,48,120,54,51,44,70,105,108,101,78,111,116,70,111,117,110,100,61,48,120,49,50,44,70,105,108,101,82,101,97,100,70,108,97,103,61,48,120,52,54,44,70,105,108,101,87,114,105,116,101,70,108,97,103,61,48,120,52,55,44,70,105,110,105,115,104,101,100,61,48,120,55,101,44,70,117,110,99,116,105,111,110,61,48,120,98,53,44,71,101,116,70,105,101,108,100,61,48,120,53,54,44,71,101,116,83,117,114,102,97,99,101,73,110,102,111,61,48,120,55,100,44,72,111,115,116,78,111,116,70,111,117,110,100,61,48,120,56,49,44,72,111,115,116,85,110,114,101,97,99,104,97,98,108,101,61,48,120,56,53,44,73,100,101,110,116,105,99,97,108,80,97,116,104,115,61,48,120,55,57,44,73,108,108,101,103,97,108,65,99,116,105,111,110,65,116,116,101,109,112,116,61,48,120,51,57,44,73,108,108,101,103,97,108,65,99,116,105,111,110,73,68,61,48,120,51,55,44,73,108,108,101,103,97,108,65,100,100,114,101,115,115,61,48,120,57,49,44,73,108,108,101,103,97,108,77,101,116,104,111,100,73,68,61,48,120,51,54,44,73,109,109,117,116,97,98,108,101,61,48,120,97,102,44,73,110,85,115,101,61,48,120,99,44,73,110,105,116,61,48,120,50,49,44,73,110,105,116,77,111,100,117,108,101,61,48,120,49,49,44,73,110,112,117,116,79,117,116,112,117,116,61,48,120,57,52,44,73,110,116,101,103,114,105,116,121,86,105,111,108,97,116,105,111,110,61,48,120,56,56,44,73,110,118,97,108,105,100,68,97,116,97,61,48,120,102,44,73,110,118,97,108,105,100,68,105,109,101,110,115,105,111,110,61,48,120,53,57,44,73,110,118,97,108,105,100,72,84,84,80,82,101,115,112,111,110,115,101,61,48,120,97,49,44,73,110,118,97,108,105,100,72,97,110,100,108,101,61,48,120,57,54,44,73,110,118,97,108,105,100,79,98,106,101,99,116,61,48,120,56,101,44,73,110,118,97,108,105,100,80,97,116,104,61,48,120,51,51,44,73,110,118,97,108,105,100,82,101,102,101,114,101,110,99,101,61,48,120,97,50,44,73,110,118,97,108,105,100,83,116,97,116,101,61,48,120,56,48,44,73,110,118,97,108,105,100,85,82,73,61,48,120,56,50,44,73,110,118,97,108,105,100,86,97,108,117,101,61,48,120,57,56,44,76,105,109,105,116,101,100,83,117,99,99,101,115,115,61,48,120,50,44,76,105,115,116,67,104,105,108,100,114,101,110,61,48,120,54,97,44,76,111,97,100,77,111,100,117,108,101,61,48,120,57,53,44,76,111,99,107,61,48,120,49,56,44,76,111,99,107,70,97,105,108,101,100,61,48,120,49,56,44,76,111,99,107,77,117,116,101,120,61,48,120,97,97,44,76,111,99,107,82,101,113,117,105,114,101,100,61,48,120,57,98,44,76,111,99,107,101,100,61,48,120,57,99,44,76,111,111,112,61,48,120,54,50,44,76,111,115,116,67,108,97,115,115,61,48,120,49,97,44,76,111,115,116,79,119,110,101,114,61,48,120,50,102,44,76,111,119,67,97,112,97,99,105,116,121,61,48,120,50,48,44,77,97,114,107,101,100,70,111,114,68,101,108,101,116,105,111,110,61,48,120,51,53,44,77,101,109,111,114,121,61,48,120,49,100,44,77,101,109,111,114,121,67,111,114,114,117,112,116,61,48,120,51,49,44,77,101,109,111,114,121,68,111,101,115,78,111,116,69,120,105,115,116,61,48,120,51,100,44,77,101,109,111,114,121,73,110,102,111,61,48,120,54,54,44,77,105,115,109,97,116,99,104,61,48,120,53,101,44,77,105,115,115,105,110,103,67,108,97,115,115,61,48,120,52,53,44,77,105,115,115,105,110,103,67,108,97,115,115,78,97,109,101,61,48,120,50,97,44,77,105,115,115,105,110,103,80,97,116,104,61,48,120,52,99,44,77,111,100,117,108,101,73,110,105,116,70,97,105,108,101,100,61,48,120,51,99,44,77,111,100,117,108,101,77,105,115,115,105,110,103,73,110,105,116,61,48,120,51,98,44,77,111,100,117,108,101,77,105,115,115,105,110,103,78,97,109,101,61,48,120,52,48,44,77,111,100,117,108,101,79,112,101,110,70,97,105,108,101,100,61,48,120,51,56,44,78,101,101,100,79,119,110,101,114,61,48,120,50,52,44,78,101,101,100,87,105,100,116,104,72,101,105,103,104,116,61,48,120,50,55,44,78,101,103,97,116,105,118,101,67,108,97,115,115,73,68,61,48,120,50,57,44,78,101,103,97,116,105,118,101,83,117,98,67,108,97,115,115,73,68,61,48,120,50,56,44,78,101,116,119,111,114,107,85,110,114,101,97,99,104,97,98,108,101,61,48,120,56,52,44,78,101,119,79,98,106,101,99,116,61,48,120,53,53,44,78,111,65,99,116,105,111,110,61,48,120,49,98,44,78,111,68,97,116,97,61,48,120,49,53,44,78,111,70,105,101,108,100,65,99,99,101,115,115,61,48,120,53,55,44,78,111,77,97,116,99,104,105,110,103,79,98,106,101,99,116,61,48,120,52,97,44,78,111,77,101,100,105,97,73,110,115,101,114,116,101,100,61,48,120,57,101,44,78,111,77,101,109,111,114,121,61,48,120,97,44,78,111,77,101,116,104,111,100,115,61,48,120,52,57,44,78,111,80,101,114,109,105,115,115,105,111,110,61,48,120,50,50,44,78,111,80,111,105,110,116,101,114,61,48,120,98,44,78,111,83,101,97,114,99,104,82,101,115,117,108,116,61,48,120,52,101,44,78,111,83,116,97,116,115,61,48,120,49,102,44,78,111,83,117,112,112,111,114,116,61,48,120,49,99,44,78,111,116,70,111,117,110,100,61,48,120,49,48,44,78,111,116,73,110,105,116,105,97,108,105,115,101,100,61,48,120,54,55,44,78,111,116,76,111,99,107,101,100,61,48,120,52,100,44,78,111,116,80,111,115,115,105,98,108,101,61,48,120,98,51,44,78,111,116,104,105,110,103,68,111,110,101,61,48,120,52,44,78,111,116,105,102,105,101,100,61,48,120,52,48,48,48,48,48,48,48,44,78,117,108,108,65,114,103,115,61,48,120,56,100,44,79,98,106,101,99,116,67,111,114,114,117,112,116,61,48,120,53,48,44,79,98,106,101,99,116,69,120,105,115,116,115,61,48,120,54,101,44,79,98,115,111,108,101,116,101,61,48,120,98,49,44,79,98,116,97,105,110,77,101,116,104,111,100,61,48,120,50,99,44,79,107,97,121,61,48,120,48,44,79,112,101,110,70,105,108,101,61,48,120,55,54,44,79,112,101,110,71,76,61,48,120,97,53,44,79,117,116,79,102,66,111,117,110,100,115,61,48,120,53,102,44,79,117,116,79,102,68,97,116,97,61,48,120,55,101,44,79,117,116,79,102,82,97,110,103,101,61,48,120,50,98,44,79,117,116,79,102,83,112,97,99,101,61,48,120,55,99,44,79,117,116,115,105,100,101,77,97,105,110,84,104,114,101,97,100,61,48,120,97,54,44,79,119,110,101,114,78,101,101,100,115,66,105,116,109,97,112,61,48,120,50,53,44,79,119,110,101,114,80,97,115,115,84,104,114,111,117,103,104,61,48,120,53,49,44,80,101,114,109,105,115,115,105,111,110,68,101,110,105,101,100,61,48,120,50,50,44,80,101,114,109,105,115,115,105,111,110,115,61,48,120,50,50,44,80,114,111,120,121,83,83,76,84,117,110,110,101,108,61,48,120,97,48,44,81,117,101,114,121,61,48,120,50,101,44,82,101,97,100,61,48,120,49,54,44,82,101,97,100,70,105,108,101,84,111,66,117,102,102,101,114,61,48,120,98,48,44,82,101,97,100,79,110,108,121,61,48,120,55,55,44,82,101,97,108,108,111,99,77,101,109,111,114,121,61,48,120,54,49,44,82,101,99,117,114,115,105,111,110,61,48,120,57,48,44,82,101,100,105,109,101,110,115,105,111,110,61,48,120,55,49,44,82,101,102,114,101,115,104,61,48,120,54,57,44,82,101,115,105,122,101,61,48,120,55,48,44,82,101,115,111,108,118,101,80,97,116,104,61,48,120,54,52,44,82,101,115,111,108,118,101,83,121,109,98,111,108,61,48,120,98,52,44,82,101,115,111,117,114,99,101,69,120,105,115,116,115,61,48,120,54,56,44,82,101,116,114,121,61,48,120,55,44,83,97,110,105,116,121,70,97,105,108,117,114,101,61,48,120,55,98,44,83,99,104,101,109,97,86,105,111,108,97,116,105,111,110,61,48,120,56,57,44,83,101,97,114,99,104,61,48,120,49,48,44,83,101,99,117,114,105,116,121,61,48,120,57,55,44,83,101,101,107,61,48,120,54,48,44,83,101,114,118,105,99,101,85,110,97,118,97,105,108,97,98,108,101,61,48,120,57,57,44,83,101,116,70,105,101,108,100,61,48,120,51,52,44,83,101,116,86,97,108,117,101,78,111,116,65,114,114,97,121,61,48,120,98,99,44,83,101,116,86,97,108,117,101,78,111,116,70,117,110,99,116,105,111,110,61,48,120,98,97,44,83,101,116,86,97,108,117,101,78,111,116,76,111,111,107,117,112,61,48,120,98,100,44,83,101,116,86,97,108,117,101,78,111,116,78,117,109,101,114,105,99,61,48,120,98,55,44,83,101,116,86,97,108,117,101,78,111,116,79,98,106,101,99,116,61,48,120,98,57,44,83,101,116,86,97,108,117,101,78,111,116,80,111,105,110,116,101,114,61,48,120,98,98,44,83,101,116,86,97,108,117,101,78,111,116,83,116,114,105,110,103,61,48,120,98,56,44,83,101,116,86,111,108,117,109,101,61,48,120,97,98,44,83,107,105,112,61,48,120,54,44,83,109,97,108,108,77,97,115,107,61,48,120,54,99,44,83,116,97,116,101,109,101,110,116,85,110,115,97,116,105,115,102,105,101,100,61,48,120,52,102,44,83,116,114,105,110,103,70,111,114,109,97,116,61,48,120,55,102,44,83,121,110,116,97,120,61,48,120,55,102,44,83,121,115,116,101,109,67,97,108,108,61,48,120,54,98,44,83,121,115,116,101,109,67,111,114,114,117,112,116,61,48,120,50,51,44,83,121,115,116,101,109,76,111,99,107,101,100,61,48,120,51,102,44,84,97,115,107,83,116,105,108,108,69,120,105,115,116,115,61,48,120,56,55,44,84,101,114,109,105,110,97,116,101,61,48,120,57,44,84,104,114,101,97,100,65,108,114,101,97,100,121,65,99,116,105,118,101,61,48,120,97,52,44,84,104,114,101,97,100,78,111,116,76,111,99,107,101,100,61,48,120,97,57,44,84,105,109,101,79,117,116,61,48,120,49,101,44,84,114,117,101,61,48,120,48,44,85,110,98,97,108,97,110,99,101,100,88,77,76,61,48,120,57,50,44,85,110,100,101,102,105,110,101,100,70,105,101,108,100,61,48,120,52,52,44,85,110,114,101,99,111,103,110,105,115,101,100,70,105,101,108,100,84,121,112,101,61,48,120,53,98,44,85,110,115,117,112,112,111,114,116,101,100,70,105,101,108,100,61,48,120,53,100,44,85,110,115,117,112,112,111,114,116,101,100,79,119,110,101,114,61,48,120,53,50,44,85,115,101,83,117,98,67,108,97,115,115,61,48,120,97,55,44,86,105,114,116,117,97,108,86,111,108,117,109,101,61,48,120,53,56,44,87,111,117,108,100,66,108,111,99,107,61,48,120,57,51,44,87,114,105,116,101,61,48,120,49,55,44,87,114,111,110,103,67,108,97,115,115,61,48,120,56,101,44,87,114,111,110,103,79,98,106,101,99,116,84,121,112,101,61,48,120,56,101,44,87,114,111,110,103,84,121,112,101,61,48,120,97,56,44,87,114,111,110,103,86,101,114,115,105,111,110,61,48,120,49,51,10,99,46,69,86,71,58,65,78,68,82,79,73,68,61,48,120,100,44,65,80,80,61,48,120,99,44,65,85,68,73,79,61,48,120,56,44,67,76,65,83,83,61,48,120,98,44,68,73,83,80,76,65,89,61,48,120,53,44,69,78,68,61,48,120,101,44,70,73,76,69,83,89,83,84,69,77,61,48,120,49,44,71,85,73,61,48,120,52,44,72,65,82,68,87,65,82,69,61,48,120,55,44,73,79,61,48,120,54,44,78,69,84,87,79,82,75,61,48,120,50,44,80,79,87,69,82,61,48,120,97,44,83,89,83,84,69,77,61,48,120,51,44,85,83,69,82,61,48,120,57,10,99,46,70,66,75,58,67,79,80,89,95,70,73,76,69,61,48,120,50,44,68,69,76,69,84,69,95,70,73,76,69,61,48,120,51,44,77,79,86,69,95,70,73,76,69,61,48,120,49,10,99,46,70,68,58,65,76,76,79,67,61,48,120,50,48,44,65,82,82,65,89,61,48,120,49,48,48,48,44,65,82,82,65,89,83,73,90,69,61,48,120,56,48,44,66,85,70,70,69,82,61,48,120,50,48,48,44,66,85,70,83,73,90,69,61,48,120,56,48,44,66,89,84,69,61,48,120,49,48,48,48,48,48,48,44,67,80,80,61,48,120,52,48,48,48,44,67,85,83,84,79,77,61,48,120,56,48,48,48,44,68,79,85,66,76,69,61,48,120,56,48,48,48,48,48,48,48,44,68,79,85,66,76,69,82,69,83,85,76,84,61,48,120,56,48,48,48,48,49,48,48,44,69,82,82,79,82,61,48,120,56,48,48,44,70,76,65,71,83,61,48,120,52,48,44,70,76,79,65,84,61,48,120,49,48,48,48,48,48,48,48,44,70,85,78,67,84,73,79,78,61,48,120,50,48,48,48,48,48,48,44,70,85,78,67,84,73,79,78,80,84,82,61,48,120,97,48,48,48,48,48,48,44,73,61,48,120,52,48,48,44,73,78,73,84,61,48,120,52,48,48,44,76,65,82,71,69,61,48,120,52,48,48,48,48,48,48,44,76,65,82,71,69,82,69,83,85,76,84,61,48,120,52,48,48,48,49,48,48,44,76,79,67,65,76,61,48,120,50,44,76,79,78,71,61,48,120,52,48,48,48,48,48,48,48,44,76,79,78,71,82,69,83,85,76,84,61,48,120,52,48,48,48,48,49,48,48,44,76,79,79,75,85,80,61,48,120,56,48,44,79,66,74,69,67,84,61,48,120,49,44,79,66,74,69,67,84,73,68,61,48,120,52,48,48,48,48,48,48,49,44,79,66,74,69,67,84,80,84,82,61,48,120,56,48,48,48,48,48,49,44,80,79,73,78,84,69,82,61,48,120,56,48,48,48,48,48,48,44,80,82,73,86,65,84,69,61,48,120,49,48,48,48,48,44,80,84,82,61,48,120,56,48,48,48,48,48,48,44,80,84,82,66,85,70,70,69,82,61,48,120,56,48,48,48,50,48,48,44,80,84,82,82,69,83,85,76,84,61,48,120,56,48,48,48,49,48,48,44,80,84,82,83,73,90,69,61,48,120,56,48,44,80,84,82,95,68,79,85,66,76,69,82,69,83,85,76,84,61,48,120,56,56,48,48,48,49,48,48,44,80,84,82,95,76,65,82,71,69,82,69,83,85,76,84,61,48,120,99,48,48,48,49,48,48,44,80,84,82,95,76,79,78,71,82,69,83,85,76,84,61,48,120,52,56,48,48,48,49,48,48,44,82,61,48,120,49,48,48,44,82,69,65,68,61,48,120,49,48,48,44,82,69,83,79,85,82,67,69,61,48,120,50,48,48,48,44,82,69,83,85,76,84,61,48,120,49,48,48,44,82,71,66,61,48,120,56,48,48,48,48,44,82,73,61,48,120,53,48,48,44,82,87,61,48,120,51,48,48,44,83,67,65,76,69,68,61,48,120,50,48,48,48,48,48,44,83,84,82,61,48,120,56,48,48,48,48,48,44,83,84,82,73,78,71,61,48,120,56,48,48,48,48,48,44,83,84,82,82,69,83,85,76,84,61,48,120,56,48,48,49,48,48,44,83,84,82,85,67,84,61,48,120,49,48,44,83,89,78,79,78,89,77,61,48,120,50,48,48,48,48,44,83,89,83,84,69,77,61,48,120,49,48,48,48,48,44,84,65,71,83,61,48,120,52,48,48,44,85,78,73,84,61,48,120,50,48,48,48,48,48,48,48,44,85,78,83,73,71,78,69,68,61,48,120,52,48,48,48,48,44,86,65,82,84,65,71,83,61,48,120,52,48,44,86,73,82,84,85,65,76,61,48,120,56,44,86,79,73,68,61,48,120,48,44,86,79,76,65,84,73,76,69,61,48,120,48,44,87,61,48,120,50,48,48,44,87,79,82,68,61,48,120,52,48,48,48,48,48,44,87,82,73,84,69,61,48,120,50,48,48,10,99,46,70,68,66,58,67,79,77,80,82,69,83,83,95,70,73,76,69,61,48,120,50,44,68,69,67,79,77,80,82,69,83,83,95,70,73,76,69,61,48,120,49,44,68,69,67,79,77,80,82,69,83,83,95,79,66,74,69,67,84,61,48,120,52,44,82,69,77,79,86,69,95,70,73,76,69,61,48,120,51,10,99,46,70,68,76,58,70,69,69,68,66,65,67,75,61,48,120,49,10,99,46,70,68,84,58,65,67,67,69,83,83,69,68,61,48,120,50,44,65,82,67,72,73,86,69,68,61,48,120,51,44,67,82,69,65,84,69,68,61,48,120,49,44,77,79,68,73,70,73,69,68,61,48,120,48,10,99,46,70,70,82,58,65,66,79,82,84,61,48,120,50,44,67,79,78,84,73,78,85,69,61,48,120,48,44,79,75,65,89,61,48,120,48,44,83,75,73,80,61,48,120,49,10,99,46,70,76,58,65,80,80,82,79,88,73,77,65,84,69,61,48,120,49,48,44,66,85,70,70,69,82,61,48,120,52,48,44,68,69,86,73,67,69,61,48,120,52,48,48,44,68,73,82,69,67,84,79,82,89,61,48,120,56,44,69,88,67,76,85,68,69,95,70,73,76,69,83,61,48,120,49,48,48,48,44,69,88,67,76,85,68,69,95,70,79,76,68,69,82,83,61,48,120,50,48,48,48,44,70,73,76,69,61,48,120,49,48,48,44,70,79,76,68,69,82,61,48,120,56,44,76,73,78,75,61,48,120,50,48,44,76,79,79,80,61,48,120,56,48,44,78,69,87,61,48,120,50,44,82,69,65,68,61,48,120,52,44,82,69,83,69,84,95,68,65,84,69,61,48,120,50,48,48,44,83,84,82,69,65,77,61,48,120,56,48,48,44,87,82,73,84,69,61,48,120,49,10,99,46,70,79,70,58,83,77,65,82,84,95,78,65,77,69,83,61,48,120,49,10,99,46,73,68,84,89,80,69,58,70,85,78,67,84,73,79,78,61,48,120,51,44,71,76,79,66,65,76,61,48,120,50,44,77,69,83,83,65,71,69,61,48,120,49,10,99,46,74,69,84,58,65,66,83,95,88,89,61,48,120,49,98,44,65,78,65,76,79,71,50,95,88,89,61,48,120,49,54,44,65,78,65,76,79,71,50,95,90,61,48,120,49,55,44,65,78,65,76,79,71,95,88,89,61,48,120,49,52,44,65,78,65,76,79,71,95,90,61,48,120,49,53,44,66,85,84,84,79,78,95,49,61,48,120,50,44,66,85,84,84,79,78,95,49,48,61,48,120,98,44,66,85,84,84,79,78,95,50,61,48,120,51,44,66,85,84,84,79,78,95,51,61,48,120,52,44,66,85,84,84,79,78,95,52,61,48,120,53,44,66,85,84,84,79,78,95,53,61,48,120,54,44,66,85,84,84,79,78,95,54,61,48,120,55,44,66,85,84,84,79,78,95,55,61,48,120,56,44,66,85,84,84,79,78,95,56,61,48,120,57,44,66,85,84,84,79,78,95,57,61,48,120,97,44,66,85,84,84,79,78,95,83,69,76,69,67,84,61,48,120,102,44,66,85,84,84,79,78,95,83,84,65,82,84,61,48,120,101,44,67,82,79,83,83,69,68,95,73,78,61,48,120,49,99,44,67,82,79,83,83,69,68,95,79,85,84,61,48,120,49,100,44,68,69,86,73,67,69,95,84,73,76,84,95,88,89,61,48,120,49,102,44,68,69,86,73,67,69,95,84,73,76,84,95,90,61,48,120,50,48,44,68,73,71,73,84,65,76,95,88,89,61,48,120,49,44,68,73,83,80,76,65,89,95,69,68,71,69,61,48,120,50,49,44,69,78,68,61,48,120,50,50,44,76,69,70,84,95,66,85,77,80,69,82,95,49,61,48,120,49,48,44,76,69,70,84,95,66,85,77,80,69,82,95,50,61,48,120,49,49,44,76,77,66,61,48,120,50,44,77,77,66,61,48,120,52,44,80,69,78,95,84,73,76,84,95,88,89,61,48,120,49,97,44,80,82,69,83,83,85,82,69,61,48,120,49,101,44,82,73,71,72,84,95,66,85,77,80,69,82,95,49,61,48,120,49,50,44,82,73,71,72,84,95,66,85,77,80,69,82,95,50,61,48,120,49,51,44,82,77,66,61,48,120,51,44,84,82,73,71,71,69,82,95,76,69,70,84,61,48,120,99,44,84,82,73,71,71,69,82,95,82,73,71,72,84,61,48,120,100,44,87,72,69,69,76,61,48,120,49,56,44,87,72,69,69,76,95,84,73,76,84,61,48,120,49,57,10,99,46,74,84,89,80,69,58,65,78,65,76,79,71,61,48,120,50,48,44,65,78,67,72,79,82,69,68,61,48,120,50,44,66,85,84,84,79,78,61,48,120,56,48,44,67,82,79,83,83,73,78,71,61,48,120,56,44,68,66,76,95,67,76,73,67,75,61,48,120,50,48,48,44,68,73,71,73,84,65,76,61,48,120,49,48,44,68,82,65,71,71,69,68,61,48,120,52,44,68,82,65,71,95,73,84,69,77,61,48,120,56,48,48,44,69,88,84,95,77,79,86,69,77,69,78,84,61,48,120,52,48,44,77,79,86,69,77,69,78,84,61,48,120,49,48,48,44,82,69,80,69,65,84,69,68,61,48,120,52,48,48,44,83,69,67,79,78,68,65,82,89,61,48,120,49,10,99,46,75,69,89,58,65,61,48,120,49,44,65,80,79,83,84,82,79,80,72,69,61,48,120,50,98,44,65,84,61,48,120,56,97,44,66,61,48,120,50,44,66,65,67,75,61,48,120,56,54,44,66,65,67,75,83,80,65,67,69,61,48,120,54,57,44,66,65,67,75,95,83,76,65,83,72,61,48,120,50,102,44,66,82,69,65,75,61,48,120,55,98,44,67,61,48,120,51,44,67,65,76,76,61,48,120,56,55,44,67,65,77,69,82,65,61,48,120,56,57,44,67,65,78,67,69,76,61,48,120,55,97,44,67,65,80,83,95,76,79,67,75,61,48,120,52,54,44,67,76,69,65,82,61,48,120,54,101,44,67,79,77,77,65,61,48,120,50,99,44,68,61,48,120,52,44,68,69,76,69,84,69,61,48,120,54,100,44,68,79,84,61,48,120,50,100,44,68,79,87,78,61,48,120,54,49,44,69,61,48,120,53,44,69,73,71,72,84,61,48,120,50,50,44,69,78,68,61,48,120,55,50,44,69,78,68,95,67,65,76,76,61,48,120,56,56,44,69,78,84,69,82,61,48,120,54,98,44,69,81,85,65,76,83,61,48,120,50,55,44,69,83,67,65,80,69,61,48,120,54,99,44,69,88,69,67,85,84,69,61,48,120,55,52,44,70,61,48,120,54,44,70,49,61,48,120,52,99,44,70,49,48,61,48,120,53,53,44,70,49,49,61,48,120,53,54,44,70,49,50,61,48,120,53,55,44,70,49,51,61,48,120,53,56,44,70,49,52,61,48,120,53,57,44,70,49,53,61,48,120,53,97,44,70,49,54,61,48,120,53,98,44,70,49,55,61,48,120,53,99,44,70,49,56,61,48,120,56,48,44,70,49,57,61,48,120,56,49,44,70,50,61,48,120,52,100,44,70,50,48,61,48,120,56,50,44,70,51,61,48,120,52,101,44,70,52,61,48,120,52,102,44,70,53,61,48,120,53,48,44,70,54,61,48,120,53,49,44,70,55,61,48,120,53,50,44,70,56,61,48,120,53,51,44,70,57,61,48,120,53,52,44,70,73,78,68,61,48,120,55,57,44,70,73,86,69,61,48,120,49,102,44,70,79,82,87,65,82,68,61,48,120,57,48,44,70,79,85,82,61,48,120,49,101,44,71,61,48,120,55,44,72,61,48,120,56,44,72,69,76,80,61,48,120,52,51,44,72,79,77,69,61,48,120,54,102,44,73,61,48,120,57,44,73,78,83,69,82,84,61,48,120,55,53,44,74,61,48,120,97,44,75,61,48,120,98,44,76,61,48,120,99,44,76,69,70,84,61,48,120,54,51,44,76,69,78,83,95,70,79,67,85,83,61,48,120,56,99,44,76,69,83,83,95,71,82,69,65,84,69,82,61,48,120,53,102,44,76,73,83,84,95,69,78,68,61,48,120,57,54,44,76,95,65,76,84,61,48,120,52,56,44,76,95,67,79,77,77,65,78,68,61,48,120,52,97,44,76,95,67,79,78,84,82,79,76,61,48,120,52,49,44,76,95,83,72,73,70,84,61,48,120,52,52,44,76,95,83,81,85,65,82,69,61,48,120,50,56,44,77,61,48,120,100,44,77,65,67,82,79,61,48,120,53,100,44,77,69,78,85,61,48,120,55,56,44,77,73,78,85,83,61,48,120,50,54,44,77,85,84,69,61,48,120,57,50,44,78,61,48,120,101,44,78,69,88,84,61,48,120,56,101,44,78,73,78,69,61,48,120,50,51,44,78,80,95,48,61,48,120,51,49,44,78,80,95,49,61,48,120,51,50,44,78,80,95,50,61,48,120,51,51,44,78,80,95,51,61,48,120,51,52,44,78,80,95,52,61,48,120,51,53,44,78,80,95,53,61,48,120,51,54,44,78,80,95,54,61,48,120,51,55,44,78,80,95,55,61,48,120,51,56,44,78,80,95,56,61,48,120,51,57,44,78,80,95,57,61,48,120,51,97,44,78,80,95,66,65,82,61,48,120,51,100,44,78,80,95,68,69,67,73,77,65,76,61,48,120,51,102,44,78,80,95,68,73,86,73,68,69,61,48,120,52,48,44,78,80,95,68,79,84,61,48,120,51,102,44,78,80,95,69,78,84,69,82,61,48,120,55,101,44,78,80,95,77,73,78,85,83,61,48,120,51,101,44,78,80,95,77,85,76,84,73,80,76,89,61,48,120,51,98,44,78,80,95,80,76,85,83,61,48,120,51,99,44,78,80,95,80,76,85,83,95,77,73,78,85,83,61,48,120,53,101,44,78,80,95,83,69,80,65,82,65,84,79,82,61,48,120,51,100,44,78,85,77,95,76,79,67,75,61,48,120,55,99,44,79,61,48,120,102,44,79,78,69,61,48,120,49,98,44,80,61,48,120,49,48,44,80,65,71,69,95,68,79,87,78,61,48,120,55,49,44,80,65,71,69,95,85,80,61,48,120,55,48,44,80,65,85,83,69,61,48,120,54,53,44,80,69,82,73,79,68,61,48,120,50,100,44,80,76,65,89,61,48,120,57,53,44,80,76,85,83,61,48,120,56,98,44,80,79,85,78,68,61,48,120,57,52,44,80,79,87,69,82,61,48,120,54,56,44,80,82,69,86,73,79,85,83,61,48,120,56,102,44,80,82,73,78,84,61,48,120,52,55,44,80,82,84,95,83,67,82,61,48,120,55,100,44,81,61,48,120,49,49,44,82,61,48,120,49,50,44,82,69,68,79,61,48,120,55,55,44,82,69,86,69,82,83,69,95,81,85,79,84,69,61,48,120,50,53,44,82,69,87,73,78,68,61,48,120,57,49,44,82,73,71,72,84,61,48,120,54,50,44,82,95,65,76,84,61,48,120,52,57,44,82,95,67,79,77,77,65,78,68,61,48,120,52,98,44,82,95,67,79,78,84,82,79,76,61,48,120,52,50,44,82,95,83,72,73,70,84,61,48,120,52,53,44,82,95,83,81,85,65,82,69,61,48,120,50,57,44,83,61,48,120,49,51,44,83,67,82,95,76,79,67,75,61,48,120,54,52,44,83,69,76,69,67,84,61,48,120,55,51,44,83,69,77,73,95,67,79,76,79,78,61,48,120,50,97,44,83,69,86,69,78,61,48,120,50,49,44,83,73,88,61,48,120,50,48,44,83,76,65,83,72,61,48,120,50,101,44,83,76,69,69,80,61,48,120,54,55,44,83,80,65,67,69,61,48,120,51,48,44,83,84,65,82,61,48,120,57,51,44,83,84,79,80,61,48,120,56,100,44,83,89,83,82,81,61,48,120,55,102,44,84,61,48,120,49,52,44,84,65,66,61,48,120,54,97,44,84,72,82,69,69,61,48,120,49,100,44,84,87,79,61,48,120,49,99,44,85,61,48,120,49,53,44,85,78,68,79,61,48,120,55,54,44,85,80,61,48,120,54,48,44,86,61,48,120,49,54,44,86,79,76,85,77,69,95,68,79,87,78,61,48,120,56,53,44,86,79,76,85,77,69,95,85,80,61,48,120,56,52,44,87,61,48,120,49,55,44,87,65,75,69,61,48,120,54,54,44,87,73,78,95,67,79,78,84,82,79,76,61,48,120,56,51,44,88,61,48,120,49,56,44,89,61,48,120,49,57,44,90,61,48,120,49,97,44,90,69,82,79,61,48,120,50,52,10,99,46,75,81,58,65,76,84,61,48,120,54,48,44,65,76,84,71,82,61,48,120,52,48,44,67,65,80,83,95,76,79,67,75,61,48,120,52,44,67,79,77,77,65,78,68,61,48,120,49,56,48,44,67,79,78,84,82,79,76,61,48,120,49,56,44,67,84,82,76,61,48,120,49,56,44,68,69,65,68,95,75,69,89,61,48,120,49,48,48,48,48,44,73,78,70,79,61,48,120,51,99,48,52,44,73,78,83,84,82,85,67,84,73,79,78,95,75,69,89,83,61,48,120,55,56,44,76,95,65,76,84,61,48,120,50,48,44,76,95,67,79,77,77,65,78,68,61,48,120,56,48,44,76,95,67,79,78,84,82,79,76,61,48,120,56,44,76,95,67,84,82,76,61,48,120,56,44,76,95,83,72,73,70,84,61,48,120,49,44,78,79,84,95,80,82,73,78,84,65,66,76,69,61,48,120,50,48,48,48,44,78,85,77,95,76,79,67,75,61,48,120,56,48,48,48,44,78,85,77,95,80,65,68,61,48,120,50,48,48,44,80,82,69,83,83,69,68,61,48,120,49,48,48,48,44,81,85,65,76,73,70,73,69,82,83,61,48,120,49,102,98,44,82,69,76,69,65,83,69,68,61,48,120,56,48,48,44,82,69,80,69,65,84,61,48,120,52,48,48,44,82,95,65,76,84,61,48,120,52,48,44,82,95,67,79,77,77,65,78,68,61,48,120,49,48,48,44,82,95,67,79,78,84,82,79,76,61,48,120,49,48,44,82,95,67,84,82,76,61,48,120,49,48,44,82,95,83,72,73,70,84,61,48,120,50,44,83,67,82,95,76,79,67,75,61,48,120,52,48,48,48,44,83,72,73,70,84,61,48,120,51,44,87,73,78,95,67,79,78,84,82,79,76,61,48,120,50,48,48,48,48,10,99,46,76,65,89,79,85,84,58,66,65,67,75,71,82,79,85,78,68,61,48,120,56,44,69,77,66,69,68,68,69,68,61,48,120,50,48,44,70,79,82,69,71,82,79,85,78,68,61,48,120,49,48,44,73,71,78,79,82,69,95,67,85,82,83,79,82,61,48,120,56,48,44,76,69,70,84,61,48,120,50,44,76,79,67,75,61,48,120,52,48,44,82,73,71,72,84,61,48,120,52,44,83,81,85,65,82,69,61,48,120,48,44,84,73,71,72,84,61,48,120,49,44,84,73,76,69,61,48,120,49,48,48,44,87,73,68,69,61,48,120,54,10,99,46,76,68,70,58,67,72,69,67,75,95,69,88,73,83,84,83,61,48,120,49,10,99,46,76,79,67,58,68,73,82,69,67,84,79,82,89,61,48,120,49,44,70,73,76,69,61,48,120,51,44,70,79,76,68,69,82,61,48,120,49,44,86,79,76,85,77,69,61,48,120,50,10,99,46,77,65,88,58,70,73,76,69,78,65,77,69,61,48,120,49,48,48,44,78,65,77,69,95,76,69,78,61,48,120,49,102,10,99,46,77,69,77,58,65,85,68,73,79,61,48,120,56,44,67,65,76,76,69,82,61,48,120,56,48,48,48,48,48,44,67,79,68,69,61,48,120,49,48,44,67,79,76,76,69,67,84,61,48,120,49,48,48,48,44,68,65,84,65,61,48,120,48,44,69,88,67,76,85,83,73,86,69,61,48,120,56,48,48,44,72,73,68,68,69,78,61,48,120,49,48,48,48,48,48,44,77,65,78,65,71,69,68,61,48,120,49,44,78,79,95,66,76,79,67,75,61,48,120,50,48,48,48,44,78,79,95,66,76,79,67,75,73,78,71,61,48,120,50,48,48,48,44,78,79,95,67,76,69,65,82,61,48,120,52,48,48,48,48,44,78,79,95,76,79,67,75,61,48,120,52,48,48,44,78,79,95,80,79,79,76,61,48,120,50,48,44,79,66,74,69,67,84,61,48,120,50,48,48,44,82,69,65,68,61,48,120,49,48,48,48,48,44,82,69,65,68,95,87,82,73,84,69,61,48,120,51,48,48,48,48,44,83,84,82,73,78,71,61,48,120,49,48,48,44,84,69,88,84,85,82,69,61,48,120,52,44,84,77,80,95,76,79,67,75,61,48,120,52,48,44,85,78,84,82,65,67,75,69,68,61,48,120,56,48,44,86,73,68,69,79,61,48,120,50,44,87,82,73,84,69,61,48,120,50,48,48,48,48,10,99,46,77,70,70,58,65,84,84,82,73,66,61,48,120,50,48,44,67,76,79,83,69,68,61,48,120,56,48,44,67,82,69,65,84,69,61,48,120,52,44,68,69,69,80,61,48,120,49,48,48,48,44,68,69,76,69,84,69,61,48,120,56,44,70,73,76,69,61,48,120,52,48,48,44,70,79,76,68,69,82,61,48,120,50,48,48,44,77,79,68,73,70,89,61,48,120,50,44,77,79,86,69,68,61,48,120,49,48,44,79,80,69,78,69,68,61,48,120,52,48,44,82,69,65,68,61,48,120,49,44,82,69,78,65,77,69,61,48,120,49,48,44,83,69,76,70,61,48,120,56,48,48,44,85,78,77,79,85,78,84,61,48,120,49,48,48,44,87,82,73,84,69,61,48,120,50,10,99,46,77,72,70,58,68,69,70,65,85,76,84,61,48,120,50,44,83,84,65,84,73,67,61,48,120,49,44,83,84,82,85,67,84,85,82,69,61,48,120,50,10,99,46,77,79,70,58,76,73,78,75,95,76,73,66,82,65,82,89,61,48,120,49,44,83,84,65,84,73,67,61,48,120,50,44,83,89,83,84,69,77,95,80,82,79,66,69,61,48,120,52,10,99,46,77,79,86,69,58,65,76,76,61,48,120,102,44,68,79,87,78,61,48,120,49,44,76,69,70,84,61,48,120,52,44,82,73,71,72,84,61,48,120,56,44,85,80,61,48,120,50,10,99,46,77,83,70,58,65,68,68,61,48,120,56,44,65,68,68,82,69,83,83,61,48,120,49,48,44,77,69,83,83,65,71,69,95,73,68,61,48,120,50,48,44,78,79,95,68,85,80,76,73,67,65,84,69,61,48,120,52,44,85,80,68,65,84,69,61,48,120,50,44,87,65,73,84,61,48,120,49,10,99,46,77,83,71,73,68,58,65,67,84,73,79,78,61,48,120,54,51,44,66,82,69,65,75,61,48,120,54,52,44,67,79,77,77,65,78,68,61,48,120,54,53,44,67,79,82,69,95,69,78,68,61,48,120,54,52,44,68,69,66,85,71,61,48,120,53,102,44,69,86,69,78,84,61,48,120,53,101,44,70,82,69,69,61,48,120,54,50,44,81,85,73,84,61,48,120,51,101,56,44,84,72,82,69,65,68,95,65,67,84,73,79,78,61,48,120,53,98,44,84,72,82,69,65,68,95,67,65,76,76,66,65,67,75,61,48,120,53,99,44,86,65,76,73,68,65,84,69,95,80,82,79,67,69,83,83,61,48,120,53,100,44,87,65,73,84,95,70,79,82,95,79,66,74,69,67,84,83,61,48,120,53,97,10,99,46,77,84,70,58,65,78,73,77,61,48,120,56,44,82,69,76,65,84,73,86,69,61,48,120,49,48,44,88,61,48,120,49,44,89,61,48,120,50,44,90,61,48,120,52,10,99,46,78,69,84,77,83,71,58,69,78,68,61,48,120,49,44,83,84,65,82,84,61,48,120,48,10,99,46,78,70,58,67,79,76,76,69,67,84,61,48,120,56,48,44,70,82,69,69,61,48,120,49,48,44,70,82,69,69,95,79,78,95,85,78,76,79,67,75,61,48,120,56,44,73,78,73,84,73,65,76,73,83,69,68,61,48,120,50,44,76,79,67,65,76,61,48,120,52,44,77,69,83,83,65,71,69,61,48,120,50,48,48,44,78,65,77,69,61,48,120,56,48,48,48,48,48,48,48,44,80,82,73,86,65,84,69,61,48,120,48,44,82,69,67,76,65,83,83,69,68,61,48,120,49,48,48,44,83,73,71,78,65,76,76,69,68,61,48,120,52,48,48,44,83,85,80,80,82,69,83,83,95,76,79,71,61,48,120,52,48,44,84,73,77,69,82,95,83,85,66,61,48,120,50,48,44,85,78,73,81,85,69,61,48,120,52,48,48,48,48,48,48,48,44,85,78,84,82,65,67,75,69,68,61,48,120,49,10,99,46,79,80,70,58,65,82,71,83,61,48,120,52,48,44,68,69,84,65,73,76,61,48,120,52,44,69,82,82,79,82,61,48,120,56,48,44,77,65,88,95,68,69,80,84,72,61,48,120,50,44,77,79,68,85,76,69,95,80,65,84,72,61,48,120,52,48,48,44,79,80,84,73,79,78,83,61,48,120,49,44,80,82,73,86,73,76,69,71,69,68,61,48,120,49,48,48,44,82,79,79,84,95,80,65,84,72,61,48,120,56,48,48,44,83,67,65,78,95,77,79,68,85,76,69,83,61,48,120,49,48,48,48,44,83,72,79,87,95,69,82,82,79,82,83,61,48,120,50,48,44,83,72,79,87,95,73,79,61,48,120,49,48,44,83,72,79,87,95,77,69,77,79,82,89,61,48,120,56,44,83,89,83,84,69,77,95,80,65,84,72,61,48,120,50,48,48,10,99,46,80,69,82,77,73,84,58,65,76,76,95,68,69,76,69,84,69,61,48,120,56,56,56,44,65,76,76,95,69,88,69,67,61,48,120,52,52,52,44,65,76,76,95,82,69,65,68,61,48,120,49,49,49,44,65,76,76,95,87,82,73,84,69,61,48,120,50,50,50,44,65,82,67,72,73,86,69,61,48,120,50,48,48,48,44,68,69,76,69,84,69,61,48,120,56,44,69,86,69,82,89,79,78,69,95,65,67,67,69,83,83,61,48,120,102,102,102,44,69,86,69,82,89,79,78,69,95,68,69,76,69,84,69,61,48,120,56,56,56,44,69,86,69,82,89,79,78,69,95,69,88,69,67,61,48,120,52,52,52,44,69,86,69,82,89,79,78,69,95,82,69,65,68,61,48,120,49,49,49,44,69,86,69,82,89,79,78,69,95,82,69,65,68,87,82,73,84,69,61,48,120,51,51,51,44,69,86,69,82,89,79,78,69,95,87,82,73,84,69,61,48,120,50,50,50,44,69,88,69,67,61,48,120,52,44,71,82,79,85,80,61,48,120,102,48,44,71,82,79,85,80,73,68,61,48,120,49,48,48,48,48,44,71,82,79,85,80,95,68,69,76,69,84,69,61,48,120,56,48,44,71,82,79,85,80,95,69,88,69,67,61,48,120,52,48,44,71,82,79,85,80,95,82,69,65,68,61,48,120,49,48,44,71,82,79,85,80,95,87,82,73,84,69,61,48,120,50,48,44,72,73,68,68,69,78,61,48,120,49,48,48,48,44,73,78,72,69,82,73,84,61,48,120,50,48,48,48,48,44,78,69,84,87,79,82,75,61,48,120,56,48,48,48,48,44,79,70,70,76,73,78,69,61,48,120,52,48,48,48,48,44,79,84,72,69,82,83,61,48,120,102,48,48,44,79,84,72,69,82,83,95,68,69,76,69,84,69,61,48,120,56,48,48,44,79,84,72,69,82,83,95,69,88,69,67,61,48,120,52,48,48,44,79,84,72,69,82,83,95,82,69,65,68,61,48,120,49,48,48,44,79,84,72,69,82,83,95,87,82,73,84,69,61,48,120,50,48,48,44,80,65,83,83,87,79,82,68,61,48,120,52,48,48,48,44,82,69,65,68,61,48,120,49,44,85,83,69,82,61,48,120,102,44,85,83,69,82,73,68,61,48,120,56,48,48,48,44,85,83,69,82,95,69,88,69,67,61,48,120,52,44,85,83,69,82,95,82,69,65,68,61,48,120,49,44,85,83,69,82,95,87,82,73,84,69,61,48,120,50,44,87,82,73,84,69,61,48,120,50,10,99,46,80,77,70,58,83,89,83,84,69,77,95,78,79,95,66,82,69,65,75,61,48,120,49,10,99,46,80,84,67,58,67,82,79,83,83,72,65,73,82,61,48,120,97,44,67,85,83,84,79,77,61,48,120,49,55,44,68,69,70,65,85,76,84,61,48,120,49,44,68,82,65,71,71,65,66,76,69,61,48,120,49,56,44,69,78,68,61,48,120,49,57,44,72,65,78,68,61,48,120,49,48,44,72,65,78,68,95,76,69,70,84,61,48,120,49,49,44,72,65,78,68,95,82,73,71,72,84,61,48,120,49,50,44,73,78,86,73,83,73,66,76,69,61,48,120,49,54,44,77,65,71,78,73,70,73,69,82,61,48,120,102,44,78,79,95,67,72,65,78,71,69,61,48,120,48,44,80,65,73,78,84,66,82,85,83,72,61,48,120,49,52,44,83,73,90,69,95,66,79,84,84,79,77,61,48,120,57,44,83,73,90,69,95,66,79,84,84,79,77,95,76,69,70,84,61,48,120,50,44,83,73,90,69,95,66,79,84,84,79,77,95,82,73,71,72,84,61,48,120,51,44,83,73,90,69,95,76,69,70,84,61,48,120,54,44,83,73,90,69,95,82,73,71,72,84,61,48,120,55,44,83,73,90,69,95,84,79,80,61,48,120,56,44,83,73,90,69,95,84,79,80,95,76,69,70,84,61,48,120,52,44,83,73,90,69,95,84,79,80,95,82,73,71,72,84,61,48,120,53,44,83,73,90,73,78,71,61,48,120,99,44,83,76,69,69,80,61,48,120,98,44,83,80,76,73,84,95,72,79,82,73,90,79,78,84,65,76,61,48,120,101,44,83,80,76,73,84,95,86,69,82,84,73,67,65,76,61,48,120,100,44,83,84,79,80,61,48,120,49,53,44,84,69,88,84,61,48,120,49,51,10,99,46,82,68,70,58,65,82,67,72,73,86,69,61,48,120,50,48,48,48,44,68,65,84,69,61,48,120,50,44,70,73,76,69,61,48,120,56,44,70,73,76,69,83,61,48,120,56,44,70,79,76,68,69,82,61,48,120,49,48,44,70,79,76,68,69,82,83,61,48,120,49,48,44,72,73,68,68,69,78,61,48,120,49,48,48,44,76,73,78,75,61,48,120,52,48,44,79,80,69,78,68,73,82,61,48,120,52,48,48,48,44,80,69,82,77,73,83,83,73,79,78,83,61,48,120,52,44,81,85,65,76,73,70,73,69,68,61,48,120,50,48,48,44,81,85,65,76,73,70,89,61,48,120,50,48,48,44,82,69,65,68,95,65,76,76,61,48,120,49,102,44,82,69,65,68,95,79,78,76,89,61,48,120,49,48,48,48,44,83,73,90,69,61,48,120,49,44,83,84,82,69,65,77,61,48,120,56,48,48,44,84,65,71,83,61,48,120,56,48,44,84,73,77,69,61,48,120,50,44,86,73,82,84,85,65,76,61,48,120,52,48,48,44,86,79,76,85,77,69,61,48,120,50,48,10,99,46,82,69,83,58,67,79,78,83,79,76,69,95,70,68,61,48,120,50,44,67,79,82,69,95,73,68,76,61,48,120,56,44,67,80,85,95,83,80,69,69,68,61,48,120,49,54,44,68,73,83,80,76,65,89,95,68,82,73,86,69,82,61,48,120,53,44,69,88,67,69,80,84,73,79,78,95,72,65,78,68,76,69,82,61,48,120,49,49,44,70,82,69,69,95,77,69,77,79,82,89,61,48,120,49,55,44,70,82,69,69,95,83,87,65,80,61,48,120,49,44,74,78,73,95,69,78,86,61,48,120,101,44,75,69,89,95,83,84,65,84,69,61,48,120,51,44,76,79,71,95,68,69,80,84,72,61,48,120,100,44,76,79,71,95,76,69,86,69,76,61,48,120,97,44,77,65,88,95,80,82,79,67,69,83,83,69,83,61,48,120,99,44,78,69,84,95,80,82,79,67,69,83,83,73,78,71,61,48,120,49,50,44,79,80,69,78,95,73,78,70,79,61,48,120,49,48,44,80,82,73,86,73,76,69,71,69,68,61,48,120,55,44,80,82,73,86,73,76,69,71,69,68,95,85,83,69,82,61,48,120,54,44,80,82,79,67,69,83,83,95,83,84,65,84,69,61,48,120,49,51,44,83,84,65,84,73,67,95,66,85,73,76,68,61,48,120,57,44,84,72,82,69,65,68,95,73,68,61,48,120,102,44,84,79,84,65,76,95,77,69,77,79,82,89,61,48,120,49,52,44,84,79,84,65,76,95,83,72,65,82,69,68,95,77,69,77,79,82,89,61,48,120,98,44,84,79,84,65,76,95,83,87,65,80,61,48,120,49,53,44,85,83,69,82,95,73,68,61,48,120,52,10,99,46,82,70,68,58,65,76,76,79,87,95,82,69,67,85,82,83,73,79,78,61,48,120,50,48,44,65,76,87,65,89,83,95,67,65,76,76,61,48,120,49,48,48,44,69,88,67,69,80,84,61,48,120,50,44,82,69,65,68,61,48,120,52,44,82,69,67,65,76,76,61,48,120,56,48,44,82,69,77,79,86,69,61,48,120,56,44,83,79,67,75,69,84,61,48,120,52,48,44,83,84,79,80,95,82,69,67,85,82,83,69,61,48,120,49,48,44,87,82,73,84,69,61,48,120,49,10,99,46,82,80,58,77,79,68,85,76,69,95,80,65,84,72,61,48,120,49,44,82,79,79,84,95,80,65,84,72,61,48,120,51,44,83,89,83,84,69,77,95,80,65,84,72,61,48,120,50,10,99,46,82,83,70,58,65,80,80,82,79,88,73,77,65,84,69,61,48,120,52,44,67,65,83,69,95,83,69,78,83,73,84,73,86,69,61,48,120,50,48,44,67,72,69,67,75,95,86,73,82,84,85,65,76,61,48,120,50,44,78,79,95,68,69,69,80,95,83,67,65,78,61,48,120,56,44,78,79,95,70,73,76,69,95,67,72,69,67,75,61,48,120,49,44,80,65,84,72,61,48,120,49,48,10,99,46,83,67,70,58,69,88,73,84,95,79,78,95,69,82,82,79,82,61,48,120,49,44,76,79,71,95,65,76,76,61,48,120,50,10,99,46,83,69,69,75,58,67,85,82,82,69,78,84,61,48,120,49,44,69,78,68,61,48,120,50,44,82,69,76,65,84,73,86,69,61,48,120,51,44,83,84,65,82,84,61,48,120,48,10,99,46,83,84,82,58,67,65,83,69,61,48,120,49,44,77,65,84,67,72,95,67,65,83,69,61,48,120,49,44,77,65,84,67,72,95,76,69,78,61,48,120,50,10,99,46,83,84,84,58,70,76,79,65,84,61,48,120,50,44,72,69,88,61,48,120,51,44,78,85,77,66,69,82,61,48,120,49,44,83,84,82,73,78,71,61,48,120,52,10,99,46,84,72,70,58,65,85,84,79,95,70,82,69,69,61,48,120,49,10,99,46,84,79,73,58,65,78,68,82,79,73,68,95,65,83,83,69,84,77,71,82,61,48,120,52,44,65,78,68,82,79,73,68,95,67,76,65,83,83,61,48,120,51,44,65,78,68,82,79,73,68,95,69,78,86,61,48,120,50,44,76,79,67,65,76,95,67,65,67,72,69,61,48,120,48,44,76,79,67,65,76,95,83,84,79,82,65,71,69,61,48,120,49,10,99,46,84,83,70,58,65,84,84,65,67,72,69,68,61,48,120,49,48,48,44,68,69,84,65,67,72,69,68,61,48,120,56,48,44,70,79,82,69,73,71,78,61,48,120,49,44,76,79,71,95,65,76,76,61,48,120,50,48,44,80,73,80,69,61,48,120,50,48,48,44,80,82,73,86,73,76,69,71,69,68,61,48,120,56,44,81,85,73,69,84,61,48,120,52,48,44,82,69,83,69,84,95,80,65,84,72,61,48,120,52,44,83,72,69,76,76,61,48,120,49,48,44,87,65,73,84,61,48,120,50,10,99,46,84,83,84,65,84,69,58,80,65,85,83,69,68,61,48,120,49,44,82,85,78,78,73,78,71,61,48,120,48,44,83,84,79,80,80,73,78,71,61,48,120,50,44,84,69,82,77,73,78,65,84,69,68,61,48,120,51,10,99,46,86,65,83,58,67,65,83,69,95,83,69,78,83,73,84,73,86,69,61,48,120,102,44,67,76,79,83,69,95,68,73,82,61,48,120,54,44,67,82,69,65,84,69,95,76,73,78,75,61,48,120,49,49,44,68,69,76,69,84,69,61,48,120,51,44,68,69,82,69,71,73,83,84,69,82,61,48,120,49,44,68,82,73,86,69,82,95,83,73,90,69,61,48,120,49,50,44,71,69,84,95,68,69,86,73,67,69,95,73,78,70,79,61,48,120,98,44,71,69,84,95,73,78,70,79,61,48,120,97,44,73,68,69,78,84,73,70,89,95,70,73,76,69,61,48,120,99,44,73,71,78,79,82,69,95,70,73,76,69,61,48,120,57,44,77,65,75,69,95,68,73,82,61,48,120,100,44,79,80,69,78,95,68,73,82,61,48,120,53,44,82,69,65,68,95,76,73,78,75,61,48,120,49,48,44,82,69,78,65,77,69,61,48,120,52,44,83,65,77,69,95,70,73,76,69,61,48,120,101,44,83,67,65,78,95,68,73,82,61,48,120,50,44,84,69,83,84,95,80,65,84,72,61,48,120,55,44,87,65,84,67,72,95,80,65,84,72,61,48,120,56,10,99,46,86,76,70,58,65,80,73,61,48,120,50,48,44,66,82,65,78,67,72,61,48,120,49,44,67,82,73,84,73,67,65,76,61,48,120,56,44,68,69,84,65,73,76,61,48,120,52,48,44,69,82,82,79,82,61,48,120,50,44,70,85,78,67,84,73,79,78,61,48,120,49,48,48,44,73,78,70,79,61,48,120,49,48,44,84,82,65,67,69,61,48,120,56,48,44,87,65,82,78,73,78,71,61,48,120,52,10,99,46,86,79,76,85,77,69,58,72,73,68,68,69,78,61,48,120,52,44,80,82,73,79,82,73,84,89,61,48,120,50,44,82,69,80,76,65,67,69,61,48,120,49,44,83,89,83,84,69,77,61,48,120,56,10,0 }; +char glIDL[] = { 115,46,73,110,112,117,116,69,118,101,110,116,58,112,78,101,120,116,58,73,110,112,117,116,69,118,101,110,116,44,100,86,97,108,117,101,44,120,84,105,109,101,115,116,97,109,112,44,108,82,101,99,105,112,105,101,110,116,73,68,44,108,79,118,101,114,73,68,44,100,65,98,115,88,44,100,65,98,115,89,44,100,88,44,100,89,44,108,68,101,118,105,99,101,73,68,44,108,84,121,112,101,44,108,70,108,97,103,115,44,108,77,97,115,107,10,115,46,100,99,82,101,113,117,101,115,116,58,108,73,116,101,109,44,99,80,114,101,102,101,114,101,110,99,101,91,52,93,10,115,46,100,99,65,117,100,105,111,58,108,83,105,122,101,44,108,70,111,114,109,97,116,10,115,46,100,99,75,101,121,69,110,116,114,121,58,108,70,108,97,103,115,44,108,86,97,108,117,101,44,120,84,105,109,101,115,116,97,109,112,44,108,85,110,105,99,111,100,101,10,115,46,100,99,68,101,118,105,99,101,73,110,112,117,116,58,100,86,97,108,117,101,115,91,50,93,44,120,84,105,109,101,115,116,97,109,112,44,108,68,101,118,105,99,101,73,68,44,108,70,108,97,103,115,44,108,84,121,112,101,10,115,46,68,97,116,101,84,105,109,101,58,119,89,101,97,114,44,99,77,111,110,116,104,44,99,68,97,121,44,99,72,111,117,114,44,99,77,105,110,117,116,101,44,99,83,101,99,111,110,100,44,99,84,105,109,101,90,111,110,101,10,115,46,72,83,86,58,100,72,117,101,44,100,83,97,116,117,114,97,116,105,111,110,44,100,86,97,108,117,101,44,100,65,108,112,104,97,10,115,46,70,82,71,66,58,102,82,101,100,44,102,71,114,101,101,110,44,102,66,108,117,101,44,102,65,108,112,104,97,10,115,46,82,71,66,56,58,117,99,82,101,100,44,117,99,71,114,101,101,110,44,117,99,66,108,117,101,44,117,99,65,108,112,104,97,10,115,46,82,71,66,49,54,58,117,119,82,101,100,44,117,119,71,114,101,101,110,44,117,119,66,108,117,101,44,117,119,65,108,112,104,97,10,115,46,82,71,66,51,50,58,117,108,82,101,100,44,117,108,71,114,101,101,110,44,117,108,66,108,117,101,44,117,108,65,108,112,104,97,10,115,46,82,71,66,80,97,108,101,116,116,101,58,108,65,109,116,67,111,108,111,117,114,115,44,101,67,111,108,58,82,71,66,56,91,50,53,54,93,10,115,46,67,111,108,111,117,114,70,111,114,109,97,116,58,117,99,82,101,100,83,104,105,102,116,44,117,99,71,114,101,101,110,83,104,105,102,116,44,117,99,66,108,117,101,83,104,105,102,116,44,117,99,65,108,112,104,97,83,104,105,102,116,44,117,99,82,101,100,77,97,115,107,44,117,99,71,114,101,101,110,77,97,115,107,44,117,99,66,108,117,101,77,97,115,107,44,117,99,65,108,112,104,97,77,97,115,107,44,117,99,82,101,100,80,111,115,44,117,99,71,114,101,101,110,80,111,115,44,117,99,66,108,117,101,80,111,115,44,117,99,65,108,112,104,97,80,111,115,44,117,99,66,105,116,115,80,101,114,80,105,120,101,108,10,115,46,67,108,105,112,82,101,99,116,97,110,103,108,101,58,108,76,101,102,116,44,108,84,111,112,44,108,82,105,103,104,116,44,108,66,111,116,116,111,109,10,115,46,69,100,103,101,115,58,108,76,101,102,116,44,108,84,111,112,44,108,82,105,103,104,116,44,108,66,111,116,116,111,109,10,115,46,79,98,106,101,99,116,83,105,103,110,97,108,58,111,79,98,106,101,99,116,10,115,46,70,117,110,99,116,105,111,110,70,105,101,108,100,58,115,78,97,109,101,44,117,108,84,121,112,101,10,115,46,70,117,110,99,116,105,111,110,58,112,65,100,100,114,101,115,115,44,115,78,97,109,101,44,112,65,114,103,115,58,70,117,110,99,116,105,111,110,70,105,101,108,100,10,115,46,70,105,101,108,100,65,114,114,97,121,58,115,78,97,109,101,44,112,71,101,116,70,105,101,108,100,44,112,83,101,116,70,105,101,108,100,44,109,65,114,103,44,117,108,70,108,97,103,115,10,115,46,70,105,101,108,100,68,101,102,58,115,78,97,109,101,44,108,86,97,108,117,101,10,115,46,83,121,115,116,101,109,83,116,97,116,101,58,115,80,108,97,116,102,111,114,109,44,108,67,111,110,115,111,108,101,70,68,44,108,83,116,97,103,101,10,115,46,85,110,105,116,58,100,86,97,108,117,101,44,117,108,84,121,112,101,10,115,46,65,99,116,105,111,110,65,114,114,97,121,58,112,82,111,117,116,105,110,101,44,108,65,99,116,105,111,110,67,111,100,101,10,115,46,65,99,116,105,111,110,84,97,98,108,101,58,117,108,72,97,115,104,44,108,83,105,122,101,44,115,78,97,109,101,44,112,65,114,103,115,58,70,117,110,99,116,105,111,110,70,105,101,108,100,10,115,46,67,104,105,108,100,69,110,116,114,121,58,108,79,98,106,101,99,116,73,68,44,117,108,67,108,97,115,115,73,68,10,115,46,77,101,115,115,97,103,101,58,120,84,105,109,101,44,108,85,73,68,44,108,84,121,112,101,44,108,83,105,122,101,10,115,46,77,101,109,73,110,102,111,58,112,83,116,97,114,116,44,108,79,98,106,101,99,116,73,68,44,117,108,83,105,122,101,44,108,70,108,97,103,115,44,108,77,101,109,111,114,121,73,68,44,119,65,99,99,101,115,115,67,111,117,110,116,10,115,46,67,111,109,112,114,101,115,115,105,111,110,70,101,101,100,98,97,99,107,58,108,70,101,101,100,98,97,99,107,73,68,44,108,73,110,100,101,120,44,115,80,97,116,104,44,115,68,101,115,116,44,120,80,114,111,103,114,101,115,115,44,120,79,114,105,103,105,110,97,108,83,105,122,101,44,120,67,111,109,112,114,101,115,115,101,100,83,105,122,101,44,119,89,101,97,114,44,119,77,111,110,116,104,44,119,68,97,121,44,119,72,111,117,114,44,119,77,105,110,117,116,101,44,119,83,101,99,111,110,100,10,115,46,67,111,109,112,114,101,115,115,101,100,73,116,101,109,58,120,79,114,105,103,105,110,97,108,83,105,122,101,44,120,67,111,109,112,114,101,115,115,101,100,83,105,122,101,44,112,78,101,120,116,58,67,111,109,112,114,101,115,115,101,100,73,116,101,109,44,115,80,97,116,104,44,108,80,101,114,109,105,115,115,105,111,110,115,44,108,85,115,101,114,73,68,44,108,71,114,111,117,112,73,68,44,108,79,116,104,101,114,115,73,68,44,108,70,108,97,103,115,44,101,67,114,101,97,116,101,100,58,68,97,116,101,84,105,109,101,44,101,77,111,100,105,102,105,101,100,58,68,97,116,101,84,105,109,101,10,115,46,70,105,108,101,73,110,102,111,58,120,83,105,122,101,44,120,84,105,109,101,83,116,97,109,112,44,112,78,101,120,116,58,70,105,108,101,73,110,102,111,44,115,78,97,109,101,44,108,70,108,97,103,115,44,108,80,101,114,109,105,115,115,105,111,110,115,44,108,85,115,101,114,73,68,44,108,71,114,111,117,112,73,68,44,101,67,114,101,97,116,101,100,58,68,97,116,101,84,105,109,101,44,101,77,111,100,105,102,105,101,100,58,68,97,116,101,84,105,109,101,10,115,46,68,105,114,73,110,102,111,58,112,73,110,102,111,58,70,105,108,101,73,110,102,111,10,115,46,70,105,108,101,70,101,101,100,98,97,99,107,58,120,83,105,122,101,44,120,80,111,115,105,116,105,111,110,44,115,80,97,116,104,44,115,68,101,115,116,44,108,70,101,101,100,98,97,99,107,73,68,44,99,82,101,115,101,114,118,101,100,91,51,50,93,10,115,46,70,105,101,108,100,58,109,65,114,103,44,112,71,101,116,86,97,108,117,101,44,112,83,101,116,86,97,108,117,101,44,112,87,114,105,116,101,86,97,108,117,101,44,115,78,97,109,101,44,117,108,70,105,101,108,100,73,68,44,117,119,79,102,102,115,101,116,44,117,119,73,110,100,101,120,44,117,108,70,108,97,103,115,10,99,46,65,67,58,65,99,116,105,118,97,116,101,61,48,120,50,44,67,108,101,97,114,61,48,120,52,44,67,108,105,112,98,111,97,114,100,61,48,120,50,100,44,67,111,112,121,68,97,116,97,61,48,120,55,44,68,97,116,97,70,101,101,100,61,48,120,56,44,68,101,97,99,116,105,118,97,116,101,61,48,120,57,44,68,105,115,97,98,108,101,61,48,120,50,102,44,68,114,97,103,68,114,111,112,61,48,120,49,48,44,68,114,97,119,61,48,120,97,44,69,78,68,61,48,120,51,49,44,69,110,97,98,108,101,61,48,120,54,44,70,108,117,115,104,61,48,120,98,44,70,111,99,117,115,61,48,120,99,44,70,114,101,101,61,48,120,100,44,70,114,101,101,87,97,114,110,105,110,103,61,48,120,53,44,71,101,116,75,101,121,61,48,120,102,44,72,105,100,101,61,48,120,49,49,44,73,110,105,116,61,48,120,49,50,44,76,111,99,107,61,48,120,49,51,44,76,111,115,116,70,111,99,117,115,61,48,120,49,52,44,77,111,118,101,61,48,120,49,53,44,77,111,118,101,84,111,66,97,99,107,61,48,120,49,54,44,77,111,118,101,84,111,70,114,111,110,116,61,48,120,49,55,44,77,111,118,101,84,111,80,111,105,110,116,61,48,120,50,51,44,78,101,119,67,104,105,108,100,61,48,120,49,56,44,78,101,119,79,98,106,101,99,116,61,48,120,49,97,44,78,101,119,79,119,110,101,114,61,48,120,49,57,44,78,101,119,80,108,97,99,101,109,101,110,116,61,48,120,51,48,44,78,101,120,116,61,48,120,50,57,44,80,114,101,118,61,48,120,50,97,44,81,117,101,114,121,61,48,120,49,99,44,82,101,97,100,61,48,120,49,100,44,82,101,100,105,109,101,110,115,105,111,110,61,48,120,51,44,82,101,100,111,61,48,120,49,98,44,82,101,102,114,101,115,104,61,48,120,50,101,44,82,101,110,97,109,101,61,48,120,49,101,44,82,101,115,101,116,61,48,120,49,102,44,82,101,115,105,122,101,61,48,120,50,48,44,83,97,118,101,73,109,97,103,101,61,48,120,50,49,44,83,97,118,101,83,101,116,116,105,110,103,115,61,48,120,101,44,83,97,118,101,84,111,79,98,106,101,99,116,61,48,120,50,50,44,83,101,101,107,61,48,120,50,52,44,83,101,116,70,105,101,108,100,61,48,120,50,99,44,83,101,116,75,101,121,61,48,120,50,53,44,83,104,111,119,61,48,120,50,54,44,83,105,103,110,97,108,61,48,120,49,44,85,110,100,111,61,48,120,50,55,44,85,110,108,111,99,107,61,48,120,50,56,44,87,114,105,116,101,61,48,120,50,98,10,99,46,65,76,73,71,78,58,66,79,84,84,79,77,61,48,120,50,48,44,67,69,78,84,69,82,61,48,120,99,44,72,79,82,73,90,79,78,84,65,76,61,48,120,52,44,76,69,70,84,61,48,120,49,44,77,73,68,68,76,69,61,48,120,99,44,82,73,71,72,84,61,48,120,50,44,84,79,80,61,48,120,49,48,44,86,69,82,84,73,67,65,76,61,48,120,56,10,99,46,67,67,70,58,65,85,68,73,79,61,48,120,56,48,44,67,79,77,77,65,78,68,61,48,120,49,44,68,65,84,65,61,48,120,49,48,48,44,70,73,76,69,83,89,83,84,69,77,61,48,120,50,44,71,82,65,80,72,73,67,83,61,48,120,52,44,71,85,73,61,48,120,56,44,73,79,61,48,120,49,48,44,77,73,83,67,61,48,120,50,48,48,44,77,85,76,84,73,77,69,68,73,65,61,48,120,56,48,48,44,78,69,84,87,79,82,75,61,48,120,52,48,48,44,83,89,83,84,69,77,61,48,120,50,48,44,84,79,79,76,61,48,120,52,48,10,99,46,67,70,58,68,69,70,76,65,84,69,61,48,120,51,44,71,90,73,80,61,48,120,49,44,90,76,73,66,61,48,120,50,10,99,46,67,76,70,58,73,78,72,69,82,73,84,95,76,79,67,65,76,61,48,120,49,44,78,79,95,79,87,78,69,82,83,72,73,80,61,48,120,50,10,99,46,67,76,73,80,77,79,68,69,58,67,79,80,89,61,48,120,50,44,67,85,84,61,48,120,49,44,80,65,83,84,69,61,48,120,52,10,99,46,67,77,70,58,65,80,80,76,89,95,83,69,67,85,82,73,84,89,61,48,120,50,48,44,67,82,69,65,84,69,95,70,73,76,69,61,48,120,52,44,78,69,87,61,48,120,50,44,78,79,95,76,73,78,75,83,61,48,120,49,48,44,80,65,83,83,87,79,82,68,61,48,120,49,44,82,69,65,68,95,79,78,76,89,61,48,120,56,10,99,46,67,78,70,58,65,85,84,79,95,83,65,86,69,61,48,120,50,44,78,69,87,61,48,120,56,44,79,80,84,73,79,78,65,76,95,70,73,76,69,83,61,48,120,52,44,83,84,82,73,80,95,81,85,79,84,69,83,61,48,120,49,10,99,46,68,65,84,65,58,65,85,68,73,79,61,48,120,53,44,67,79,78,84,69,78,84,61,48,120,98,44,68,69,86,73,67,69,95,73,78,80,85,84,61,48,120,51,44,70,73,76,69,61,48,120,97,44,73,77,65,71,69,61,48,120,55,44,73,78,80,85,84,95,82,69,65,68,89,61,48,120,99,44,82,65,87,61,48,120,50,44,82,69,67,69,73,80,84,61,48,120,57,44,82,69,67,79,82,68,61,48,120,54,44,82,69,81,85,69,83,84,61,48,120,56,44,84,69,88,84,61,48,120,49,44,88,77,76,61,48,120,52,10,99,46,68,69,86,73,67,69,58,66,79,79,75,77,65,82,75,61,48,120,52,48,48,48,48,44,67,79,77,80,65,67,84,95,68,73,83,67,61,48,120,49,44,70,73,88,69,68,61,48,120,56,48,48,48,44,70,76,79,80,80,89,95,68,73,83,75,61,48,120,52,44,72,65,82,68,95,68,73,83,75,61,48,120,50,44,77,69,77,79,82,89,61,48,120,49,48,48,48,44,77,79,68,69,77,61,48,120,50,48,48,48,44,78,69,84,87,79,82,75,61,48,120,56,48,44,80,82,73,78,84,69,82,61,48,120,50,48,48,44,80,82,73,78,84,69,82,95,51,68,61,48,120,49,48,48,48,48,44,82,69,65,68,61,48,120,56,44,82,69,77,79,86,65,66,76,69,61,48,120,50,48,44,82,69,77,79,86,69,65,66,76,69,61,48,120,50,48,44,83,67,65,78,78,69,82,61,48,120,52,48,48,44,83,67,65,78,78,69,82,95,51,68,61,48,120,50,48,48,48,48,44,83,79,70,84,87,65,82,69,61,48,120,52,48,44,84,65,80,69,61,48,120,49,48,48,44,84,69,77,80,79,82,65,82,89,61,48,120,56,48,48,44,85,83,66,61,48,120,52,48,48,48,44,87,82,73,84,69,61,48,120,49,48,10,99,46,68,77,70,58,70,73,88,69,68,95,67,69,78,84,69,82,95,88,61,48,120,49,48,48,48,48,48,44,70,73,88,69,68,95,67,69,78,84,69,82,95,89,61,48,120,50,48,48,48,48,48,44,70,73,88,69,68,95,68,69,80,84,72,61,48,120,49,48,48,48,44,70,73,88,69,68,95,72,69,73,71,72,84,61,48,120,49,48,48,44,70,73,88,69,68,95,82,65,68,73,85,83,95,88,61,48,120,50,48,48,48,48,44,70,73,88,69,68,95,82,65,68,73,85,83,95,89,61,48,120,50,48,48,48,48,48,48,44,70,73,88,69,68,95,87,73,68,84,72,61,48,120,50,48,48,44,70,73,88,69,68,95,88,61,48,120,52,44,70,73,88,69,68,95,88,95,79,70,70,83,69,84,61,48,120,52,48,44,70,73,88,69,68,95,89,61,48,120,56,44,70,73,88,69,68,95,89,95,79,70,70,83,69,84,61,48,120,56,48,44,70,73,88,69,68,95,90,61,48,120,52,48,48,48,44,83,67,65,76,69,68,95,67,69,78,84,69,82,95,88,61,48,120,52,48,48,48,48,44,83,67,65,76,69,68,95,67,69,78,84,69,82,95,89,61,48,120,56,48,48,48,48,44,83,67,65,76,69,68,95,68,69,80,84,72,61,48,120,50,48,48,48,44,83,67,65,76,69,68,95,72,69,73,71,72,84,61,48,120,52,48,48,44,83,67,65,76,69,68,95,82,65,68,73,85,83,95,88,61,48,120,49,48,48,48,48,44,83,67,65,76,69,68,95,82,65,68,73,85,83,95,89,61,48,120,49,48,48,48,48,48,48,44,83,67,65,76,69,68,95,87,73,68,84,72,61,48,120,56,48,48,44,83,67,65,76,69,68,95,88,61,48,120,49,44,83,67,65,76,69,68,95,88,95,79,70,70,83,69,84,61,48,120,49,48,44,83,67,65,76,69,68,95,89,61,48,120,50,44,83,67,65,76,69,68,95,89,95,79,70,70,83,69,84,61,48,120,50,48,44,83,67,65,76,69,68,95,90,61,48,120,56,48,48,48,44,83,84,65,84,85,83,95,67,72,65,78,71,69,95,72,61,48,120,52,48,48,48,48,48,44,83,84,65,84,85,83,95,67,72,65,78,71,69,95,86,61,48,120,56,48,48,48,48,48,10,99,46,68,82,76,58,68,79,87,78,61,48,120,49,44,69,65,83,84,61,48,120,50,44,76,69,70,84,61,48,120,51,44,78,79,82,84,72,61,48,120,48,44,78,79,82,84,72,95,69,65,83,84,61,48,120,52,44,78,79,82,84,72,95,87,69,83,84,61,48,120,53,44,82,73,71,72,84,61,48,120,50,44,83,79,85,84,72,61,48,120,49,44,83,79,85,84,72,95,69,65,83,84,61,48,120,54,44,83,79,85,84,72,95,87,69,83,84,61,48,120,55,44,85,80,61,48,120,48,44,87,69,83,84,61,48,120,51,10,99,46,69,68,71,69,58,65,76,76,61,48,120,102,102,44,66,79,84,84,79,77,61,48,120,56,44,66,79,84,84,79,77,95,76,69,70,84,61,48,120,52,48,44,66,79,84,84,79,77,95,82,73,71,72,84,61,48,120,56,48,44,76,69,70,84,61,48,120,50,44,82,73,71,72,84,61,48,120,52,44,84,79,80,61,48,120,49,44,84,79,80,95,76,69,70,84,61,48,120,49,48,44,84,79,80,95,82,73,71,72,84,61,48,120,50,48,10,99,46,69,82,70,58,78,111,116,105,102,105,101,100,61,48,120,52,48,48,48,48,48,48,48,10,99,46,69,82,82,58,65,99,99,101,115,115,77,101,109,111,114,121,61,48,120,52,98,44,65,99,99,101,115,115,79,98,106,101,99,116,61,48,120,53,51,44,65,99,99,101,115,115,83,101,109,97,112,104,111,114,101,61,48,120,55,51,44,65,99,116,105,118,97,116,101,61,48,120,52,50,44,65,100,100,67,108,97,115,115,61,48,120,52,49,44,65,108,108,111,99,77,101,109,111,114,121,61,48,120,53,52,44,65,108,108,111,99,83,101,109,97,112,104,111,114,101,61,48,120,55,50,44,65,108,114,101,97,100,121,68,101,102,105,110,101,100,61,48,120,98,54,44,65,108,114,101,97,100,121,76,111,99,107,101,100,61,48,120,57,99,44,65,114,103,115,61,48,120,49,52,44,65,114,114,97,121,70,117,108,108,61,48,120,50,100,44,66,117,102,102,101,114,79,118,101,114,102,108,111,119,61,48,120,53,99,44,66,117,115,121,61,48,120,56,98,44,67,97,110,99,101,108,108,101,100,61,48,120,51,44,67,97,114,100,82,101,97,100,101,114,85,110,97,118,97,105,108,97,98,108,101,61,48,120,57,102,44,67,97,114,100,82,101,97,100,101,114,85,110,107,110,111,119,110,61,48,120,57,100,44,67,111,109,112,114,101,115,115,105,111,110,61,48,120,97,100,44,67,111,110,110,101,99,116,105,111,110,65,98,111,114,116,101,100,61,48,120,56,99,44,67,111,110,110,101,99,116,105,111,110,82,101,102,117,115,101,100,61,48,120,56,51,44,67,111,110,115,116,114,97,105,110,116,86,105,111,108,97,116,105,111,110,61,48,120,56,56,44,67,111,110,116,105,110,117,101,61,48,120,53,44,67,111,114,101,86,101,114,115,105,111,110,61,48,120,50,54,44,67,114,101,97,116,101,70,105,108,101,61,48,120,55,52,44,67,114,101,97,116,101,79,98,106,101,99,116,61,48,120,54,53,44,67,114,101,97,116,101,82,101,115,111,117,114,99,101,61,48,120,98,50,44,68,97,116,97,83,105,122,101,61,48,120,56,97,44,68,101,97,99,116,105,118,97,116,101,100,61,48,120,57,97,44,68,101,97,100,76,111,99,107,61,48,120,51,101,44,68,101,99,111,109,112,114,101,115,115,105,111,110,61,48,120,97,99,44,68,101,108,101,116,101,70,105,108,101,61,48,120,55,53,44,68,105,114,69,109,112,116,121,61,48,120,56,44,68,105,115,99,111,110,110,101,99,116,101,100,61,48,120,56,54,44,68,111,78,111,116,69,120,112,117,110,103,101,61,48,120,51,48,44,68,111,101,115,78,111,116,69,120,105,115,116,61,48,120,55,56,44,68,111,117,98,108,101,73,110,105,116,61,48,120,52,51,44,68,114,97,119,61,48,120,52,56,44,69,78,68,61,48,120,98,101,44,69,109,112,116,121,83,116,114,105,110,103,61,48,120,54,100,44,69,110,100,79,102,70,105,108,101,61,48,120,55,101,44,69,110,116,114,121,77,105,115,115,105,110,103,72,101,97,100,101,114,61,48,120,51,97,44,69,120,97,109,105,110,101,70,97,105,108,101,100,61,48,120,49,57,44,69,120,99,101,112,116,105,111,110,61,48,120,97,51,44,69,120,99,101,112,116,105,111,110,84,104,114,101,115,104,111,108,100,61,48,120,57,44,69,120,99,108,117,115,105,118,101,68,101,110,105,101,100,61,48,120,53,51,44,69,120,101,99,86,105,111,108,97,116,105,111,110,61,48,120,56,102,44,69,120,105,115,116,115,61,48,120,55,97,44,69,120,112,101,99,116,101,100,70,105,108,101,61,48,120,54,102,44,69,120,112,101,99,116,101,100,70,111,108,100,101,114,61,48,120,97,101,44,70,97,105,108,101,100,61,48,120,100,44,70,97,108,115,101,61,48,120,49,44,70,105,101,108,100,78,111,116,83,101,116,61,48,120,52,52,44,70,105,101,108,100,83,101,97,114,99,104,61,48,120,51,50,44,70,105,101,108,100,84,121,112,101,77,105,115,109,97,116,99,104,61,48,120,53,97,44,70,105,108,101,61,48,120,101,44,70,105,108,101,68,111,101,115,78,111,116,69,120,105,115,116,61,48,120,49,50,44,70,105,108,101,69,120,105,115,116,115,61,48,120,54,51,44,70,105,108,101,78,111,116,70,111,117,110,100,61,48,120,49,50,44,70,105,108,101,82,101,97,100,70,108,97,103,61,48,120,52,54,44,70,105,108,101,87,114,105,116,101,70,108,97,103,61,48,120,52,55,44,70,105,110,105,115,104,101,100,61,48,120,55,101,44,70,117,110,99,116,105,111,110,61,48,120,98,53,44,71,101,116,70,105,101,108,100,61,48,120,53,54,44,71,101,116,83,117,114,102,97,99,101,73,110,102,111,61,48,120,55,100,44,72,111,115,116,78,111,116,70,111,117,110,100,61,48,120,56,49,44,72,111,115,116,85,110,114,101,97,99,104,97,98,108,101,61,48,120,56,53,44,73,100,101,110,116,105,99,97,108,80,97,116,104,115,61,48,120,55,57,44,73,108,108,101,103,97,108,65,99,116,105,111,110,65,116,116,101,109,112,116,61,48,120,51,57,44,73,108,108,101,103,97,108,65,99,116,105,111,110,73,68,61,48,120,51,55,44,73,108,108,101,103,97,108,65,100,100,114,101,115,115,61,48,120,57,49,44,73,108,108,101,103,97,108,77,101,116,104,111,100,73,68,61,48,120,51,54,44,73,109,109,117,116,97,98,108,101,61,48,120,97,102,44,73,110,85,115,101,61,48,120,99,44,73,110,105,116,61,48,120,50,49,44,73,110,105,116,77,111,100,117,108,101,61,48,120,49,49,44,73,110,112,117,116,79,117,116,112,117,116,61,48,120,57,52,44,73,110,116,101,103,114,105,116,121,86,105,111,108,97,116,105,111,110,61,48,120,56,56,44,73,110,118,97,108,105,100,68,97,116,97,61,48,120,102,44,73,110,118,97,108,105,100,68,105,109,101,110,115,105,111,110,61,48,120,53,57,44,73,110,118,97,108,105,100,72,84,84,80,82,101,115,112,111,110,115,101,61,48,120,97,49,44,73,110,118,97,108,105,100,72,97,110,100,108,101,61,48,120,57,54,44,73,110,118,97,108,105,100,79,98,106,101,99,116,61,48,120,56,101,44,73,110,118,97,108,105,100,80,97,116,104,61,48,120,51,51,44,73,110,118,97,108,105,100,82,101,102,101,114,101,110,99,101,61,48,120,97,50,44,73,110,118,97,108,105,100,83,116,97,116,101,61,48,120,56,48,44,73,110,118,97,108,105,100,85,82,73,61,48,120,56,50,44,73,110,118,97,108,105,100,86,97,108,117,101,61,48,120,57,56,44,76,105,109,105,116,101,100,83,117,99,99,101,115,115,61,48,120,50,44,76,105,115,116,67,104,105,108,100,114,101,110,61,48,120,54,97,44,76,111,97,100,77,111,100,117,108,101,61,48,120,57,53,44,76,111,99,107,61,48,120,49,56,44,76,111,99,107,70,97,105,108,101,100,61,48,120,49,56,44,76,111,99,107,77,117,116,101,120,61,48,120,97,97,44,76,111,99,107,82,101,113,117,105,114,101,100,61,48,120,57,98,44,76,111,99,107,101,100,61,48,120,57,99,44,76,111,111,112,61,48,120,54,50,44,76,111,115,116,67,108,97,115,115,61,48,120,49,97,44,76,111,115,116,79,119,110,101,114,61,48,120,50,102,44,76,111,119,67,97,112,97,99,105,116,121,61,48,120,50,48,44,77,97,114,107,101,100,70,111,114,68,101,108,101,116,105,111,110,61,48,120,51,53,44,77,101,109,111,114,121,61,48,120,49,100,44,77,101,109,111,114,121,67,111,114,114,117,112,116,61,48,120,51,49,44,77,101,109,111,114,121,68,111,101,115,78,111,116,69,120,105,115,116,61,48,120,51,100,44,77,101,109,111,114,121,73,110,102,111,61,48,120,54,54,44,77,105,115,109,97,116,99,104,61,48,120,53,101,44,77,105,115,115,105,110,103,67,108,97,115,115,61,48,120,52,53,44,77,105,115,115,105,110,103,67,108,97,115,115,78,97,109,101,61,48,120,50,97,44,77,105,115,115,105,110,103,80,97,116,104,61,48,120,52,99,44,77,111,100,117,108,101,73,110,105,116,70,97,105,108,101,100,61,48,120,51,99,44,77,111,100,117,108,101,77,105,115,115,105,110,103,73,110,105,116,61,48,120,51,98,44,77,111,100,117,108,101,77,105,115,115,105,110,103,78,97,109,101,61,48,120,52,48,44,77,111,100,117,108,101,79,112,101,110,70,97,105,108,101,100,61,48,120,51,56,44,78,101,101,100,79,119,110,101,114,61,48,120,50,52,44,78,101,101,100,87,105,100,116,104,72,101,105,103,104,116,61,48,120,50,55,44,78,101,103,97,116,105,118,101,67,108,97,115,115,73,68,61,48,120,50,57,44,78,101,103,97,116,105,118,101,83,117,98,67,108,97,115,115,73,68,61,48,120,50,56,44,78,101,116,119,111,114,107,85,110,114,101,97,99,104,97,98,108,101,61,48,120,56,52,44,78,101,119,79,98,106,101,99,116,61,48,120,53,53,44,78,111,65,99,116,105,111,110,61,48,120,49,98,44,78,111,68,97,116,97,61,48,120,49,53,44,78,111,70,105,101,108,100,65,99,99,101,115,115,61,48,120,53,55,44,78,111,77,97,116,99,104,105,110,103,79,98,106,101,99,116,61,48,120,52,97,44,78,111,77,101,100,105,97,73,110,115,101,114,116,101,100,61,48,120,57,101,44,78,111,77,101,109,111,114,121,61,48,120,97,44,78,111,77,101,116,104,111,100,115,61,48,120,52,57,44,78,111,80,101,114,109,105,115,115,105,111,110,61,48,120,50,50,44,78,111,80,111,105,110,116,101,114,61,48,120,98,44,78,111,83,101,97,114,99,104,82,101,115,117,108,116,61,48,120,52,101,44,78,111,83,116,97,116,115,61,48,120,49,102,44,78,111,83,117,112,112,111,114,116,61,48,120,49,99,44,78,111,116,70,111,117,110,100,61,48,120,49,48,44,78,111,116,73,110,105,116,105,97,108,105,115,101,100,61,48,120,54,55,44,78,111,116,76,111,99,107,101,100,61,48,120,52,100,44,78,111,116,80,111,115,115,105,98,108,101,61,48,120,98,51,44,78,111,116,104,105,110,103,68,111,110,101,61,48,120,52,44,78,111,116,105,102,105,101,100,61,48,120,52,48,48,48,48,48,48,48,44,78,117,108,108,65,114,103,115,61,48,120,56,100,44,79,98,106,101,99,116,67,111,114,114,117,112,116,61,48,120,53,48,44,79,98,106,101,99,116,69,120,105,115,116,115,61,48,120,54,101,44,79,98,115,111,108,101,116,101,61,48,120,98,49,44,79,98,116,97,105,110,77,101,116,104,111,100,61,48,120,50,99,44,79,107,97,121,61,48,120,48,44,79,112,101,110,70,105,108,101,61,48,120,55,54,44,79,112,101,110,71,76,61,48,120,97,53,44,79,117,116,79,102,66,111,117,110,100,115,61,48,120,53,102,44,79,117,116,79,102,68,97,116,97,61,48,120,55,101,44,79,117,116,79,102,82,97,110,103,101,61,48,120,50,98,44,79,117,116,79,102,83,112,97,99,101,61,48,120,55,99,44,79,117,116,115,105,100,101,77,97,105,110,84,104,114,101,97,100,61,48,120,97,54,44,79,119,110,101,114,78,101,101,100,115,66,105,116,109,97,112,61,48,120,50,53,44,79,119,110,101,114,80,97,115,115,84,104,114,111,117,103,104,61,48,120,53,49,44,80,101,114,109,105,115,115,105,111,110,68,101,110,105,101,100,61,48,120,50,50,44,80,101,114,109,105,115,115,105,111,110,115,61,48,120,50,50,44,80,114,111,120,121,83,83,76,84,117,110,110,101,108,61,48,120,97,48,44,81,117,101,114,121,61,48,120,50,101,44,82,101,97,100,61,48,120,49,54,44,82,101,97,100,70,105,108,101,84,111,66,117,102,102,101,114,61,48,120,98,48,44,82,101,97,100,79,110,108,121,61,48,120,55,55,44,82,101,97,108,108,111,99,77,101,109,111,114,121,61,48,120,54,49,44,82,101,99,117,114,115,105,111,110,61,48,120,57,48,44,82,101,100,105,109,101,110,115,105,111,110,61,48,120,55,49,44,82,101,102,114,101,115,104,61,48,120,54,57,44,82,101,115,105,122,101,61,48,120,55,48,44,82,101,115,111,108,118,101,80,97,116,104,61,48,120,54,52,44,82,101,115,111,108,118,101,83,121,109,98,111,108,61,48,120,98,52,44,82,101,115,111,117,114,99,101,69,120,105,115,116,115,61,48,120,54,56,44,82,101,116,114,121,61,48,120,55,44,83,97,110,105,116,121,70,97,105,108,117,114,101,61,48,120,55,98,44,83,99,104,101,109,97,86,105,111,108,97,116,105,111,110,61,48,120,56,57,44,83,101,97,114,99,104,61,48,120,49,48,44,83,101,99,117,114,105,116,121,61,48,120,57,55,44,83,101,101,107,61,48,120,54,48,44,83,101,114,118,105,99,101,85,110,97,118,97,105,108,97,98,108,101,61,48,120,57,57,44,83,101,116,70,105,101,108,100,61,48,120,51,52,44,83,101,116,86,97,108,117,101,78,111,116,65,114,114,97,121,61,48,120,98,99,44,83,101,116,86,97,108,117,101,78,111,116,70,117,110,99,116,105,111,110,61,48,120,98,97,44,83,101,116,86,97,108,117,101,78,111,116,76,111,111,107,117,112,61,48,120,98,100,44,83,101,116,86,97,108,117,101,78,111,116,78,117,109,101,114,105,99,61,48,120,98,55,44,83,101,116,86,97,108,117,101,78,111,116,79,98,106,101,99,116,61,48,120,98,57,44,83,101,116,86,97,108,117,101,78,111,116,80,111,105,110,116,101,114,61,48,120,98,98,44,83,101,116,86,97,108,117,101,78,111,116,83,116,114,105,110,103,61,48,120,98,56,44,83,101,116,86,111,108,117,109,101,61,48,120,97,98,44,83,107,105,112,61,48,120,54,44,83,109,97,108,108,77,97,115,107,61,48,120,54,99,44,83,116,97,116,101,109,101,110,116,85,110,115,97,116,105,115,102,105,101,100,61,48,120,52,102,44,83,116,114,105,110,103,70,111,114,109,97,116,61,48,120,55,102,44,83,121,110,116,97,120,61,48,120,55,102,44,83,121,115,116,101,109,67,97,108,108,61,48,120,54,98,44,83,121,115,116,101,109,67,111,114,114,117,112,116,61,48,120,50,51,44,83,121,115,116,101,109,76,111,99,107,101,100,61,48,120,51,102,44,84,97,115,107,83,116,105,108,108,69,120,105,115,116,115,61,48,120,56,55,44,84,101,114,109,105,110,97,116,101,61,48,120,57,44,84,104,114,101,97,100,65,108,114,101,97,100,121,65,99,116,105,118,101,61,48,120,97,52,44,84,104,114,101,97,100,78,111,116,76,111,99,107,101,100,61,48,120,97,57,44,84,105,109,101,79,117,116,61,48,120,49,101,44,84,114,117,101,61,48,120,48,44,85,110,98,97,108,97,110,99,101,100,88,77,76,61,48,120,57,50,44,85,110,100,101,102,105,110,101,100,70,105,101,108,100,61,48,120,52,52,44,85,110,114,101,99,111,103,110,105,115,101,100,70,105,101,108,100,84,121,112,101,61,48,120,53,98,44,85,110,115,117,112,112,111,114,116,101,100,70,105,101,108,100,61,48,120,53,100,44,85,110,115,117,112,112,111,114,116,101,100,79,119,110,101,114,61,48,120,53,50,44,85,115,101,83,117,98,67,108,97,115,115,61,48,120,97,55,44,86,105,114,116,117,97,108,86,111,108,117,109,101,61,48,120,53,56,44,87,111,117,108,100,66,108,111,99,107,61,48,120,57,51,44,87,114,105,116,101,61,48,120,49,55,44,87,114,111,110,103,67,108,97,115,115,61,48,120,56,101,44,87,114,111,110,103,79,98,106,101,99,116,84,121,112,101,61,48,120,56,101,44,87,114,111,110,103,84,121,112,101,61,48,120,97,56,44,87,114,111,110,103,86,101,114,115,105,111,110,61,48,120,49,51,10,99,46,69,86,71,58,65,78,68,82,79,73,68,61,48,120,100,44,65,80,80,61,48,120,99,44,65,85,68,73,79,61,48,120,56,44,67,76,65,83,83,61,48,120,98,44,68,73,83,80,76,65,89,61,48,120,53,44,69,78,68,61,48,120,101,44,70,73,76,69,83,89,83,84,69,77,61,48,120,49,44,71,85,73,61,48,120,52,44,72,65,82,68,87,65,82,69,61,48,120,55,44,73,79,61,48,120,54,44,78,69,84,87,79,82,75,61,48,120,50,44,80,79,87,69,82,61,48,120,97,44,83,89,83,84,69,77,61,48,120,51,44,85,83,69,82,61,48,120,57,10,99,46,70,66,75,58,67,79,80,89,95,70,73,76,69,61,48,120,50,44,68,69,76,69,84,69,95,70,73,76,69,61,48,120,51,44,77,79,86,69,95,70,73,76,69,61,48,120,49,10,99,46,70,68,58,65,76,76,79,67,61,48,120,50,48,44,65,82,82,65,89,61,48,120,49,48,48,48,44,65,82,82,65,89,83,73,90,69,61,48,120,56,48,44,66,85,70,70,69,82,61,48,120,50,48,48,44,66,85,70,83,73,90,69,61,48,120,56,48,44,66,89,84,69,61,48,120,49,48,48,48,48,48,48,44,67,80,80,61,48,120,52,48,48,48,44,67,85,83,84,79,77,61,48,120,56,48,48,48,44,68,79,85,66,76,69,61,48,120,56,48,48,48,48,48,48,48,44,68,79,85,66,76,69,82,69,83,85,76,84,61,48,120,56,48,48,48,48,49,48,48,44,69,82,82,79,82,61,48,120,56,48,48,44,70,76,65,71,83,61,48,120,52,48,44,70,76,79,65,84,61,48,120,49,48,48,48,48,48,48,48,44,70,85,78,67,84,73,79,78,61,48,120,50,48,48,48,48,48,48,44,70,85,78,67,84,73,79,78,80,84,82,61,48,120,97,48,48,48,48,48,48,44,73,61,48,120,52,48,48,44,73,78,73,84,61,48,120,52,48,48,44,76,65,82,71,69,61,48,120,52,48,48,48,48,48,48,44,76,65,82,71,69,82,69,83,85,76,84,61,48,120,52,48,48,48,49,48,48,44,76,79,67,65,76,61,48,120,50,44,76,79,78,71,61,48,120,52,48,48,48,48,48,48,48,44,76,79,78,71,82,69,83,85,76,84,61,48,120,52,48,48,48,48,49,48,48,44,76,79,79,75,85,80,61,48,120,56,48,44,79,66,74,69,67,84,61,48,120,49,44,79,66,74,69,67,84,73,68,61,48,120,52,48,48,48,48,48,48,49,44,79,66,74,69,67,84,80,84,82,61,48,120,56,48,48,48,48,48,49,44,80,79,73,78,84,69,82,61,48,120,56,48,48,48,48,48,48,44,80,82,73,86,65,84,69,61,48,120,49,48,48,48,48,44,80,84,82,61,48,120,56,48,48,48,48,48,48,44,80,84,82,66,85,70,70,69,82,61,48,120,56,48,48,48,50,48,48,44,80,84,82,82,69,83,85,76,84,61,48,120,56,48,48,48,49,48,48,44,80,84,82,83,73,90,69,61,48,120,56,48,44,80,84,82,95,68,79,85,66,76,69,82,69,83,85,76,84,61,48,120,56,56,48,48,48,49,48,48,44,80,84,82,95,76,65,82,71,69,82,69,83,85,76,84,61,48,120,99,48,48,48,49,48,48,44,80,84,82,95,76,79,78,71,82,69,83,85,76,84,61,48,120,52,56,48,48,48,49,48,48,44,82,61,48,120,49,48,48,44,82,69,65,68,61,48,120,49,48,48,44,82,69,83,79,85,82,67,69,61,48,120,50,48,48,48,44,82,69,83,85,76,84,61,48,120,49,48,48,44,82,71,66,61,48,120,56,48,48,48,48,44,82,73,61,48,120,53,48,48,44,82,87,61,48,120,51,48,48,44,83,67,65,76,69,68,61,48,120,50,48,48,48,48,48,44,83,84,82,61,48,120,56,48,48,48,48,48,44,83,84,82,73,78,71,61,48,120,56,48,48,48,48,48,44,83,84,82,82,69,83,85,76,84,61,48,120,56,48,48,49,48,48,44,83,84,82,85,67,84,61,48,120,49,48,44,83,89,78,79,78,89,77,61,48,120,50,48,48,48,48,44,83,89,83,84,69,77,61,48,120,49,48,48,48,48,44,84,65,71,83,61,48,120,52,48,48,44,85,78,73,84,61,48,120,50,48,48,48,48,48,48,48,44,85,78,83,73,71,78,69,68,61,48,120,52,48,48,48,48,44,86,65,82,84,65,71,83,61,48,120,52,48,44,86,73,82,84,85,65,76,61,48,120,56,44,86,79,73,68,61,48,120,48,44,86,79,76,65,84,73,76,69,61,48,120,48,44,87,61,48,120,50,48,48,44,87,79,82,68,61,48,120,52,48,48,48,48,48,44,87,82,73,84,69,61,48,120,50,48,48,10,99,46,70,68,66,58,67,79,77,80,82,69,83,83,95,70,73,76,69,61,48,120,50,44,68,69,67,79,77,80,82,69,83,83,95,70,73,76,69,61,48,120,49,44,68,69,67,79,77,80,82,69,83,83,95,79,66,74,69,67,84,61,48,120,52,44,82,69,77,79,86,69,95,70,73,76,69,61,48,120,51,10,99,46,70,68,76,58,70,69,69,68,66,65,67,75,61,48,120,49,10,99,46,70,68,84,58,65,67,67,69,83,83,69,68,61,48,120,50,44,65,82,67,72,73,86,69,68,61,48,120,51,44,67,82,69,65,84,69,68,61,48,120,49,44,77,79,68,73,70,73,69,68,61,48,120,48,10,99,46,70,70,82,58,65,66,79,82,84,61,48,120,50,44,67,79,78,84,73,78,85,69,61,48,120,48,44,79,75,65,89,61,48,120,48,44,83,75,73,80,61,48,120,49,10,99,46,70,76,58,65,80,80,82,79,88,73,77,65,84,69,61,48,120,49,48,44,66,85,70,70,69,82,61,48,120,52,48,44,68,69,86,73,67,69,61,48,120,52,48,48,44,68,73,82,69,67,84,79,82,89,61,48,120,56,44,69,88,67,76,85,68,69,95,70,73,76,69,83,61,48,120,49,48,48,48,44,69,88,67,76,85,68,69,95,70,79,76,68,69,82,83,61,48,120,50,48,48,48,44,70,73,76,69,61,48,120,49,48,48,44,70,79,76,68,69,82,61,48,120,56,44,76,73,78,75,61,48,120,50,48,44,76,79,79,80,61,48,120,56,48,44,78,69,87,61,48,120,50,44,82,69,65,68,61,48,120,52,44,82,69,83,69,84,95,68,65,84,69,61,48,120,50,48,48,44,83,84,82,69,65,77,61,48,120,56,48,48,44,87,82,73,84,69,61,48,120,49,10,99,46,70,79,70,58,83,77,65,82,84,95,78,65,77,69,83,61,48,120,49,10,99,46,73,68,84,89,80,69,58,70,85,78,67,84,73,79,78,61,48,120,51,44,71,76,79,66,65,76,61,48,120,50,44,77,69,83,83,65,71,69,61,48,120,49,10,99,46,74,69,84,58,65,66,83,95,88,89,61,48,120,49,98,44,65,78,65,76,79,71,50,95,88,89,61,48,120,49,54,44,65,78,65,76,79,71,50,95,90,61,48,120,49,55,44,65,78,65,76,79,71,95,88,89,61,48,120,49,52,44,65,78,65,76,79,71,95,90,61,48,120,49,53,44,66,85,84,84,79,78,95,49,61,48,120,50,44,66,85,84,84,79,78,95,49,48,61,48,120,98,44,66,85,84,84,79,78,95,50,61,48,120,51,44,66,85,84,84,79,78,95,51,61,48,120,52,44,66,85,84,84,79,78,95,52,61,48,120,53,44,66,85,84,84,79,78,95,53,61,48,120,54,44,66,85,84,84,79,78,95,54,61,48,120,55,44,66,85,84,84,79,78,95,55,61,48,120,56,44,66,85,84,84,79,78,95,56,61,48,120,57,44,66,85,84,84,79,78,95,57,61,48,120,97,44,66,85,84,84,79,78,95,83,69,76,69,67,84,61,48,120,102,44,66,85,84,84,79,78,95,83,84,65,82,84,61,48,120,101,44,67,82,79,83,83,69,68,95,73,78,61,48,120,49,99,44,67,82,79,83,83,69,68,95,79,85,84,61,48,120,49,100,44,68,69,86,73,67,69,95,84,73,76,84,95,88,89,61,48,120,49,102,44,68,69,86,73,67,69,95,84,73,76,84,95,90,61,48,120,50,48,44,68,73,71,73,84,65,76,95,88,89,61,48,120,49,44,68,73,83,80,76,65,89,95,69,68,71,69,61,48,120,50,49,44,69,78,68,61,48,120,50,50,44,76,69,70,84,95,66,85,77,80,69,82,95,49,61,48,120,49,48,44,76,69,70,84,95,66,85,77,80,69,82,95,50,61,48,120,49,49,44,76,77,66,61,48,120,50,44,77,77,66,61,48,120,52,44,80,69,78,95,84,73,76,84,95,88,89,61,48,120,49,97,44,80,82,69,83,83,85,82,69,61,48,120,49,101,44,82,73,71,72,84,95,66,85,77,80,69,82,95,49,61,48,120,49,50,44,82,73,71,72,84,95,66,85,77,80,69,82,95,50,61,48,120,49,51,44,82,77,66,61,48,120,51,44,84,82,73,71,71,69,82,95,76,69,70,84,61,48,120,99,44,84,82,73,71,71,69,82,95,82,73,71,72,84,61,48,120,100,44,87,72,69,69,76,61,48,120,49,56,44,87,72,69,69,76,95,84,73,76,84,61,48,120,49,57,10,99,46,74,84,89,80,69,58,65,78,65,76,79,71,61,48,120,50,48,44,65,78,67,72,79,82,69,68,61,48,120,50,44,66,85,84,84,79,78,61,48,120,56,48,44,67,82,79,83,83,73,78,71,61,48,120,56,44,68,66,76,95,67,76,73,67,75,61,48,120,50,48,48,44,68,73,71,73,84,65,76,61,48,120,49,48,44,68,82,65,71,71,69,68,61,48,120,52,44,68,82,65,71,95,73,84,69,77,61,48,120,56,48,48,44,69,88,84,95,77,79,86,69,77,69,78,84,61,48,120,52,48,44,77,79,86,69,77,69,78,84,61,48,120,49,48,48,44,82,69,80,69,65,84,69,68,61,48,120,52,48,48,44,83,69,67,79,78,68,65,82,89,61,48,120,49,10,99,46,75,69,89,58,65,61,48,120,49,44,65,80,79,83,84,82,79,80,72,69,61,48,120,50,98,44,65,84,61,48,120,56,97,44,66,61,48,120,50,44,66,65,67,75,61,48,120,56,54,44,66,65,67,75,83,80,65,67,69,61,48,120,54,57,44,66,65,67,75,95,83,76,65,83,72,61,48,120,50,102,44,66,82,69,65,75,61,48,120,55,98,44,67,61,48,120,51,44,67,65,76,76,61,48,120,56,55,44,67,65,77,69,82,65,61,48,120,56,57,44,67,65,78,67,69,76,61,48,120,55,97,44,67,65,80,83,95,76,79,67,75,61,48,120,52,54,44,67,76,69,65,82,61,48,120,54,101,44,67,79,77,77,65,61,48,120,50,99,44,68,61,48,120,52,44,68,69,76,69,84,69,61,48,120,54,100,44,68,79,84,61,48,120,50,100,44,68,79,87,78,61,48,120,54,49,44,69,61,48,120,53,44,69,73,71,72,84,61,48,120,50,50,44,69,78,68,61,48,120,55,50,44,69,78,68,95,67,65,76,76,61,48,120,56,56,44,69,78,84,69,82,61,48,120,54,98,44,69,81,85,65,76,83,61,48,120,50,55,44,69,83,67,65,80,69,61,48,120,54,99,44,69,88,69,67,85,84,69,61,48,120,55,52,44,70,61,48,120,54,44,70,49,61,48,120,52,99,44,70,49,48,61,48,120,53,53,44,70,49,49,61,48,120,53,54,44,70,49,50,61,48,120,53,55,44,70,49,51,61,48,120,53,56,44,70,49,52,61,48,120,53,57,44,70,49,53,61,48,120,53,97,44,70,49,54,61,48,120,53,98,44,70,49,55,61,48,120,53,99,44,70,49,56,61,48,120,56,48,44,70,49,57,61,48,120,56,49,44,70,50,61,48,120,52,100,44,70,50,48,61,48,120,56,50,44,70,51,61,48,120,52,101,44,70,52,61,48,120,52,102,44,70,53,61,48,120,53,48,44,70,54,61,48,120,53,49,44,70,55,61,48,120,53,50,44,70,56,61,48,120,53,51,44,70,57,61,48,120,53,52,44,70,73,78,68,61,48,120,55,57,44,70,73,86,69,61,48,120,49,102,44,70,79,82,87,65,82,68,61,48,120,57,48,44,70,79,85,82,61,48,120,49,101,44,71,61,48,120,55,44,72,61,48,120,56,44,72,69,76,80,61,48,120,52,51,44,72,79,77,69,61,48,120,54,102,44,73,61,48,120,57,44,73,78,83,69,82,84,61,48,120,55,53,44,74,61,48,120,97,44,75,61,48,120,98,44,76,61,48,120,99,44,76,69,70,84,61,48,120,54,51,44,76,69,78,83,95,70,79,67,85,83,61,48,120,56,99,44,76,69,83,83,95,71,82,69,65,84,69,82,61,48,120,53,102,44,76,73,83,84,95,69,78,68,61,48,120,57,54,44,76,95,65,76,84,61,48,120,52,56,44,76,95,67,79,77,77,65,78,68,61,48,120,52,97,44,76,95,67,79,78,84,82,79,76,61,48,120,52,49,44,76,95,83,72,73,70,84,61,48,120,52,52,44,76,95,83,81,85,65,82,69,61,48,120,50,56,44,77,61,48,120,100,44,77,65,67,82,79,61,48,120,53,100,44,77,69,78,85,61,48,120,55,56,44,77,73,78,85,83,61,48,120,50,54,44,77,85,84,69,61,48,120,57,50,44,78,61,48,120,101,44,78,69,88,84,61,48,120,56,101,44,78,73,78,69,61,48,120,50,51,44,78,80,95,48,61,48,120,51,49,44,78,80,95,49,61,48,120,51,50,44,78,80,95,50,61,48,120,51,51,44,78,80,95,51,61,48,120,51,52,44,78,80,95,52,61,48,120,51,53,44,78,80,95,53,61,48,120,51,54,44,78,80,95,54,61,48,120,51,55,44,78,80,95,55,61,48,120,51,56,44,78,80,95,56,61,48,120,51,57,44,78,80,95,57,61,48,120,51,97,44,78,80,95,66,65,82,61,48,120,51,100,44,78,80,95,68,69,67,73,77,65,76,61,48,120,51,102,44,78,80,95,68,73,86,73,68,69,61,48,120,52,48,44,78,80,95,68,79,84,61,48,120,51,102,44,78,80,95,69,78,84,69,82,61,48,120,55,101,44,78,80,95,77,73,78,85,83,61,48,120,51,101,44,78,80,95,77,85,76,84,73,80,76,89,61,48,120,51,98,44,78,80,95,80,76,85,83,61,48,120,51,99,44,78,80,95,80,76,85,83,95,77,73,78,85,83,61,48,120,53,101,44,78,80,95,83,69,80,65,82,65,84,79,82,61,48,120,51,100,44,78,85,77,95,76,79,67,75,61,48,120,55,99,44,79,61,48,120,102,44,79,78,69,61,48,120,49,98,44,80,61,48,120,49,48,44,80,65,71,69,95,68,79,87,78,61,48,120,55,49,44,80,65,71,69,95,85,80,61,48,120,55,48,44,80,65,85,83,69,61,48,120,54,53,44,80,69,82,73,79,68,61,48,120,50,100,44,80,76,65,89,61,48,120,57,53,44,80,76,85,83,61,48,120,56,98,44,80,79,85,78,68,61,48,120,57,52,44,80,79,87,69,82,61,48,120,54,56,44,80,82,69,86,73,79,85,83,61,48,120,56,102,44,80,82,73,78,84,61,48,120,52,55,44,80,82,84,95,83,67,82,61,48,120,55,100,44,81,61,48,120,49,49,44,82,61,48,120,49,50,44,82,69,68,79,61,48,120,55,55,44,82,69,86,69,82,83,69,95,81,85,79,84,69,61,48,120,50,53,44,82,69,87,73,78,68,61,48,120,57,49,44,82,73,71,72,84,61,48,120,54,50,44,82,95,65,76,84,61,48,120,52,57,44,82,95,67,79,77,77,65,78,68,61,48,120,52,98,44,82,95,67,79,78,84,82,79,76,61,48,120,52,50,44,82,95,83,72,73,70,84,61,48,120,52,53,44,82,95,83,81,85,65,82,69,61,48,120,50,57,44,83,61,48,120,49,51,44,83,67,82,95,76,79,67,75,61,48,120,54,52,44,83,69,76,69,67,84,61,48,120,55,51,44,83,69,77,73,95,67,79,76,79,78,61,48,120,50,97,44,83,69,86,69,78,61,48,120,50,49,44,83,73,88,61,48,120,50,48,44,83,76,65,83,72,61,48,120,50,101,44,83,76,69,69,80,61,48,120,54,55,44,83,80,65,67,69,61,48,120,51,48,44,83,84,65,82,61,48,120,57,51,44,83,84,79,80,61,48,120,56,100,44,83,89,83,82,81,61,48,120,55,102,44,84,61,48,120,49,52,44,84,65,66,61,48,120,54,97,44,84,72,82,69,69,61,48,120,49,100,44,84,87,79,61,48,120,49,99,44,85,61,48,120,49,53,44,85,78,68,79,61,48,120,55,54,44,85,80,61,48,120,54,48,44,86,61,48,120,49,54,44,86,79,76,85,77,69,95,68,79,87,78,61,48,120,56,53,44,86,79,76,85,77,69,95,85,80,61,48,120,56,52,44,87,61,48,120,49,55,44,87,65,75,69,61,48,120,54,54,44,87,73,78,95,67,79,78,84,82,79,76,61,48,120,56,51,44,88,61,48,120,49,56,44,89,61,48,120,49,57,44,90,61,48,120,49,97,44,90,69,82,79,61,48,120,50,52,10,99,46,75,81,58,65,76,84,61,48,120,54,48,44,65,76,84,71,82,61,48,120,52,48,44,67,65,80,83,95,76,79,67,75,61,48,120,52,44,67,79,77,77,65,78,68,61,48,120,49,56,48,44,67,79,78,84,82,79,76,61,48,120,49,56,44,67,84,82,76,61,48,120,49,56,44,68,69,65,68,95,75,69,89,61,48,120,49,48,48,48,48,44,73,78,70,79,61,48,120,51,99,48,52,44,73,78,83,84,82,85,67,84,73,79,78,95,75,69,89,83,61,48,120,55,56,44,76,95,65,76,84,61,48,120,50,48,44,76,95,67,79,77,77,65,78,68,61,48,120,56,48,44,76,95,67,79,78,84,82,79,76,61,48,120,56,44,76,95,67,84,82,76,61,48,120,56,44,76,95,83,72,73,70,84,61,48,120,49,44,78,79,84,95,80,82,73,78,84,65,66,76,69,61,48,120,50,48,48,48,44,78,85,77,95,76,79,67,75,61,48,120,56,48,48,48,44,78,85,77,95,80,65,68,61,48,120,50,48,48,44,80,82,69,83,83,69,68,61,48,120,49,48,48,48,44,81,85,65,76,73,70,73,69,82,83,61,48,120,49,102,98,44,82,69,76,69,65,83,69,68,61,48,120,56,48,48,44,82,69,80,69,65,84,61,48,120,52,48,48,44,82,95,65,76,84,61,48,120,52,48,44,82,95,67,79,77,77,65,78,68,61,48,120,49,48,48,44,82,95,67,79,78,84,82,79,76,61,48,120,49,48,44,82,95,67,84,82,76,61,48,120,49,48,44,82,95,83,72,73,70,84,61,48,120,50,44,83,67,82,95,76,79,67,75,61,48,120,52,48,48,48,44,83,72,73,70,84,61,48,120,51,44,87,73,78,95,67,79,78,84,82,79,76,61,48,120,50,48,48,48,48,10,99,46,76,65,89,79,85,84,58,66,65,67,75,71,82,79,85,78,68,61,48,120,56,44,69,77,66,69,68,68,69,68,61,48,120,50,48,44,70,79,82,69,71,82,79,85,78,68,61,48,120,49,48,44,73,71,78,79,82,69,95,67,85,82,83,79,82,61,48,120,56,48,44,76,69,70,84,61,48,120,50,44,76,79,67,75,61,48,120,52,48,44,82,73,71,72,84,61,48,120,52,44,83,81,85,65,82,69,61,48,120,48,44,84,73,71,72,84,61,48,120,49,44,84,73,76,69,61,48,120,49,48,48,44,87,73,68,69,61,48,120,54,10,99,46,76,68,70,58,67,72,69,67,75,95,69,88,73,83,84,83,61,48,120,49,10,99,46,76,79,67,58,68,73,82,69,67,84,79,82,89,61,48,120,49,44,70,73,76,69,61,48,120,51,44,70,79,76,68,69,82,61,48,120,49,44,86,79,76,85,77,69,61,48,120,50,10,99,46,77,65,88,58,70,73,76,69,78,65,77,69,61,48,120,49,48,48,44,78,65,77,69,95,76,69,78,61,48,120,49,102,10,99,46,77,69,77,58,65,85,68,73,79,61,48,120,56,44,67,65,76,76,69,82,61,48,120,56,48,48,48,48,48,44,67,79,68,69,61,48,120,49,48,44,67,79,76,76,69,67,84,61,48,120,49,48,48,48,44,68,65,84,65,61,48,120,48,44,69,88,67,76,85,83,73,86,69,61,48,120,56,48,48,44,72,73,68,68,69,78,61,48,120,49,48,48,48,48,48,44,77,65,78,65,71,69,68,61,48,120,49,44,78,79,95,66,76,79,67,75,61,48,120,50,48,48,48,44,78,79,95,66,76,79,67,75,73,78,71,61,48,120,50,48,48,48,44,78,79,95,67,76,69,65,82,61,48,120,52,48,48,48,48,44,78,79,95,76,79,67,75,61,48,120,52,48,48,44,78,79,95,80,79,79,76,61,48,120,50,48,44,79,66,74,69,67,84,61,48,120,50,48,48,44,82,69,65,68,61,48,120,49,48,48,48,48,44,82,69,65,68,95,87,82,73,84,69,61,48,120,51,48,48,48,48,44,83,84,82,73,78,71,61,48,120,49,48,48,44,84,69,88,84,85,82,69,61,48,120,52,44,84,77,80,95,76,79,67,75,61,48,120,52,48,44,85,78,84,82,65,67,75,69,68,61,48,120,56,48,44,86,73,68,69,79,61,48,120,50,44,87,82,73,84,69,61,48,120,50,48,48,48,48,10,99,46,77,70,70,58,65,84,84,82,73,66,61,48,120,50,48,44,67,76,79,83,69,68,61,48,120,56,48,44,67,82,69,65,84,69,61,48,120,52,44,68,69,69,80,61,48,120,49,48,48,48,44,68,69,76,69,84,69,61,48,120,56,44,70,73,76,69,61,48,120,52,48,48,44,70,79,76,68,69,82,61,48,120,50,48,48,44,77,79,68,73,70,89,61,48,120,50,44,77,79,86,69,68,61,48,120,49,48,44,79,80,69,78,69,68,61,48,120,52,48,44,82,69,65,68,61,48,120,49,44,82,69,78,65,77,69,61,48,120,49,48,44,83,69,76,70,61,48,120,56,48,48,44,85,78,77,79,85,78,84,61,48,120,49,48,48,44,87,82,73,84,69,61,48,120,50,10,99,46,77,72,70,58,68,69,70,65,85,76,84,61,48,120,50,44,83,84,65,84,73,67,61,48,120,49,44,83,84,82,85,67,84,85,82,69,61,48,120,50,10,99,46,77,79,70,58,76,73,78,75,95,76,73,66,82,65,82,89,61,48,120,49,44,83,84,65,84,73,67,61,48,120,50,44,83,89,83,84,69,77,95,80,82,79,66,69,61,48,120,52,10,99,46,77,79,86,69,58,65,76,76,61,48,120,102,44,68,79,87,78,61,48,120,49,44,76,69,70,84,61,48,120,52,44,82,73,71,72,84,61,48,120,56,44,85,80,61,48,120,50,10,99,46,77,83,70,58,65,68,68,61,48,120,56,44,65,68,68,82,69,83,83,61,48,120,49,48,44,77,69,83,83,65,71,69,95,73,68,61,48,120,50,48,44,78,79,95,68,85,80,76,73,67,65,84,69,61,48,120,52,44,85,80,68,65,84,69,61,48,120,50,44,87,65,73,84,61,48,120,49,10,99,46,77,83,71,73,68,58,65,67,84,73,79,78,61,48,120,54,51,44,66,82,69,65,75,61,48,120,54,52,44,67,79,77,77,65,78,68,61,48,120,54,53,44,67,79,82,69,95,69,78,68,61,48,120,54,52,44,68,69,66,85,71,61,48,120,53,102,44,69,86,69,78,84,61,48,120,53,101,44,70,82,69,69,61,48,120,54,50,44,81,85,73,84,61,48,120,51,101,56,44,84,72,82,69,65,68,95,65,67,84,73,79,78,61,48,120,53,98,44,84,72,82,69,65,68,95,67,65,76,76,66,65,67,75,61,48,120,53,99,44,86,65,76,73,68,65,84,69,95,80,82,79,67,69,83,83,61,48,120,53,100,44,87,65,73,84,95,70,79,82,95,79,66,74,69,67,84,83,61,48,120,53,97,10,99,46,77,84,70,58,65,78,73,77,61,48,120,56,44,82,69,76,65,84,73,86,69,61,48,120,49,48,44,88,61,48,120,49,44,89,61,48,120,50,44,90,61,48,120,52,10,99,46,78,69,84,77,83,71,58,69,78,68,61,48,120,49,44,83,84,65,82,84,61,48,120,48,10,99,46,78,70,58,67,79,76,76,69,67,84,61,48,120,56,48,44,70,82,69,69,61,48,120,49,48,44,70,82,69,69,95,79,78,95,85,78,76,79,67,75,61,48,120,56,44,73,78,73,84,73,65,76,73,83,69,68,61,48,120,50,44,76,79,67,65,76,61,48,120,52,44,77,69,83,83,65,71,69,61,48,120,50,48,48,44,78,65,77,69,61,48,120,56,48,48,48,48,48,48,48,44,80,82,73,86,65,84,69,61,48,120,48,44,82,69,67,76,65,83,83,69,68,61,48,120,49,48,48,44,83,73,71,78,65,76,76,69,68,61,48,120,52,48,48,44,83,85,80,80,82,69,83,83,95,76,79,71,61,48,120,52,48,44,84,73,77,69,82,95,83,85,66,61,48,120,50,48,44,85,78,73,81,85,69,61,48,120,52,48,48,48,48,48,48,48,44,85,78,84,82,65,67,75,69,68,61,48,120,49,10,99,46,79,80,70,58,65,82,71,83,61,48,120,52,48,44,68,69,84,65,73,76,61,48,120,52,44,69,82,82,79,82,61,48,120,56,48,44,77,65,88,95,68,69,80,84,72,61,48,120,50,44,77,79,68,85,76,69,95,80,65,84,72,61,48,120,52,48,48,44,79,80,84,73,79,78,83,61,48,120,49,44,80,82,73,86,73,76,69,71,69,68,61,48,120,49,48,48,44,82,79,79,84,95,80,65,84,72,61,48,120,56,48,48,44,83,67,65,78,95,77,79,68,85,76,69,83,61,48,120,49,48,48,48,44,83,72,79,87,95,69,82,82,79,82,83,61,48,120,50,48,44,83,72,79,87,95,73,79,61,48,120,49,48,44,83,72,79,87,95,77,69,77,79,82,89,61,48,120,56,44,83,89,83,84,69,77,95,80,65,84,72,61,48,120,50,48,48,10,99,46,80,69,82,77,73,84,58,65,76,76,95,68,69,76,69,84,69,61,48,120,56,56,56,44,65,76,76,95,69,88,69,67,61,48,120,52,52,52,44,65,76,76,95,82,69,65,68,61,48,120,49,49,49,44,65,76,76,95,87,82,73,84,69,61,48,120,50,50,50,44,65,82,67,72,73,86,69,61,48,120,50,48,48,48,44,68,69,76,69,84,69,61,48,120,56,44,69,86,69,82,89,79,78,69,95,65,67,67,69,83,83,61,48,120,102,102,102,44,69,86,69,82,89,79,78,69,95,68,69,76,69,84,69,61,48,120,56,56,56,44,69,86,69,82,89,79,78,69,95,69,88,69,67,61,48,120,52,52,52,44,69,86,69,82,89,79,78,69,95,82,69,65,68,61,48,120,49,49,49,44,69,86,69,82,89,79,78,69,95,82,69,65,68,87,82,73,84,69,61,48,120,51,51,51,44,69,86,69,82,89,79,78,69,95,87,82,73,84,69,61,48,120,50,50,50,44,69,88,69,67,61,48,120,52,44,71,82,79,85,80,61,48,120,102,48,44,71,82,79,85,80,73,68,61,48,120,49,48,48,48,48,44,71,82,79,85,80,95,68,69,76,69,84,69,61,48,120,56,48,44,71,82,79,85,80,95,69,88,69,67,61,48,120,52,48,44,71,82,79,85,80,95,82,69,65,68,61,48,120,49,48,44,71,82,79,85,80,95,87,82,73,84,69,61,48,120,50,48,44,72,73,68,68,69,78,61,48,120,49,48,48,48,44,73,78,72,69,82,73,84,61,48,120,50,48,48,48,48,44,78,69,84,87,79,82,75,61,48,120,56,48,48,48,48,44,79,70,70,76,73,78,69,61,48,120,52,48,48,48,48,44,79,84,72,69,82,83,61,48,120,102,48,48,44,79,84,72,69,82,83,95,68,69,76,69,84,69,61,48,120,56,48,48,44,79,84,72,69,82,83,95,69,88,69,67,61,48,120,52,48,48,44,79,84,72,69,82,83,95,82,69,65,68,61,48,120,49,48,48,44,79,84,72,69,82,83,95,87,82,73,84,69,61,48,120,50,48,48,44,80,65,83,83,87,79,82,68,61,48,120,52,48,48,48,44,82,69,65,68,61,48,120,49,44,85,83,69,82,61,48,120,102,44,85,83,69,82,73,68,61,48,120,56,48,48,48,44,85,83,69,82,95,69,88,69,67,61,48,120,52,44,85,83,69,82,95,82,69,65,68,61,48,120,49,44,85,83,69,82,95,87,82,73,84,69,61,48,120,50,44,87,82,73,84,69,61,48,120,50,10,99,46,80,77,70,58,83,89,83,84,69,77,95,78,79,95,66,82,69,65,75,61,48,120,49,10,99,46,80,84,67,58,67,82,79,83,83,72,65,73,82,61,48,120,97,44,67,85,83,84,79,77,61,48,120,49,55,44,68,69,70,65,85,76,84,61,48,120,49,44,68,82,65,71,71,65,66,76,69,61,48,120,49,56,44,69,78,68,61,48,120,49,57,44,72,65,78,68,61,48,120,49,48,44,72,65,78,68,95,76,69,70,84,61,48,120,49,49,44,72,65,78,68,95,82,73,71,72,84,61,48,120,49,50,44,73,78,86,73,83,73,66,76,69,61,48,120,49,54,44,77,65,71,78,73,70,73,69,82,61,48,120,102,44,78,79,95,67,72,65,78,71,69,61,48,120,48,44,80,65,73,78,84,66,82,85,83,72,61,48,120,49,52,44,83,73,90,69,95,66,79,84,84,79,77,61,48,120,57,44,83,73,90,69,95,66,79,84,84,79,77,95,76,69,70,84,61,48,120,50,44,83,73,90,69,95,66,79,84,84,79,77,95,82,73,71,72,84,61,48,120,51,44,83,73,90,69,95,76,69,70,84,61,48,120,54,44,83,73,90,69,95,82,73,71,72,84,61,48,120,55,44,83,73,90,69,95,84,79,80,61,48,120,56,44,83,73,90,69,95,84,79,80,95,76,69,70,84,61,48,120,52,44,83,73,90,69,95,84,79,80,95,82,73,71,72,84,61,48,120,53,44,83,73,90,73,78,71,61,48,120,99,44,83,76,69,69,80,61,48,120,98,44,83,80,76,73,84,95,72,79,82,73,90,79,78,84,65,76,61,48,120,101,44,83,80,76,73,84,95,86,69,82,84,73,67,65,76,61,48,120,100,44,83,84,79,80,61,48,120,49,53,44,84,69,88,84,61,48,120,49,51,10,99,46,82,68,70,58,65,82,67,72,73,86,69,61,48,120,50,48,48,48,44,68,65,84,69,61,48,120,50,44,70,73,76,69,61,48,120,56,44,70,73,76,69,83,61,48,120,56,44,70,79,76,68,69,82,61,48,120,49,48,44,70,79,76,68,69,82,83,61,48,120,49,48,44,72,73,68,68,69,78,61,48,120,49,48,48,44,76,73,78,75,61,48,120,52,48,44,79,80,69,78,68,73,82,61,48,120,52,48,48,48,44,80,69,82,77,73,83,83,73,79,78,83,61,48,120,52,44,81,85,65,76,73,70,73,69,68,61,48,120,50,48,48,44,81,85,65,76,73,70,89,61,48,120,50,48,48,44,82,69,65,68,95,65,76,76,61,48,120,49,102,44,82,69,65,68,95,79,78,76,89,61,48,120,49,48,48,48,44,83,73,90,69,61,48,120,49,44,83,84,82,69,65,77,61,48,120,56,48,48,44,84,65,71,83,61,48,120,56,48,44,84,73,77,69,61,48,120,50,44,86,73,82,84,85,65,76,61,48,120,52,48,48,44,86,79,76,85,77,69,61,48,120,50,48,10,99,46,82,69,83,58,67,79,78,83,79,76,69,95,70,68,61,48,120,50,44,67,79,82,69,95,73,68,76,61,48,120,56,44,67,80,85,95,83,80,69,69,68,61,48,120,49,54,44,68,73,83,80,76,65,89,95,68,82,73,86,69,82,61,48,120,53,44,69,88,67,69,80,84,73,79,78,95,72,65,78,68,76,69,82,61,48,120,49,49,44,70,82,69,69,95,77,69,77,79,82,89,61,48,120,49,55,44,70,82,69,69,95,83,87,65,80,61,48,120,49,44,74,78,73,95,69,78,86,61,48,120,101,44,75,69,89,95,83,84,65,84,69,61,48,120,51,44,76,79,71,95,68,69,80,84,72,61,48,120,100,44,76,79,71,95,76,69,86,69,76,61,48,120,97,44,77,65,88,95,80,82,79,67,69,83,83,69,83,61,48,120,99,44,78,69,84,95,80,82,79,67,69,83,83,73,78,71,61,48,120,49,50,44,79,80,69,78,95,73,78,70,79,61,48,120,49,48,44,80,82,73,86,73,76,69,71,69,68,61,48,120,55,44,80,82,73,86,73,76,69,71,69,68,95,85,83,69,82,61,48,120,54,44,80,82,79,67,69,83,83,95,83,84,65,84,69,61,48,120,49,51,44,83,84,65,84,73,67,95,66,85,73,76,68,61,48,120,57,44,84,72,82,69,65,68,95,73,68,61,48,120,102,44,84,79,84,65,76,95,77,69,77,79,82,89,61,48,120,49,52,44,84,79,84,65,76,95,83,72,65,82,69,68,95,77,69,77,79,82,89,61,48,120,98,44,84,79,84,65,76,95,83,87,65,80,61,48,120,49,53,44,85,83,69,82,95,73,68,61,48,120,52,10,99,46,82,70,68,58,65,76,76,79,87,95,82,69,67,85,82,83,73,79,78,61,48,120,50,48,44,65,76,87,65,89,83,95,67,65,76,76,61,48,120,49,48,48,44,69,88,67,69,80,84,61,48,120,50,44,82,69,65,68,61,48,120,52,44,82,69,67,65,76,76,61,48,120,56,48,44,82,69,77,79,86,69,61,48,120,56,44,83,79,67,75,69,84,61,48,120,52,48,44,83,84,79,80,95,82,69,67,85,82,83,69,61,48,120,49,48,44,87,82,73,84,69,61,48,120,49,10,99,46,82,80,58,77,79,68,85,76,69,95,80,65,84,72,61,48,120,49,44,82,79,79,84,95,80,65,84,72,61,48,120,51,44,83,89,83,84,69,77,95,80,65,84,72,61,48,120,50,10,99,46,82,83,70,58,65,80,80,82,79,88,73,77,65,84,69,61,48,120,52,44,67,65,83,69,95,83,69,78,83,73,84,73,86,69,61,48,120,50,48,44,67,72,69,67,75,95,86,73,82,84,85,65,76,61,48,120,50,44,78,79,95,68,69,69,80,95,83,67,65,78,61,48,120,56,44,78,79,95,70,73,76,69,95,67,72,69,67,75,61,48,120,49,44,80,65,84,72,61,48,120,49,48,10,99,46,83,67,70,58,69,88,73,84,95,79,78,95,69,82,82,79,82,61,48,120,49,44,76,79,71,95,65,76,76,61,48,120,50,10,99,46,83,69,69,75,58,67,85,82,82,69,78,84,61,48,120,49,44,69,78,68,61,48,120,50,44,82,69,76,65,84,73,86,69,61,48,120,51,44,83,84,65,82,84,61,48,120,48,10,99,46,83,84,82,58,67,65,83,69,61,48,120,49,44,77,65,84,67,72,95,67,65,83,69,61,48,120,49,44,77,65,84,67,72,95,76,69,78,61,48,120,50,10,99,46,83,84,84,58,70,76,79,65,84,61,48,120,50,44,72,69,88,61,48,120,51,44,78,85,77,66,69,82,61,48,120,49,44,83,84,82,73,78,71,61,48,120,52,10,99,46,84,72,70,58,65,85,84,79,95,70,82,69,69,61,48,120,49,10,99,46,84,79,73,58,65,78,68,82,79,73,68,95,65,83,83,69,84,77,71,82,61,48,120,52,44,65,78,68,82,79,73,68,95,67,76,65,83,83,61,48,120,51,44,65,78,68,82,79,73,68,95,69,78,86,61,48,120,50,44,76,79,67,65,76,95,67,65,67,72,69,61,48,120,48,44,76,79,67,65,76,95,83,84,79,82,65,71,69,61,48,120,49,10,99,46,84,83,70,58,65,84,84,65,67,72,69,68,61,48,120,49,48,48,44,68,69,84,65,67,72,69,68,61,48,120,56,48,44,70,79,82,69,73,71,78,61,48,120,49,44,76,79,71,95,65,76,76,61,48,120,50,48,44,80,73,80,69,61,48,120,50,48,48,44,80,82,73,86,73,76,69,71,69,68,61,48,120,56,44,81,85,73,69,84,61,48,120,52,48,44,82,69,83,69,84,95,80,65,84,72,61,48,120,52,44,83,72,69,76,76,61,48,120,49,48,44,87,65,73,84,61,48,120,50,10,99,46,84,83,84,65,84,69,58,80,65,85,83,69,68,61,48,120,49,44,82,85,78,78,73,78,71,61,48,120,48,44,83,84,79,80,80,73,78,71,61,48,120,50,44,84,69,82,77,73,78,65,84,69,68,61,48,120,51,10,99,46,86,65,83,58,67,65,83,69,95,83,69,78,83,73,84,73,86,69,61,48,120,102,44,67,76,79,83,69,95,68,73,82,61,48,120,54,44,67,82,69,65,84,69,95,76,73,78,75,61,48,120,49,49,44,68,69,76,69,84,69,61,48,120,51,44,68,69,82,69,71,73,83,84,69,82,61,48,120,49,44,68,82,73,86,69,82,95,83,73,90,69,61,48,120,49,50,44,71,69,84,95,68,69,86,73,67,69,95,73,78,70,79,61,48,120,98,44,71,69,84,95,73,78,70,79,61,48,120,97,44,73,68,69,78,84,73,70,89,95,70,73,76,69,61,48,120,99,44,73,71,78,79,82,69,95,70,73,76,69,61,48,120,57,44,77,65,75,69,95,68,73,82,61,48,120,100,44,79,80,69,78,95,68,73,82,61,48,120,53,44,82,69,65,68,95,76,73,78,75,61,48,120,49,48,44,82,69,78,65,77,69,61,48,120,52,44,83,65,77,69,95,70,73,76,69,61,48,120,101,44,83,67,65,78,95,68,73,82,61,48,120,50,44,84,69,83,84,95,80,65,84,72,61,48,120,55,44,87,65,84,67,72,95,80,65,84,72,61,48,120,56,10,99,46,86,76,70,58,65,80,73,61,48,120,50,48,44,66,82,65,78,67,72,61,48,120,49,44,67,82,73,84,73,67,65,76,61,48,120,56,44,68,69,84,65,73,76,61,48,120,52,48,44,69,82,82,79,82,61,48,120,50,44,70,85,78,67,84,73,79,78,61,48,120,49,48,48,44,73,78,70,79,61,48,120,49,48,44,84,82,65,67,69,61,48,120,56,48,44,87,65,82,78,73,78,71,61,48,120,52,10,99,46,86,79,76,85,77,69,58,72,73,68,68,69,78,61,48,120,52,44,80,82,73,79,82,73,84,89,61,48,120,50,44,82,69,80,76,65,67,69,61,48,120,49,44,83,89,83,84,69,77,61,48,120,56,10,0 }; diff --git a/src/core/lib_filesystem.cpp b/src/core/lib_filesystem.cpp index 1604dba67..b8e269681 100644 --- a/src/core/lib_filesystem.cpp +++ b/src/core/lib_filesystem.cpp @@ -1112,8 +1112,8 @@ ERR ReadFileToBuffer(CSTRING Path, APTR Buffer, LONG BufferSize, LONG *BytesRead -FUNCTION- ReadInfoTag: Read a named tag from a !FileInfo structure. -Call ReadInfoTag() to retrieve the string value associated with a named tag in a !FileInfo structure. The tag must -have been added with ~AddInfoTag() or `ERR::NotFound` will be returned. +ReadInfoTag() will read the value of a named tag in a !FileInfo structure. The tag must have been added with +~AddInfoTag() or `ERR::NotFound` will be returned. -INPUT- struct(FileInfo) Info: Pointer to a valid !FileInfo structure. @@ -2495,7 +2495,7 @@ ERR fs_getdeviceinfo(std::string_view Path, objStorageDevice *Info) if (glVolumes[vol].contains("Device")) { auto &device = glVolumes[vol]["Device"]; if (!device.compare("disk")) Info->DeviceFlags |= DEVICE::FLOPPY_DISK|DEVICE::REMOVABLE|DEVICE::READ|DEVICE::WRITE; - else if (!device.compare("fixed")) Info->DeviceFlags |= DEVICE::HARD_DISK|DEVICE::READ|DEVICE::WRITE; + else if (!device.compare("fixed")) Info->DeviceFlags |= DEVICE::HARD_DISK|DEVICE::READ|DEVICE::WRITE; else if (!device.compare("hd")) Info->DeviceFlags |= DEVICE::HARD_DISK|DEVICE::READ|DEVICE::WRITE; else if (!device.compare("cd")) Info->DeviceFlags |= DEVICE::COMPACT_DISC|DEVICE::REMOVABLE|DEVICE::READ; else if (!device.compare("usb")) Info->DeviceFlags |= DEVICE::USB|DEVICE::REMOVABLE; @@ -2509,12 +2509,12 @@ ERR fs_getdeviceinfo(std::string_view Path, objStorageDevice *Info) if (Info->DeviceFlags IS DEVICE::NIL) { // Unable to find a device reference for the volume, so try to resolve the path and try again. + Info->DeviceFlags |= DEVICE::BOOKMARK; if (!resolve.empty()) { // We've done what we can - drop through #ifdef _WIN32 // On win32 we can get the drive information from the drive letter // TODO: Write Win32 code to discover the drive type in GetDeviceInfo(). #endif - location.assign(resolve); } else { @@ -2539,7 +2539,7 @@ ERR fs_getdeviceinfo(std::string_view Path, objStorageDevice *Info) if (error IS ERR::Okay) { if (!(winGetFreeDiskSpace(location[0], &bytes_avail, &total_size))) { - log.msg("Failed to read location \"%s\" (from \"%s\")", location.c_str(), Path.data()); + log.msg("Failed to read disk space for \"%s\" (%s)", location.c_str(), Path.data()); Info->BytesFree = -1; Info->BytesUsed = 0; Info->DeviceSize = -1; diff --git a/src/core/microsoft/windows.cpp b/src/core/microsoft/windows.cpp index 935dc4157..86fb6c855 100644 --- a/src/core/microsoft/windows.cpp +++ b/src/core/microsoft/windows.cpp @@ -1268,7 +1268,7 @@ extern "C" void winEnumSpecialFolders(void (*enumfolder)(const char *, const cha //{ CSIDL_PRINTERS, "printers:", "Printers", "devices/printer" }, //{ CSIDL_DRIVES, "computer:", "My Computer", "programs/filemanager" } { CSIDL_NETHOOD, "network:", "Network Places", "devices/network", 0 }, - { CSIDL_PERSONAL, "documents:", "Documents", "office/documents", 0 }, + { CSIDL_PERSONAL, "documents:", "Documents", "page/multiple", 0 }, { CSIDL_DESKTOPDIRECTORY, "desktop:", "Desktop", "devices/harddisk", 0 } }; char path[MAX_PATH]; @@ -1400,16 +1400,16 @@ extern "C" ERR winCreateDir(const char *Path) //******************************************************************************************************************** // Returns TRUE on success. -extern "C" LONG winGetFreeDiskSpace(unsigned char Drive, long long *TotalSpace, long long *BytesUsed) +extern "C" LONG winGetFreeDiskSpace(char Drive, long long *TotalSpace, long long *BytesUsed) { DWORD sectors, bytes_per_sector, free_clusters, total_clusters; *TotalSpace = 0; *BytesUsed = 0; - std::string location = std::to_string(Drive) + ":\\"; + char location[4] = { Drive, ':', '\\', 0 }; - if (GetDiskFreeSpace(location.c_str(), §ors, &bytes_per_sector, &free_clusters, &total_clusters)) { + if (GetDiskFreeSpace(location, §ors, &bytes_per_sector, &free_clusters, &total_clusters)) { *TotalSpace = (double)sectors * (double)bytes_per_sector * (double)free_clusters; *BytesUsed = ((double)sectors * (double)bytes_per_sector * (double)total_clusters); return 1; diff --git a/src/vector/scene/scene.cpp b/src/vector/scene/scene.cpp index c42261428..a84b3f7c6 100644 --- a/src/vector/scene/scene.cpp +++ b/src/vector/scene/scene.cpp @@ -12,7 +12,7 @@ The VectorScene class acts as a container and control point for the management o purpose is to draw the scene to a target @Bitmap or @Surface provided by the client. Vector scenes are created by initialising multiple Vector objects such as @VectorPath and @VectorViewport and -positioning them within a vector tree. The VectorScene must lie at the root. +positioning them within a vector tree. The VectorScene must lie at the root of the tree. The default mode of operation is for scenes to be manually drawn, for which the client must set the target #Bitmap and call the #Draw() action as required. Automated drawing can be enabled by setting the target #Surface prior diff --git a/src/vector/scene/scene_input.cpp b/src/vector/scene/scene_input.cpp index 334d63d01..73ce3fef1 100644 --- a/src/vector/scene/scene_input.cpp +++ b/src/vector/scene/scene_input.cpp @@ -187,7 +187,7 @@ ERR scene_input_events(const InputEvent *Events, LONG Handle) } } - if (input->OverID != Self->SurfaceID) { + if ((input->OverID != Self->SurfaceID) and ((input->Flags & JTYPE::CROSSING) IS JTYPE::NIL)) { // Activity occurring on another surface may be reported to us in circumstances where our surface is modal. continue; } diff --git a/src/vector/vectors/vector.cpp b/src/vector/vectors/vector.cpp index f20445a38..579535b3a 100644 --- a/src/vector/vectors/vector.cpp +++ b/src/vector/vectors/vector.cpp @@ -901,6 +901,8 @@ static ERR VECTOR_SubscribeInput(extVector *Self, struct vec::SubscribeInput *Ar { pf::Log log; + // Refer to scene_input_events() for the origin of incoming input messages + if ((!Args) or (!Args->Callback)) return log.warning(ERR::NullArgs); if (Args->Mask != JTYPE::NIL) {