diff --git a/src/Button.re b/src/Button.re deleted file mode 100644 index d27a4dc..0000000 --- a/src/Button.re +++ /dev/null @@ -1,173 +0,0 @@ - -open SharedTypes; - - -type buttons('a) = list((string, 'a)); -type size = Huge | Normal | Small; - -let height = size => switch size { -| Huge => 80 -| Normal => 50 -| Small => 30 -}; - -let normalButtons = buttons => (Normal, buttons); -let smallButtons = buttons => (Normal, buttons); - -let margin = size => switch size { -| Huge => 20 -| Normal => 10 -| Small => 5 -}; - -let whichFont = (ctx) => fun -| Huge => ctx.titleFont -| Normal => ctx.textFont -| Small => ctx.smallFont ; - -let getWidth = (env, font, text) => switch (font^) { -| None => 0 -| Some(font) => Reprocessing_Font.Font.calcStringWidth(env, font, text) -}; - -let maxWidth = (env, font, buttons) => List.fold_left((a, (text, _)) => max(a, getWidth(env, font, text)), 0, buttons); - -let color = Reprocessing.Utils.color(~r=50, ~g=50 ,~b=50, ~a=255); -let disabledColor = Reprocessing.Utils.color(~r=20, ~g=20 ,~b=20, ~a=255); - -let drawInner = (~enabled, (x, y), width, (size, buttons), ~ctx, ~env) => { - let margin = margin(size); - let buttonHeight = height(size); - - - open Reprocessing; - List.iteri((i, (text, action)) => { - let enabled = enabled(i, action); - let y = y + i * (buttonHeight + margin); - - Draw.fill( - enabled ? color : disabledColor - , env); - Draw.noStroke(env); - - if (enabled && MyUtils.rectCollide(Env.mouse(env), ((x,y), (width, buttonHeight)))) { - Draw.strokeWeight(2, env); - Draw.stroke(Utils.color(~r=100, ~g=100, ~b=100, ~a=255), env); - }; - - Draw.rect(~pos=(x, y), ~width, ~height=buttonHeight, env); - DrawUtils.centerText(~font=ctx.textFont, ~body=text, ~pos=(x + width / 2, y + 15), env); - }, buttons); -}; - -let hitInner = (~enabled, pos, (x, y), width, (size, buttons)) => { - let buttonHeight = height(size); - let margin = margin(size); - - List.fold_left(((i, res), (_, action)) => { - let y = y + i * (buttonHeight + margin); - switch res { - | Some(x) => (i + 1, res) - | None => - let enabled = enabled(i, action); - if (enabled && MyUtils.rectCollide(pos, ((x,y), (width, buttonHeight)))) { - (i + 1, Some(action)) - } else { - (i + 1, None); - } - } - }, (0, None), buttons) |> snd; -}; - -let allEnabled = (_, _) => true; - -let draw = (~enabled=allEnabled, (cx, y), (size, buttons), ~ctx, ~env) => { - let margin = margin(size); - let buttonHeight = height(size); - let width = maxWidth(env, whichFont(ctx, size), buttons) + margin * 4; - - let x = cx - width / 2; - drawInner(~enabled, (x, y), width, (size, buttons), ~ctx, ~env); -}; - -let drawCentered = (~enabled=allEnabled, (cx, cy), (size, buttons), ~ctx, ~env) => { - let margin = margin(size); - let buttonHeight = height(size); - let width = maxWidth(env, whichFont(ctx, size), buttons) + margin * 4; - let height = List.length(buttons) * (margin + buttonHeight) - margin; - - let x = cx - width / 2; - let y = cy - height / 2; - drawInner(~enabled, (x, y), width, (size, buttons), ~ctx, ~env); -}; - -let hit = (~enabled=allEnabled, (cx, y), (size, buttons), ~ctx, ~env, pos) => { - let margin = margin(size); - let buttonHeight = height(size); - let width = maxWidth(env, whichFont(ctx, size), buttons) + margin * 4; - - let x = cx - width / 2; - hitInner(~enabled, pos, (x, y), width, (size, buttons)); -}; - -let hitCentered = (~enabled=allEnabled, (cx, cy), (size, buttons), ~ctx, ~env, pos) => { - let margin = margin(size); - let buttonHeight = height(size); - let width = maxWidth(env, whichFont(ctx, size), buttons) + margin * 4; - let height = List.length(buttons) * (margin + buttonHeight) - margin; - - let x = cx - width / 2; - let y = cy - height / 2; - hitInner(~enabled, pos, (x, y), width, (size, buttons)); -}; - - - -let singleBottom = (env, text, font, (x, y)) => { - /* let (x, y) = (Reprocessing.Env.width(env) / 2, Reprocessing.Env.height(env) - 10); */ - /* let width = Font. */ - let width = switch font^ { - | Some(font) => Reprocessing_Font.Font.calcStringWidth(env, font, text) - | None => 0 - }; - let height = 40; - let margin = 10; - let textPos = (x - width / 2, y - height + 10); - let pos = (x - width / 2 - margin, y - height); - (pos, textPos, width + margin * 2, height, text, font) -}; - -let singleTop = (env, text, font, (x, y)) => { - let width = switch font^ { - | Some(font) => Reprocessing_Font.Font.calcStringWidth(env, font, text) - | None => 0 - }; - let height = 40; - let margin = 10; - let textPos = (x - width / 2, y + 10); - let pos = (x - width / 2 - margin, y); - (pos, textPos, width + margin * 2, height, text, font) -}; - -let drawSingle = (env, (pos, textPos, width, height, text, font)) => { - open Reprocessing; - Draw.noStroke(env); - Draw.fill(color, env); - if (MyUtils.rectCollide(Env.mouse(env), (pos, (width, height)))) { - /* Draw.noFill(env); */ - Draw.strokeWeight(2, env); - Draw.stroke(Utils.color(~r=100, ~g=100, ~b=100, ~a=255), env); - }; - Draw.rect(~pos, ~width, ~height, env); - Draw.text(~pos=textPos, ~body=text, ~font, env); -}; - -let hitSingle = (env, ((x, y), _, width, height, _, _)) => { - let (a, b) = Reprocessing.Env.mouse(env); - if (a >= x && a <= x + width && b >= y && b <= y + height) { - true - } else { - false - } -}; - diff --git a/src/FreePlayPicker.re b/src/FreePlayPicker.re index 15f6b64..8d84d6b 100644 --- a/src/FreePlayPicker.re +++ b/src/FreePlayPicker.re @@ -1,16 +1,40 @@ open SharedTypes; -let buttons = (Button.Normal, [ - ("Easy", Easy), - ("Medium", Medium), - ("Hard", Hard), - ("Ludicrous", Ludicrous) -]); +let initialState = (); -let backButton = (ctx, env) => - Button.singleBottom(env, "Back", ctx.textFont, (Reprocessing.Env.width(env) / 2, Reprocessing.Env.height(env) - 10)); +let button = (ctx, name, diff, enabled) => UIManager.Button( + name, + diff, + {...WelcomeScreen2.buttonStyle(~enabled, ctx.textFont), margin: 18} +); -let initialState = (); +let root = (ctx, env) => { + let highest = UserData.highestBeatenStage(ctx.userData); + UIManager.{ + el: VBox( + [ + Text("Difficulty", {font: ctx.titleFont, tint: None}, Center), + Spacer(25), + button(ctx, "Easy", Easy, true), + button(ctx, "Medium", Medium, highest >= 0), + button(ctx, "Hard", Hard, highest >= 1), + button(ctx, "Ludicrous", Ludicrous, highest >= 2), + ], + 10, + Center + ), + align: Center, + valign: Top, + pos: (Reprocessing.Env.width(env) / 2, 20) +}; +}; + +let back = (ctx, env) => UIManager.{ + el: Button("Back", (), WelcomeScreen2.buttonStyle(ctx.textFont)), + align: Center, + valign: Bottom, + pos: (Reprocessing.Env.width(env) / 2, Reprocessing.Env.height(env) - 10) +}; let screen = ScreenManager.stateless( @@ -18,35 +42,20 @@ let screen = (ctx, env) => { open Reprocessing; Draw.background(Constants.black, env); - DrawUtils.centerText( - ~font=ctx.titleFont, - ~pos=(Env.width(env) / 2, 20), - ~body="Difficulty", - env - ); - Button.draw( - ~enabled=((i, _) => i <= 1+ UserData.highestBeatenStage(ctx.userData)), - (Env.width(env) / 2, 100), - buttons, - ~ctx, - ~env - ); - Button.drawSingle(env, backButton(ctx, env)); - + UIManager.draw(env, root(ctx, env)); + UIManager.draw(env, back(ctx, env)); Stateless(ctx) }, ~mouseDown= (ctx, env) => { - open Reprocessing; - let res = Button.hit( - ~enabled=((i, _) => i <= 1+ UserData.highestBeatenStage(ctx.userData)), - (Env.width(env) / 2, 100), buttons, ~ctx, ~env, Env.mouse(env)); - switch res { - | None => if (Button.hitSingle(env, backButton(ctx, env))) { - Transition(ctx, `Quit) - } else { Stateless(ctx) } - | Some(dest) => Transition(ctx, `FreeStyle(dest)) + switch (UIManager.act(env, root(ctx, env))) { + | Some(level) => Transition(ctx, `FreeStyle(level)) + | None => + switch (UIManager.act(env, back(ctx, env))) { + | Some(()) => Transition(ctx, `Quit) + | None => Same(ctx, ()) + } } }, ~keyPressed= diff --git a/src/HighScores.re b/src/HighScores.re index f60e3e3..5c5102a 100644 --- a/src/HighScores.re +++ b/src/HighScores.re @@ -30,10 +30,14 @@ let drawScores = (ctx, env, name, scores, y) => { }) + 20 }; -let backButton = (ctx, env) => { - Button.singleBottom(env, "Back", ctx.textFont, (Env.width(env) / 2, Env.height(env) - 10)) +let back = (ctx, env) => UIManager.{ + el: Button("Back", (), WelcomeScreen2.buttonStyle(ctx.textFont)), + align: Center, + valign: Bottom, + pos: (Reprocessing.Env.width(env) / 2, Reprocessing.Env.height(env) - 10) }; + let run = (ctx, (dy, vy, down), env) => { Draw.background(Constants.black, env); let w = Env.width(env) / 2; @@ -69,7 +73,7 @@ let run = (ctx, (dy, vy, down), env) => { env ); DrawUtils.centerText(~font=ctx.boldTextFont, ~body="High scores", ~pos=(w, h), env); - Button.drawSingle(env, backButton(ctx, env)); + UIManager.draw(env, back(ctx, env)); /* let vy = abs_float(vy) < 0.01 ? 0. : vy *. 0.90; */ (dy, vy, down) @@ -81,10 +85,9 @@ let screen = { Same(ctx, run(ctx, state, env)) }, mouseDown: (ctx, (dy, vy, down), env) => { - if (Button.hitSingle(env, backButton(ctx, env))) { - Transition(ctx, `Quit) - } else { - Same(ctx, (dy, 0., Some(Env.mouse(env) |> snd |> float_of_int))) + switch (UIManager.act(env, back(ctx, env))) { + | Some(()) => Transition(ctx, `Quit) + | None => Same(ctx, (dy, 0., Some(Env.mouse(env) |> snd |> float_of_int))) } }, mouseUp: (ctx, (dy, vy, down), env) => { diff --git a/src/LevelPicker.re b/src/LevelPicker.re index bf061ff..5dc69b0 100644 --- a/src/LevelPicker.re +++ b/src/LevelPicker.re @@ -2,78 +2,44 @@ open SharedTypes; let initialState = (); -type buttonStatus = - | Locked - | Available - | Beaten; +let button = (ctx, name, diff, enabled) => UIManager.Button( + name, + diff, + {...WelcomeScreen2.buttonStyle(~enabled, ctx.textFont), margin: 18} +); -type button = { - text: string, - pos: (int, int), - width: int, - height: int, - i: int, - status: buttonStatus, - enemies: list(Enemy.t), +let stageButtons = (ctx) => { + let maxOpen = 1 + UserData.highestBeatenStage(ctx.userData); + Array.mapi((i, _) => { + button(ctx, "Stage " ++ string_of_int(i + 1), + `StartFromStage(i), + i <= maxOpen + ) + }, ctx.stages) |> Array.to_list; }; -let center = ((x, y), w, h) => (x + w/2, y + h/2); - -let drawEnemySquare = (env, enemies, (x, y), w, h) => { - open Reprocessing; - let fullW = - Env.width(env); - let fullH = - Env.height(env); - let scaleX = MyUtils.flDiv(w, fullW); - let scaleY = MyUtils.flDiv(h, fullH); - Draw.pushMatrix(env); - Draw.translate(~x=float_of_int(x), ~y=float_of_int(y), env); - Draw.scale(~x=scaleX, ~y=scaleY, env); - List.iter(enemy => { - Draw.noFill(env); - Draw.stroke(enemy.Enemy.color, env); - Draw.strokeWeight(20, env); - GravShared.circle( - ~center=enemy.Enemy.pos, - ~rad=enemy.Enemy.size *. 2., - env - ); - }, enemies); - Draw.popMatrix(env); -}; - -let backButton = (ctx, env) => { - let (x, y) = (Reprocessing.Env.width(env) / 2, Reprocessing.Env.height(env) - 10); - let font = ctx.textFont; - let text = "Back"; - /* let width = Font. */ - let width = switch font^ { - | Some(font) => Reprocessing_Font.Font.calcStringWidth(env, font, text) - | None => 0 - }; - let height = 40; - let margin = 10; - let textPos = (x - width / 2, y - height + 10); - let pos = (x - width / 2 - margin, y - height); - (pos, textPos, width + margin * 2, height, text) +let root = (ctx, env) => { + let highest = UserData.highestBeatenStage(ctx.userData); + UIManager.{ + el: VBox( + [ + Text("Pick a stage", {font: ctx.titleFont, tint: None}, Center), + Spacer(25), + ] @ stageButtons(ctx), + 10, + Center + ), + align: Center, + valign: Top, + pos: (Reprocessing.Env.width(env) / 2, 20) }; - -let drawButton = (ctx, env, (pos, textPos, width, height, text)) => { - open Reprocessing; - Draw.noStroke(env); - Draw.fill(Button.color, env); - Draw.rect(~pos, ~width, ~height, env); - Draw.text(~pos=textPos, ~body=text, ~font=ctx.textFont, env); }; -let hitButton = (ctx, env, ((x, y), _, width, height, _)) => { - let (a, b) = Reprocessing.Env.mouse(env); - if (a >= x && a <= x + width && b >= y && b <= y + height) { - true - } else { - false - } +let back = (ctx, env) => UIManager.{ + el: Button("Back", (), WelcomeScreen2.buttonStyle(ctx.textFont)), + align: Center, + valign: Bottom, + pos: (Reprocessing.Env.width(env) / 2, Reprocessing.Env.height(env) - 10) }; let screen = @@ -82,40 +48,20 @@ let screen = (ctx, env) => { open Reprocessing; Draw.background(Constants.black, env); - DrawUtils.centerText( - ~font=ctx.titleFont, - ~pos=(Env.width(env) / 2, 20), - ~body="Pick a stage", - env - ); - let buttons = Array.mapi((i, _) => { - ("Stage " ++ string_of_int(i + 1), `StartFromStage(i)) - }, ctx.stages) |> Array.to_list; - Button.draw( - ~enabled=((i, _) => i <= 1+ UserData.highestBeatenStage(ctx.userData)), - (Env.width(env) / 2, 100), - (Normal, buttons), - ~ctx, - ~env - ); - drawButton(ctx, env, backButton(ctx, env)); - + UIManager.draw(env, root(ctx, env)); + UIManager.draw(env, back(ctx, env)); Stateless(ctx) }, + ~mouseDown= (ctx, env) => { - let buttons = Array.mapi((i, _) => { - ("Stage " ++ string_of_int(i + 1), i) - }, ctx.stages) |> Array.to_list; - open Reprocessing; - let res = Button.hit( - ~enabled=((i, _) => i <= 1+ UserData.highestBeatenStage(ctx.userData)), - (Env.width(env) / 2, 100), (Normal, buttons), ~ctx, ~env, Env.mouse(env)); - switch res { - | None => if (hitButton(ctx, env, backButton(ctx, env))) { - Transition(ctx, `Quit) - } else { Stateless(ctx) } - | Some(dest) => Transition(ctx, `StartFromStage(dest)) + switch (UIManager.act(env, root(ctx, env))) { + | Some(level) => Transition(ctx, level) + | None => + switch (UIManager.act(env, back(ctx, env))) { + | Some(()) => Transition(ctx, `Quit) + | None => Same(ctx, ()) + } } }, ~keyPressed= @@ -128,4 +74,4 @@ let screen = ), ~backPressed= (ctx, _) => Some(Transition(ctx, `Quit)), () - ); \ No newline at end of file + ); diff --git a/src/PauseOverlay.re b/src/PauseOverlay.re index 44564d2..d066a9a 100644 --- a/src/PauseOverlay.re +++ b/src/PauseOverlay.re @@ -1,16 +1,30 @@ +open SharedTypes; open Reprocessing; -let buttonPos = env => (Env.width(env) / 2, Env.height(env) / 2); -let buttons = Button.normalButtons([("Resume", `Resume), ("Home", `Quit)]); +let style = font => { + ...WelcomeScreen2.buttonStyle(font), + fixedWidth: Some(150), + margin: 20 +}; + +let root = (env, ctx) => UIManager.{ + el: VBox([ + Button("Resume", `Resume, style(ctx.textFont)), + Button("Home", `Quit, style(ctx.textFont)), + ], 10, Center), + pos: (Env.width(env) / 2, Env.height(env) / 2), + align: Center, + valign: Middle +}; let draw = (ctx, env) => { Draw.fill(Utils.color(~r=50, ~g=50 ,~b=80, ~a=150), env); Draw.rect(~pos=(0, 0), ~width=Env.width(env), ~height=Env.height(env), env); - Button.drawCentered(buttonPos(env), buttons, ~ctx, ~env); + UIManager.draw(env, root(env, ctx)); }; let mouseDown = (ctx, env) => { - Button.hitCentered(buttonPos(env), buttons, ~ctx, ~env, Env.mouse(env)) + UIManager.act(env, root(env, ctx)) }; diff --git a/src/UIManager.re b/src/UIManager.re index 28cc049..f4814d1 100644 --- a/src/UIManager.re +++ b/src/UIManager.re @@ -30,7 +30,6 @@ type buttonStyle = { type element('action) = | Text(string, textStyle, align) | Button(string, 'action, buttonStyle) - /* | ButtonSet(list((string, 'action)), buttonStyle, int) */ | Spacer(int) | VBox(list(element('action)), int, align) | Custom(glEnvT => (int, int), (glEnvT, (int, int)) => unit, (glEnvT, (int, int)) => option('action)) @@ -62,13 +61,6 @@ let rec measure = (env, element) => switch element { }; (w, h + style.margin * 2) } -/* | ButtonSet(items, font, style, spacing) => { - let (w, h, num) = List.fold_left(((w, h, num), (t, _)) => { - let (ww, hh) = measureText(env, font, t); - (max(w, ww), h + hh + style.margin * 2 + spacing, num + 1) - }, (0, 0, 0), items); - (w + style.margin * 2, max(0, h - spacing)) -} */ | Custom(measure, draw, act) => measure(env) | Spacer(height) => (0, height) | VBox(items, spacer, _align) => { diff --git a/src/WelcomeScreen2.re b/src/WelcomeScreen2.re index 38a4be3..07e87ac 100644 --- a/src/WelcomeScreen2.re +++ b/src/WelcomeScreen2.re @@ -1,14 +1,16 @@ open SharedTypes; open Reprocessing; -let buttonStyle = font => UIManager.{ +let buttonStyle = (~enabled=true, font) => UIManager.{ textStyle: {font, tint: None}, - bgColor: MyUtils.withAlpha(Constants.white, 0.2), + bgColor: enabled + ? Utils.color(~r=50, ~g=50, ~b=50, ~a=255) + : Utils.color(~r=20, ~g=20, ~b=20, ~a=200), hoverBorderColor: Utils.color(~r=100, ~g=100, ~b=100, ~a=255), - borderColor: Constants.black, + borderColor: MyUtils.withAlpha(Constants.black, 0.), innerBorder: None, fixedWidth: Some(170), - enabled: true, + enabled, margin: 15 }; @@ -54,8 +56,7 @@ let wallButton = (ctx, env, name, typ) => SharedTypes.isWallTypeEnabled(ctx, typ "LOCKED", `Wall(typ), { - ...buttonStyle(ctx.boldTextFont), - bgColor: Utils.color(~r=20, ~g=20, ~b=20, ~a=200), + ...buttonStyle(~enabled=false, ctx.boldTextFont), textStyle: {font: ctx.boldTextFont, tint: Some(Utils.color(~r=100, ~g=100, ~b=100, ~a=255))}, hoverBorderColor: Constants.white, borderColor: wallColor(typ),