makepad/widgets/themes/windows-2000/widgets.splash
Admin 75a6a9e613 widgets (button): a style sheet's own button face shows the colour the app paints on it -- apps light a latch (the page they are on, a mute that is down) by setting draw_bg.color, and a sheet that replaces the Button pixel with a face of its own drew its own colour whatever was painted, so under those sheets an ON latch could not be told from an OFF one. The button draw gains color_default (each variant's own resting fill; Flatter, GradientX, Primary, Secondary, Tertiary, Outline and Danger state theirs) and three helpers for sheets: host_face moves a face colour by how far the host moved color from color_default (the sheet's bevels, gloss and grain stay), host_over does that to a finished premultiplied face inside the button's rect (m = the room the sheet grew its quad by), laying the host's colour under a face that lets the ground through (glass, a frame-only face) as far as the host moved it, and host_alpha lets a face the host keeps transparent go transparent. At the default every helper returns the sheet's face unchanged; the stock pixel does not call them, so the base themes draw as before. Windows 2000 and NeXTSTEP fill their bevelled face with host_face (what Stage laid over them from its palette until now). New sheet check button_faces_take_the_host_colour: every Button* face a sheet replaces reads the host's colour (host_over, host_face or face_fill); the library's sheets are held to it, and the README says so. Checked: cargo test --release -p makepad-widgets-core (683), -p makepad-widgets; hidden, muted Stage under Windows 2000 and NeXTSTEP: the lit page tab, mute and VJ category show lit.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 17:14:37 +02:00

162 lines
7 KiB
Text

use mod.prelude.widgets_internal.*
mod.widgets.Button.padding = mod.turtle.Inset{left: 8.0 right: 8.0 top: 4.0 bottom: 4.0}
mod.widgets.Button.draw_bg.border_radius = 0.0
mod.widgets.Button.draw_bg.border_size = 2.0
mod.widgets.Button.draw_bg.color_2 = #d4d0c8
// A ROW OF FIELDS IS ONE HEIGHT. Left to themselves the library's fields each
// come out at a size of their own -- in the widget catalogue's toolbar the
// search box, the number beside it and the drop down after it stood at three
// different heights -- and a sheet that reshapes the text box alone widens
// that gap instead of closing it. So the box metrics are stated ONCE here and
// handed to each field below, and a field added to the library later joins
// the row by being named here rather than by having these numbers copied
// into it.
let field_height = 24.0
let field_pad_v = mod.theme.mspace_1.top
let field_radius = 0.0
let field_border = mod.theme.beveling
// The room a Fit field takes. A minimum height rather than a height,
// because a line of text is shorter than a row, and the padding with it:
// where a field is Fit, the padding IS its height, and two fields padded
// differently part company again the moment the type grows.
let field_room = fn(w) {
w.min_height = field_height
w.padding.top = field_pad_v
w.padding.bottom = field_pad_v
}
// The box a field draws. Given the draw object and not the widget, because
// not every field draws its own box, and because writing a corner onto a
// draw struct that has no corner would add a slot its shader never reads.
let field_face = fn(d) {
d.border_radius = field_radius
d.border_size = field_border
}
// A field that states a frame and lays its own parts out inside it: a number
// with a stepper, a date, a time. The height is all these take. A padding
// here would NOT hold the line off the box -- each of them measures its
// parts against the turtle's whole rect and draws them from the content
// origin, so the padding displaces the line instead of insetting it, and the
// number came out sitting on the bottom edge with its arrows split around it.
let field_frame = fn(w) {
w.min_height = field_height
}
field_room(mod.widgets.TextInput)
field_face(mod.widgets.TextInput.draw_bg)
field_room(mod.widgets.ComboBox)
field_face(mod.widgets.ComboBox.draw_bg)
field_room(mod.widgets.DropDown)
field_face(mod.widgets.DropDown.draw_bg)
field_room(mod.widgets.DropDown2)
field_face(mod.widgets.DropDown2.draw_bg)
field_room(mod.widgets.FieldWell)
field_face(mod.widgets.FieldWell.draw_bg)
field_room(mod.widgets.TagField)
field_face(mod.widgets.TagField.draw_bg)
field_frame(mod.widgets.NumberField)
// The number's box strokes its own hairline and declares no border size.
mod.widgets.NumberField.draw_bg.border_radius = field_radius
// The drag-number's corner is written into its own shader, so it takes the
// room and keeps the box it draws.
field_frame(mod.widgets.ValueInput)
field_frame(mod.widgets.DateField)
field_frame(mod.widgets.TimeField)
// A picker is a date field in an anchor: the field inside fills the frame.
field_frame(mod.widgets.DatePicker)
field_frame(mod.widgets.DateRangePicker)
// The chrome-less input a well holds must impose no height of its own. It is
// a TextInput, so it inherits the minimum above, and a minimum as tall as the
// whole field, applied inside a well already that tall, pushed the line out
// through the bottom of the box.
mod.widgets.WellInput.min_height = 0.0
mod.widgets.Window.pass.clear_color = #d4d0c8
// Raised gray command buttons, with a depressed face while held.
mod.widgets.Button.draw_bg.pixel = fn() {
let p=self.pos*self.rect_size
let size=self.rect_size
let sunken=self.down>0.5
// The host's colour (a lit latch) fills the face inside the bevel.
let own=#d4d0c8
let fill=vec4(self.host_face(own.xyz),1.0)
let tl=min(p.x,p.y)
let br=min(size.x-p.x,size.y-p.y)
let d=min(tl,br)
let upper=tl<br
let raised_light=if d<1.0 {#ffffff}else{fill}
let raised_dark=if d<1.0 {#404040}else{#808080}
let light=if sunken {#ffffff}else{raised_light}
let dark=if sunken {if d<1.0 {#808080}else{#404040}}else{raised_dark}
let edge=if upper {if sunken {dark}else{light}}else{if sunken {light}else{dark}}
let color=if d<2.0 {edge}else{fill}
let focus_p=p-vec2(4.0)
let focus_q=size-p-vec2(4.0)
let fd=min(min(focus_p.x,focus_p.y),min(focus_q.x,focus_q.y))
let dot=fract((floor(p.x)+floor(p.y))*0.5)<0.5
let face=if self.focus>0.5 && fd>=0.0 && fd<1.0 && dot {#000000}else{color}
// The wait spinner is drawn by the face, so a style that replaces the
// face wholesale drops it and a button left waiting looks idle. The
// hover and disabled mixes are deliberately NOT restored: neither style
// lit a button under the pointer, and the label carries the disabled
// state on its own, from draw_text, which no style replaces.
if self.loading>0.0 {
let sdf=Sdf2d.viewport(p)
sdf.clear(face)
let c=size*0.5
let r=max(min(size.x,size.y)*0.5-self.loading_inset,1.0)
let a0=self.anim_time*2.0*PI
sdf.arc_round_caps(c.x,c.y,r,a0,a0+1.5*PI,self.loading_stroke)
sdf.fill(vec4(self.loading_color.rgb,self.loading_color.a*self.loading))
return sdf.result
}
return face*self.host_alpha()
}
// Sunken white edit fields, independent of the light theme's gradient material.
mod.widgets.TextInput.draw_bg.pixel = fn() {
let p=self.pos*self.rect_size
let size=self.rect_size
let sunken=true
let fill=if self.disabled>0.5 {#d4d0c8}else{#ffffff}
let tl=min(p.x,p.y)
let br=min(size.x-p.x,size.y-p.y)
let d=min(tl,br)
let upper=tl<br
let raised_light=if d<1.0 {#ffffff}else{#d4d0c8}
let raised_dark=if d<1.0 {#404040}else{#808080}
let light=if sunken {#ffffff}else{raised_light}
let dark=if sunken {if d<1.0 {#808080}else{#404040}}else{raised_dark}
let edge=if upper {if sunken {dark}else{light}}else{if sunken {light}else{dark}}
let color=if d<2.0 {edge}else{fill}
return color
}
// A white combo field and a separate raised arrow button.
mod.widgets.DropDown.draw_bg.pixel = fn() {
let p=self.pos*self.rect_size
let size=self.rect_size
let tl=min(p.x,p.y)
let br=min(size.x-p.x,size.y-p.y)
let edge=if tl<br {if tl<1.0 {#808080}else{#404040}}else{#ffffff}
let field=if min(tl,br)<2.0 {edge}else{if self.disabled>0.5 {#d4d0c8}else{#ffffff}}
let q=p-vec2(size.x-18.0,2.0)
let bs=vec2(16.0,size.y-4.0)
if q.x>=0.0 && q.y>=0.0 && q.x<bs.x && q.y<bs.y {
let a=min(q.x,q.y)
let b=min(bs.x-q.x,bs.y-q.y)
let pressed=self.down>0.5 || self.active>0.5
let face=if min(a,b)<1.0 {if (a<b)!=pressed {#ffffff}else{#808080}}else{#d4d0c8}
let ay=q.y-(bs.y*0.5-1.0)
let arrow=ay>=0.0 && ay<=3.0 && abs(q.x-bs.x*0.5)<=3.0-ay
return if arrow {if self.disabled>0.5 {#808080}else{#000000}}else{face}
}
return field
}
// Square two-line panel frames; the app keeps the same resident widgets.
mod.widgets.PanelView.draw_bg.bevel = 1.0
mod.widgets.PanelView.draw_bg.border_radius = 0.0
true