1 #include "lib/widget/button.h"
2 #include "lib/widget/label.h"
3 #include "lib/widget/bar.h"
4 #include "lib/sound/audio_id.h"
5 #include "lib/sound/audio.h"
6 #include "manufacture.h"
7 #include "../mission.h"
8 #include "../qtscript.h"
9
10 STRUCTURE *ManufactureController::highlightedFactory = nullptr;
11
getFactoryOrNullptr(STRUCTURE * factory)12 FACTORY *getFactoryOrNullptr(STRUCTURE *factory)
13 {
14 ASSERT_OR_RETURN(nullptr, StructIsFactory(factory), "Invalid factory pointer");
15 return (FACTORY *)factory->pFunctionality;
16 }
17
getProductionLoops(STRUCTURE * structure)18 static uint8_t getProductionLoops(STRUCTURE *structure)
19 {
20 if (structure == nullptr)
21 {
22 return 0;
23 }
24
25 auto psFactory = getFactoryOrNullptr(structure);
26 ASSERT_NOT_NULLPTR_OR_RETURN(0, psFactory);
27 return psFactory->productionLoops;
28 }
29
makeProductionRunSizeLabel()30 static std::shared_ptr<W_LABEL> makeProductionRunSizeLabel()
31 {
32 auto init = W_LABINIT();
33 init.x = OBJ_TEXTX;
34 init.y = OBJ_T1TEXTY;
35 init.width = 16;
36 init.height = 16;
37 return std::make_shared<W_LABEL>(&init);
38 }
39
updateData()40 void ManufactureController::updateData()
41 {
42 updateFactoriesList();
43 updateHighlighted();
44 updateManufactureOptionsList();
45 }
46
adjustFactoryProduction(DROID_TEMPLATE * manufactureOption,bool add)47 void ManufactureController::adjustFactoryProduction(DROID_TEMPLATE *manufactureOption, bool add)
48 {
49 factoryProdAdjust(getHighlightedObject(), manufactureOption, add);
50 }
51
adjustFactoryLoop(bool add)52 void ManufactureController::adjustFactoryLoop(bool add)
53 {
54 factoryLoopAdjust(getHighlightedObject(), add);
55 }
56
releaseFactoryProduction(STRUCTURE * structure)57 void ManufactureController::releaseFactoryProduction(STRUCTURE *structure)
58 {
59 releaseProduction(structure, ModeQueue);
60 }
61
cancelFactoryProduction(STRUCTURE * structure)62 void ManufactureController::cancelFactoryProduction(STRUCTURE *structure)
63 {
64 if (!StructureIsManufacturingPending(structure))
65 {
66 return;
67 }
68
69 if (!StructureIsOnHoldPending(structure))
70 {
71 holdProduction(structure, ModeQueue);
72 return;
73 }
74
75 cancelProduction(structure, ModeQueue);
76 audio_PlayTrack(ID_SOUND_WINDOWCLOSE);
77 }
78
startDeliveryPointPosition()79 void ManufactureController::startDeliveryPointPosition()
80 {
81 auto factory = getHighlightedObject();
82 ASSERT_NOT_NULLPTR_OR_RETURN(, factory);
83
84 // make sure that the factory isn't assigned to a commander
85 assignFactoryCommandDroid(factory, nullptr);
86 auto psFlag = FindFactoryDelivery(factory);
87 if (psFlag)
88 {
89 startDeliveryPosition(psFlag);
90 }
91 }
92
compareFactories(STRUCTURE * a,STRUCTURE * b)93 static inline bool compareFactories(STRUCTURE *a, STRUCTURE *b)
94 {
95 if (a == nullptr || b == nullptr)
96 {
97 return (a == nullptr) < (b == nullptr);
98 }
99 auto x = getFactoryOrNullptr(a);
100 ASSERT_NOT_NULLPTR_OR_RETURN(false, x);
101 auto y = getFactoryOrNullptr(b);
102 ASSERT_NOT_NULLPTR_OR_RETURN(false, y);
103 ASSERT_NOT_NULLPTR_OR_RETURN(false, x->psAssemblyPoint);
104 ASSERT_NOT_NULLPTR_OR_RETURN(false, y->psAssemblyPoint);
105 if (x->psAssemblyPoint->factoryType != y->psAssemblyPoint->factoryType)
106 {
107 return x->psAssemblyPoint->factoryType < y->psAssemblyPoint->factoryType;
108 }
109
110 return x->psAssemblyPoint->factoryInc < y->psAssemblyPoint->factoryInc;
111 }
112
updateFactoriesList()113 void ManufactureController::updateFactoriesList()
114 {
115 factories.clear();
116
117 for (auto structure = interfaceStructList(); structure != nullptr; structure = structure->psNext)
118 {
119 if (structure->status == SS_BUILT && structure->died == 0 && StructIsFactory(structure))
120 {
121 factories.push_back(structure);
122 }
123 }
124
125 std::sort(factories.begin(), factories.end(), compareFactories);
126 }
127
updateManufactureOptionsList()128 void ManufactureController::updateManufactureOptionsList()
129 {
130 if (auto factory = getHighlightedObject())
131 {
132 stats = fillTemplateList(factory);
133 }
134 else
135 {
136 stats.clear();
137 }
138 }
139
getObjectStatsAt(size_t objectIndex) const140 DROID_TEMPLATE *ManufactureController::getObjectStatsAt(size_t objectIndex) const
141 {
142 auto factory = getFactoryOrNullptr(getObjectAt(objectIndex));
143 return factory == nullptr ? nullptr : factory->psSubject;
144 }
145
refresh()146 void ManufactureController::refresh()
147 {
148 updateData();
149
150 if (objectsSize() == 0)
151 {
152 closeInterface();
153 }
154 }
155
setHighlightedObject(BASE_OBJECT * object)156 void ManufactureController::setHighlightedObject(BASE_OBJECT *object)
157 {
158 if (object == nullptr)
159 {
160 highlightedFactory = nullptr;
161 return;
162 }
163
164 auto factory = castStructure(object);
165 ASSERT_OR_RETURN(, StructIsFactory(factory), "Invalid factory pointer");
166 highlightedFactory = factory;
167 }
168
169 class ManufactureObjectButton : public ObjectButton
170 {
171 private:
172 typedef ObjectButton BaseWidget;
173
174 protected:
ManufactureObjectButton()175 ManufactureObjectButton() {}
176
177 public:
make(const std::shared_ptr<ManufactureController> & controller,size_t objectIndex)178 static std::shared_ptr<ManufactureObjectButton> make(const std::shared_ptr<ManufactureController> &controller, size_t objectIndex)
179 {
180 class make_shared_enabler: public ManufactureObjectButton {};
181 auto widget = std::make_shared<make_shared_enabler>();
182 widget->controller = controller;
183 widget->objectIndex = objectIndex;
184 widget->initialize();
185 return widget;
186 }
187
jump()188 void jump() override
189 {
190 if (!offWorldKeepLists)
191 {
192 BaseWidget::jump();
193 }
194 }
195
clickPrimary()196 void clickPrimary() override
197 {
198 controller->clearStructureSelection();
199 controller->selectObject(controller->getObjectAt(objectIndex));
200 jump();
201 BaseStatsController::scheduleDisplayStatsForm(controller);
202 }
203
204 protected:
initialize()205 void initialize()
206 {
207 attach(factoryNumberLabel = std::make_shared<W_LABEL>());
208 factoryNumberLabel->setGeometry(OBJ_TEXTX, OBJ_B1TEXTY, 16, 16);
209 }
210
display(int xOffset,int yOffset)211 void display(int xOffset, int yOffset) override
212 {
213 updateLayout();
214 auto factory = controller->getObjectAt(objectIndex);
215 ASSERT_NOT_NULLPTR_OR_RETURN(, factory);
216 ASSERT_OR_RETURN(, !isDead(factory), "Factory is dead");
217 displayIMD(Image(), ImdObject::Structure(factory), xOffset, yOffset);
218 displayIfHighlight(xOffset, yOffset);
219 }
220
updateLayout()221 void updateLayout() override
222 {
223 BaseWidget::updateLayout();
224 auto factory = getFactoryOrNullptr(controller->getObjectAt(objectIndex));
225 ASSERT_NOT_NULLPTR_OR_RETURN(, factory);
226 if (factory->psAssemblyPoint == nullptr)
227 {
228 factoryNumberLabel->setString("");
229 return;
230 }
231 factoryNumberLabel->setString(WzString::fromUtf8(astringf("%u", factory->psAssemblyPoint->factoryInc + 1)));
232 }
233
getTip()234 std::string getTip() override
235 {
236 auto factory = controller->getObjectAt(objectIndex);
237 ASSERT_NOT_NULLPTR_OR_RETURN("", factory);
238 return getStatsName(factory->pStructureType);
239 }
240
getController() const241 ManufactureController &getController() const override
242 {
243 return *controller.get();
244 }
245
246 private:
247 std::shared_ptr<ManufactureController> controller;
248 std::shared_ptr<W_LABEL> factoryNumberLabel;
249 };
250
251 class ManufactureStatsButton: public StatsButton
252 {
253 private:
254 typedef StatsButton BaseWidget;
255
256 protected:
ManufactureStatsButton()257 ManufactureStatsButton() {}
258
259 public:
make(const std::shared_ptr<ManufactureController> & controller,size_t objectIndex)260 static std::shared_ptr<ManufactureStatsButton> make(const std::shared_ptr<ManufactureController> &controller, size_t objectIndex)
261 {
262 class make_shared_enabler: public ManufactureStatsButton {};
263 auto widget = std::make_shared<make_shared_enabler>();
264 widget->controller = controller;
265 widget->objectIndex = objectIndex;
266 widget->initialize();
267 return widget;
268 }
269
270 protected:
display(int xOffset,int yOffset)271 void display(int xOffset, int yOffset) override
272 {
273 updateLayout();
274
275 auto factory = controller->getObjectAt(objectIndex);
276 auto production = getStats();
277 auto productionPending = factory && StructureIsManufacturingPending(factory);
278 auto objectImage = productionPending && production ? ImdObject::DroidTemplate(production): ImdObject::Component(nullptr);
279
280 displayIMD(Image(), objectImage, xOffset, yOffset);
281
282 if (productionPending && StructureIsOnHoldPending(factory))
283 {
284 iV_DrawImage(IntImages, ((realTime / 250) % 2) == 0 ? IMAGE_BUT0_DOWN : IMAGE_BUT_HILITE, xOffset + x(), yOffset + y());
285 }
286 else
287 {
288 displayIfHighlight(xOffset, yOffset);
289 }
290 }
291
updateLayout()292 void updateLayout() override
293 {
294 BaseWidget::updateLayout();
295 auto factory = controller->getObjectAt(objectIndex);
296 updateProgressBar(factory);
297 updateProductionRunSizeLabel(factory, FactoryGetTemplate(StructureGetFactory(factory)));
298 }
299
300 private:
getStats()301 DROID_TEMPLATE *getStats() override
302 {
303 return controller->getObjectStatsAt(objectIndex);
304 }
305
initialize()306 void initialize()
307 {
308 addProgressBar();
309 addProductionRunSizeLabel();
310 }
311
addProductionRunSizeLabel()312 void addProductionRunSizeLabel()
313 {
314 attach(productionRunSizeLabel = makeProductionRunSizeLabel());
315 productionRunSizeLabel->setFontColour(WZCOL_ACTION_PRODUCTION_RUN_TEXT);
316 }
317
updateProductionRunSizeLabel(STRUCTURE * factory,DROID_TEMPLATE * droidTemplate)318 void updateProductionRunSizeLabel(STRUCTURE *factory, DROID_TEMPLATE *droidTemplate)
319 {
320 auto productionRemaining = getProduction(factory, droidTemplate).numRemaining();
321 if (productionRemaining > 0 && factory && StructureIsManufacturingPending(factory))
322 {
323 productionRunSizeLabel->setString(WzString::fromUtf8(astringf("%d", productionRemaining)));
324 productionRunSizeLabel->show();
325 }
326 else
327 {
328 productionRunSizeLabel->hide();
329 }
330 }
331
updateProgressBar(STRUCTURE * factory)332 void updateProgressBar(STRUCTURE *factory)
333 {
334 progressBar->hide();
335
336 ASSERT_NOT_NULLPTR_OR_RETURN(, factory);
337 ASSERT_OR_RETURN(, !isDead(factory), "Factory is dead");
338
339 if (!StructureIsManufacturingPending(factory))
340 {
341 return;
342 }
343
344 auto manufacture = StructureGetFactory(factory);
345 ASSERT_NOT_NULLPTR_OR_RETURN(, manufacture);
346
347 if (manufacture->psSubject != nullptr && manufacture->buildPointsRemaining < calcTemplateBuild(manufacture->psSubject))
348 {
349 // Started production. Set the colour of the bar to yellow.
350 int buildPointsTotal = calcTemplateBuild(FactoryGetTemplate(manufacture));
351 int buildRate = manufacture->timeStartHold == 0 ? getBuildingProductionPoints(factory) : 0;
352 formatTime(progressBar.get(), buildPointsTotal - manufacture->buildPointsRemaining, buildPointsTotal, buildRate, _("Construction Progress"));
353 }
354 else
355 {
356 // Not yet started production.
357 int neededPower = checkPowerRequest(factory);
358 int powerToBuild = manufacture->psSubject ? calcTemplatePower(manufacture->psSubject) : 0;
359 formatPower(progressBar.get(), neededPower, powerToBuild);
360 }
361 }
362
isHighlighted() const363 bool isHighlighted() const override
364 {
365 auto factory = controller->getObjectAt(objectIndex);
366 return factory && (factory->selected || factory == controller->getHighlightedObject());
367 }
368
clickPrimary()369 void clickPrimary() override
370 {
371 auto factory = controller->getObjectAt(objectIndex);
372 ASSERT_NOT_NULLPTR_OR_RETURN(, factory);
373 controller->releaseFactoryProduction(factory);
374 controller->clearStructureSelection();
375 controller->selectObject(factory);
376 BaseStatsController::scheduleDisplayStatsForm(controller);
377 }
378
clickSecondary()379 void clickSecondary() override
380 {
381 auto factory = controller->getObjectAt(objectIndex);
382 ASSERT_NOT_NULLPTR_OR_RETURN(, factory);
383 controller->clearStructureSelection();
384 controller->cancelFactoryProduction(factory);
385 controller->setHighlightedObject(factory);
386 controller->refresh();
387 BaseStatsController::scheduleDisplayStatsForm(controller);
388 }
389
390 std::shared_ptr<ManufactureController> controller;
391 std::shared_ptr<W_LABEL> productionRunSizeLabel;
392 size_t objectIndex;
393 };
394
395 class ManufactureOptionButton: public StatsFormButton
396 {
397 private:
398 typedef StatsFormButton BaseWidget;
399 using BaseWidget::BaseWidget;
400
401 public:
make(const std::shared_ptr<ManufactureController> & controller,size_t manufactureOptionIndex)402 static std::shared_ptr<ManufactureOptionButton> make(const std::shared_ptr<ManufactureController> &controller, size_t manufactureOptionIndex)
403 {
404 class make_shared_enabler: public ManufactureOptionButton {};
405 auto widget = std::make_shared<make_shared_enabler>();
406 widget->controller = controller;
407 widget->manufactureOptionIndex = manufactureOptionIndex;
408 widget->initialize();
409 return widget;
410 }
411
412 protected:
display(int xOffset,int yOffset)413 void display(int xOffset, int yOffset) override
414 {
415 updateLayout();
416 auto stat = getStats();
417 ASSERT_NOT_NULLPTR_OR_RETURN(, stat);
418
419 displayIMD(Image(), ImdObject::DroidTemplate(stat), xOffset, yOffset);
420 displayIfHighlight(xOffset, yOffset);
421 }
422
423 private:
getStats()424 DROID_TEMPLATE *getStats() override
425 {
426 return controller->getStatsAt(manufactureOptionIndex);
427 }
428
initialize()429 void initialize()
430 {
431 addCostBar();
432 addProductionRunSizeLabel();
433 }
434
addProductionRunSizeLabel()435 void addProductionRunSizeLabel()
436 {
437 attach(productionRunSizeLabel = makeProductionRunSizeLabel());
438 }
439
updateProductionRunSizeLabel(STRUCTURE * structure,DROID_TEMPLATE * droidTemplate)440 void updateProductionRunSizeLabel(STRUCTURE *structure, DROID_TEMPLATE *droidTemplate)
441 {
442 auto production = getProduction(structure, droidTemplate);
443 if (production.isValid())
444 {
445 auto productionLoops = getProductionLoops(structure);
446 auto labelText = astringf(productionLoops > 0 ? "%d/%d" : "%d", production.numRemaining(), production.quantity);
447 productionRunSizeLabel->setString(WzString::fromUtf8(labelText));
448 productionRunSizeLabel->show();
449 }
450 else
451 {
452 productionRunSizeLabel->hide();
453 }
454 }
455
isHighlighted() const456 bool isHighlighted() const override
457 {
458 return controller->isHighlightedObjectStats(manufactureOptionIndex);
459 }
460
updateLayout()461 void updateLayout() override
462 {
463 BaseWidget::updateLayout();
464 if (isMouseOverWidget())
465 {
466 intSetShadowPower(getCost());
467 }
468 costBar->majorSize = std::min(100, (int32_t)(getCost() / POWERPOINTS_DROIDDIV));
469 updateProductionRunSizeLabel(controller->getHighlightedObject(), getStats());
470 }
471
getCost()472 uint32_t getCost() override
473 {
474 DROID_TEMPLATE* psTemplate = getStats();
475 return psTemplate ? calcTemplatePower(psTemplate) : 0;
476 }
477
clickPrimary()478 void clickPrimary() override
479 {
480 adjustFactoryProduction(true);
481 }
482
clickSecondary()483 void clickSecondary() override
484 {
485 adjustFactoryProduction(false);
486 }
487
adjustFactoryProduction(bool add)488 void adjustFactoryProduction(bool add)
489 {
490 auto clickedStats = controller->getStatsAt(manufactureOptionIndex);
491 ASSERT_NOT_NULLPTR_OR_RETURN(, clickedStats);
492
493 auto controllerRef = controller;
494 widgScheduleTask([add, clickedStats, controllerRef]() {
495 controllerRef->adjustFactoryProduction(clickedStats, add);
496 });
497 }
498
499 std::shared_ptr<ManufactureController> controller;
500 std::shared_ptr<W_LABEL> productionRunSizeLabel;
501 size_t manufactureOptionIndex;
502 };
503
504 class ManufactureObjectsForm: public ObjectsForm
505 {
506 private:
507 typedef ObjectsForm BaseWidget;
508 using BaseWidget::BaseWidget;
509
510 public:
make(const std::shared_ptr<ManufactureController> & controller)511 static std::shared_ptr<ManufactureObjectsForm> make(const std::shared_ptr<ManufactureController> &controller)
512 {
513 class make_shared_enabler: public ManufactureObjectsForm {};
514 auto widget = std::make_shared<make_shared_enabler>();
515 widget->controller = controller;
516 widget->initialize();
517 return widget;
518 }
519
makeStatsButton(size_t buttonIndex) const520 std::shared_ptr<StatsButton> makeStatsButton(size_t buttonIndex) const override
521 {
522 return ManufactureStatsButton::make(controller, buttonIndex);
523 }
524
makeObjectButton(size_t buttonIndex) const525 std::shared_ptr<ObjectButton> makeObjectButton(size_t buttonIndex) const override
526 {
527 return ManufactureObjectButton::make(controller, buttonIndex);
528 }
529
530 protected:
getController() const531 ManufactureController &getController() const override
532 {
533 return *controller.get();
534 }
535
536 private:
537 std::shared_ptr<ManufactureController> controller;
538 };
539
540 class ManufactureStatsForm: public ObjectStatsForm
541 {
542 private:
543 typedef ObjectStatsForm BaseWidget;
544 using BaseWidget::BaseWidget;
545
546 public:
make(const std::shared_ptr<ManufactureController> & controller)547 static std::shared_ptr<ManufactureStatsForm> make(const std::shared_ptr<ManufactureController> &controller)
548 {
549 class make_shared_enabler: public ManufactureStatsForm {};
550 auto widget = std::make_shared<make_shared_enabler>();
551 widget->controller = controller;
552 widget->initialize();
553 return widget;
554 }
555
makeOptionButton(size_t buttonIndex) const556 std::shared_ptr<StatsFormButton> makeOptionButton(size_t buttonIndex) const override
557 {
558 return ManufactureOptionButton::make(controller, buttonIndex);
559 }
560
561 protected:
getController() const562 ManufactureController &getController() const override
563 {
564 return *controller.get();
565 }
566
567 private:
initialize()568 void initialize() override
569 {
570 BaseWidget::initialize();
571 addObsoleteButton();
572 attach(std::make_shared<DeliveryPointButton>(controller));
573 addLoopProductionWidgets();
574 }
575
addObsoleteButton()576 void addObsoleteButton()
577 {
578 auto obsoleteButton = std::make_shared<MultipleChoiceButton>();
579 attach(obsoleteButton);
580 obsoleteButton->style |= WBUT_SECONDARY;
581 obsoleteButton->setChoice(controller->shouldShowRedundantDesign());
582 obsoleteButton->setImages(false, MultipleChoiceButton::Images(Image(IntImages, IMAGE_OBSOLETE_HIDE_UP), Image(IntImages, IMAGE_OBSOLETE_HIDE_UP), Image(IntImages, IMAGE_OBSOLETE_HIDE_HI)));
583 obsoleteButton->setTip(false, _("Hiding Obsolete Tech"));
584 obsoleteButton->setImages(true, MultipleChoiceButton::Images(Image(IntImages, IMAGE_OBSOLETE_SHOW_UP), Image(IntImages, IMAGE_OBSOLETE_SHOW_UP), Image(IntImages, IMAGE_OBSOLETE_SHOW_HI)));
585 obsoleteButton->setTip(true, _("Showing Obsolete Tech"));
586 obsoleteButton->move(4 + Image(IntImages, IMAGE_FDP_UP).width() + 4, STAT_SLDY);
587
588 auto weakController = std::weak_ptr<ManufactureController>(controller);
589 obsoleteButton->addOnClickHandler([weakController](W_BUTTON &button) {
590 if (auto manufactureController = weakController.lock())
591 {
592 auto &obsoleteButton = static_cast<MultipleChoiceButton &>(button);
593 auto newValue = !obsoleteButton.getChoice();
594 manufactureController->setShouldShowRedundantDesign(newValue);
595 obsoleteButton.setChoice(newValue);
596 }
597 });
598 }
599
addLoopProductionWidgets()600 void addLoopProductionWidgets()
601 {
602 auto loopProductionButton = std::make_shared<LoopProductionButton>(controller);
603 attach(loopProductionButton);
604 loopProductionButton->move(STAT_SLDX + STAT_SLDWIDTH + 2, STAT_SLDY);
605
606 auto loopProductionLabel = std::make_shared<LoopProductionLabel>(controller);
607 attach(loopProductionLabel);
608 loopProductionLabel->setGeometry(loopProductionButton->x() - 15, loopProductionButton->y(), 12, 15);
609 }
610
611 std::shared_ptr<ManufactureController> controller;
612
613 class DeliveryPointButton: public W_BUTTON
614 {
615 private:
616 typedef W_BUTTON BaseWidget;
617
618 public:
DeliveryPointButton(const std::shared_ptr<ManufactureController> & controller)619 DeliveryPointButton(const std::shared_ptr<ManufactureController> &controller): BaseWidget(), controller(controller)
620 {
621 style |= WBUT_SECONDARY;
622 move(4, STAT_SLDY);
623 setTip(_("Factory Delivery Point"));
624
625 auto weakController = std::weak_ptr<ManufactureController>(controller);
626 addOnClickHandler([weakController](W_BUTTON &) {
627 auto controller = weakController.lock();
628 ASSERT_NOT_NULLPTR_OR_RETURN(, controller);
629 controller->startDeliveryPointPosition();
630 });
631 }
632
633 protected:
display(int xOffset,int yOffset)634 void display(int xOffset, int yOffset)
635 {
636 updateLayout();
637 BaseWidget::display(xOffset, yOffset);
638 }
639
640 private:
updateLayout()641 void updateLayout()
642 {
643 auto factory = controller->getHighlightedObject();
644 ASSERT_NOT_NULLPTR_OR_RETURN(, factory);
645
646 switch (factory->pStructureType->type)
647 {
648 default:
649 case REF_FACTORY:
650 setImages(Image(IntImages, IMAGE_FDP_UP), Image(IntImages, IMAGE_FDP_DOWN), Image(IntImages, IMAGE_FDP_HI));
651 break;
652 case REF_CYBORG_FACTORY:
653 setImages(Image(IntImages, IMAGE_CDP_UP), Image(IntImages, IMAGE_CDP_DOWN), Image(IntImages, IMAGE_CDP_HI));
654 break;
655 case REF_VTOL_FACTORY:
656 setImages(Image(IntImages, IMAGE_VDP_UP), Image(IntImages, IMAGE_VDP_DOWN), Image(IntImages, IMAGE_VDP_HI));
657 break;
658 }
659 }
660
661 std::shared_ptr<ManufactureController> controller;
662 };
663
664 class LoopProductionButton: public W_BUTTON
665 {
666 private:
667 typedef W_BUTTON BaseWidget;
668
669 public:
LoopProductionButton(const std::shared_ptr<ManufactureController> & controller)670 LoopProductionButton(const std::shared_ptr<ManufactureController> &controller): BaseWidget(), controller(controller)
671 {
672 style |= WBUT_SECONDARY;
673 setImages(Image(IntImages, IMAGE_LOOP_UP), Image(IntImages, IMAGE_LOOP_DOWN), Image(IntImages, IMAGE_LOOP_HI));
674 setTip(_("Loop Production"));
675 }
676
released(W_CONTEXT * psContext,WIDGET_KEY key)677 void released(W_CONTEXT *psContext, WIDGET_KEY key) override
678 {
679 BaseWidget::released(psContext, key);
680 controller->adjustFactoryLoop(key == WKEY_PRIMARY);
681 }
682
683 protected:
display(int xOffset,int yOffset)684 void display(int xOffset, int yOffset) override
685 {
686 updateLayout();
687 BaseWidget::display(xOffset, yOffset);
688 }
689
updateLayout()690 void updateLayout()
691 {
692 setState(getProductionLoops(controller->getHighlightedObject()) == 0 ? 0: WBUT_CLICKLOCK);
693 }
694
695 private:
696 std::shared_ptr<ManufactureController> controller;
697 };
698
699 class LoopProductionLabel: public W_LABEL
700 {
701 private:
702 typedef W_LABEL BaseWidget;
703
704 public:
LoopProductionLabel(const std::shared_ptr<ManufactureController> & controller)705 LoopProductionLabel(const std::shared_ptr<ManufactureController> &controller): BaseWidget(), controller(controller)
706 {
707 }
708
709 protected:
display(int xOffset,int yOffset)710 void display(int xOffset, int yOffset) override
711 {
712 updateLayout();
713 BaseWidget::display(xOffset, yOffset);
714 }
715
updateLayout()716 void updateLayout()
717 {
718 auto productionLoops = getProductionLoops(controller->getHighlightedObject());
719 if (productionLoops != lastProductionLoop)
720 {
721 lastProductionLoop = productionLoops;
722 setString(WzString::fromUtf8(getNewString()));
723 }
724 }
725
726 private:
getNewString()727 std::string getNewString()
728 {
729 switch (lastProductionLoop)
730 {
731 case 0:
732 return "";
733 case INFINITE_PRODUCTION:
734 return "∞";
735 default:
736 return astringf("%u", lastProductionLoop + 1);
737 }
738 }
739
740 uint8_t lastProductionLoop = 0;
741 std::shared_ptr<ManufactureController> controller;
742 };
743 };
744
showInterface()745 bool ManufactureController::showInterface()
746 {
747 updateData();
748 if (factories.empty())
749 {
750 return false;
751 }
752
753 auto objectsForm = ManufactureObjectsForm::make(shared_from_this());
754 psWScreen->psForm->attach(objectsForm);
755 displayStatsForm();
756 triggerEvent(TRIGGER_MENU_MANUFACTURE_UP);
757 return true;
758 }
759
makeStatsForm()760 std::shared_ptr<StatsForm> ManufactureController::makeStatsForm()
761 {
762 return ManufactureStatsForm::make(shared_from_this());
763 }
764